Skip to content

Commit ca86f61

Browse files
committed
Add CI on PR
1 parent 224f3aa commit ca86f61

14 files changed

Lines changed: 95 additions & 63 deletions

File tree

.clang-tidy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Checks: 'clang-analyzer-*,-clang-analyzer-security.insecureAPI.*,-clang-analyzer-deadcode.DeadStores,-clang-analyzer-optin.performance.Padding,-clang-analyzer-cplusplus.NewDelete,bugprone-narrowing-conversions,bugprone-suspicious-string-compare,bugprone-switch-missing-default-case,bugprone-branch-clone'
2-
HeaderFilterRegex: '^.*/src/.*'
2+
HeaderFilterRegex: '^.*/src/(mux|btech)/.*'
33
CheckOptions:
44
- key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
55
value: false

.devcontainer/Dockerfile

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,35 @@
1-
FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04
1+
FROM mcr.microsoft.com/devcontainers/base:ubuntu24.04
2+
3+
ARG CMAKE_VERSION=4.4.0
4+
ARG JUST_VERSION=1.50.0
25

36
# [Optional] Uncomment this section to install additional vcpkg ports.
47
# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install <your-port-name-here>"
58

69
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
7-
&& apt-get -y install --no-install-recommends build-essential automake libevent-dev libdbi-dev libcrypt-dev libtool
10+
&& apt-get -y install --no-install-recommends \
11+
build-essential ca-certificates clang-20 clang-format-20 clang-tidy-20 clang-tools-20 \
12+
clangd-20 curl libsqlite3-dev sqlite3
13+
14+
RUN case "$(uname -m)" in \
15+
x86_64) CMAKE_ARCH=x86_64 ;; \
16+
aarch64|arm64) CMAKE_ARCH=aarch64 ;; \
17+
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; \
18+
esac \
19+
&& CMAKE_ARCHIVE="cmake-${CMAKE_VERSION}-linux-${CMAKE_ARCH}.tar.gz" \
20+
&& curl --proto '=https' --tlsv1.2 --fail --silent --show-error \
21+
"https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_ARCHIVE}" \
22+
--output "/tmp/${CMAKE_ARCHIVE}" \
23+
&& curl --proto '=https' --tlsv1.2 --fail --silent --show-error \
24+
"https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-SHA-256.txt" \
25+
--output /tmp/cmake-SHA-256.txt \
26+
&& grep " ${CMAKE_ARCHIVE}$" /tmp/cmake-SHA-256.txt > /tmp/cmake-archive.sha256 \
27+
&& cd /tmp \
28+
&& sha256sum --check cmake-archive.sha256 \
29+
&& tar --extract --gzip --file "${CMAKE_ARCHIVE}" --strip-components=1 --directory /usr/local \
30+
&& rm "${CMAKE_ARCHIVE}" cmake-SHA-256.txt cmake-archive.sha256
31+
32+
RUN curl --proto '=https' --tlsv1.2 --fail --silent --show-error \
33+
https://just.systems/install.sh --output /tmp/just-install.sh \
34+
&& bash /tmp/just-install.sh --to /usr/local/bin --tag "${JUST_VERSION}" \
35+
&& rm /tmp/just-install.sh

.github/workflows/ci.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Build and test
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ci-${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
build:
18+
runs-on: ubuntu-24.04
19+
timeout-minutes: 30
20+
21+
steps:
22+
- name: Check out repository
23+
uses: actions/checkout@v6
24+
with:
25+
submodules: recursive
26+
persist-credentials: false
27+
28+
- name: Build and test in devcontainer
29+
uses: devcontainers/ci@v0.3
30+
with:
31+
configFile: .devcontainer/devcontainer.json
32+
push: never
33+
runCmd: |
34+
just ci
35+
git diff --exit-code

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ When writing C code, use the following naming conventions:
3434
## Development workflows
3535

3636
* We use the `just` command runner
37-
* When making changes, run `just lint-changes`, `just build`, `just test`, and then `just install` to validate end to end.
37+
* When making changes, run `just agent-checks` to validate end to end.
3838
* Make sure that updates to behaviors are reflected in `game/help/`, and `docs/`.
3939
* Check the various `game/*.conf` and `game/*.config` files when making changes to mudconfs, configs, and settings.
4040
* If making DB schema changes, offer to update the game's database at `game/data/stompymux.db.sqlite`. If a `stompymux` process is running, direct me to shutdown the game before making changes or instability could occur.

justfile

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
22

33
build_dir := "build"
44
build_type := env_var_or_default("CMAKE_BUILD_TYPE", "RelWithDebInfo")
5-
# clang-tidy must understand C23 `constexpr`, which landed in Clang 19; the
6-
# bare `clang-tidy` on this system still resolves to v18.
5+
# clang-tidy must understand C23 `constexpr`, which landed in Clang 19.
76
clang_tidy := env_var_or_default("CLANG_TIDY", "clang-tidy-20")
7+
run_clang_tidy := env_var_or_default("RUN_CLANG_TIDY", "run-clang-tidy-20")
88
clang_format := env_var_or_default("CLANG_FORMAT", "clang-format-20")
99

10-
default: lint build test install
10+
default: fmt build test install
11+
12+
ci: fmt-check build test
13+
14+
agent-checks: ci
1115

1216
fmt:
1317
find src -type f \( -name '*.c' -o -name '*.h' -o -name '*.h.in' \) -print0 | xargs -0 -r {{clang_format}} -i
@@ -16,32 +20,7 @@ fmt-check:
1620
find src -type f \( -name '*.c' -o -name '*.h' -o -name '*.h.in' \) -print0 | xargs -0 -r {{clang_format}} --dry-run --Werror
1721

1822
tidy:
19-
cmake -S . -B {{build_dir}} -DCMAKE_BUILD_TYPE={{build_type}} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
20-
find src -type f -name '*.c' -print0 | xargs -0 -r -n1 {{clang_tidy}} -p {{build_dir}}
21-
22-
lint: fmt lint-legacy-context tidy
23-
24-
# Core and BTech code must use scoped contexts rather than legacy aliases.
25-
lint-legacy-context:
26-
count="$(rg -l '\b(mudstate|mudconf)\b' src/mux src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy context used by $count source files" >&2; exit 1; }
27-
count="$(rg -o 'btech_context_(current_unthreaded|bind_unthreaded)|BTECH_EVALUATION_CONTEXT|\bDOCHECK(N|0|1)?\(' src/mux src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy ambient BTech context usage returned ($count occurrences)" >&2; exit 1; }
28-
count="$(rg -o '\b(getMap|getMech|WhichSpecial|FindObjectsData|IsMech|IsAuto|IsMap)\(' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy BTech object lookup APIs used $count times" >&2; exit 1; }
29-
count="$(rg -o '\b(Number|Roll)\(|\b(init_genrand|genrand_[a-z0-9_]+)\(|\brollstat\b|mt19937ar\.h' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy ambient BTech random API used $count times" >&2; exit 1; }
30-
count="$(rg -o '\bMissileHitTable\b|\bmissile_hit_table_struct\b' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy mutable missile-hit table used $count times" >&2; exit 1; }
31-
count="$(rg -o 'MechWeapons\[[^]]+\]\.(vrt|battlevalue)[[:space:]]*=' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "canonical weapon definitions mutated $count times" >&2; exit 1; }
32-
count="$(rg -o 'btech_context_evaluation\(' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -le 506 || { echo "ambient BTech evaluation accessor grew to $count uses (maximum 506)" >&2; exit 1; }
33-
count="$(rg -o 'LuaRuntime[[:space:]]*\*\*|\bspath_map\b' src/mux src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "removed raw owner-slot or path-map global returned ($count occurrences)" >&2; exit 1; }
34-
count="$(rg -o '\b(MechIDS|GetMechID|GetMechToMechID|GetMechToMechID_base|UnitPartsList|TraceLOS|ShortArmorSectionString|getStatusString|AI_Info|auto_show_command|silly_get_uptime_to_string|silly_atr_get_from|my_dump_flag|sensor_mode_name|add_color|GetLRSMech|LRSTerrain|LRSElevation|get_lrshexstr|MakeMapText|BuildBitString|BuildBitString2|BuildBitString2WithDelim|BuildBitString3|PrintArmorDamageString|ArmorKeyInfo|RetrieveValue)\(' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy static-buffer helper returned ($count occurrences)" >&2; exit 1; }
35-
count="$(rg -o 'static char (buf|buf2|buffer)\[[^]]+\]' src/btech/src/glue.scode.c src/btech/src/btech/mech.sensor.c src/btech/src/btech/mech.status.c src/btech/src/btech/template.c src/btech/src/btech/mech.advanced.c | wc -l || true)"; test "$count" -eq 0 || { echo "BTech callback or formatter static buffer returned ($count occurrences)" >&2; exit 1; }
36-
count="$(rg -o 'char[[:space:]]*\*[[:space:]]*(structure_name|center_string)\(' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "caller-owned formatter regressed to a pointer return ($count occurrences)" >&2; exit 1; }
37-
count="$(rg -o '\b(cachemech|cacheref)\b' src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "ambient reference-mech cache returned ($count occurrences)" >&2; exit 1; }
38-
count="$(rg -o '\bDestroySpecialObjects\b|free\(server->configuration\)' src/mux src/btech --glob '*.c' --glob '*.h' | wc -l || true)"; test "$count" -eq 0 || { echo "legacy composition-root teardown returned ($count occurrences)" >&2; exit 1; }
39-
40-
lint-changes:
41-
git diff --name-only -z --diff-filter=ACMR HEAD -- src | while IFS= read -r -d '' file; do case "$file" in *.c|*.h|*.h.in) {{clang_format}} -i "$file" ;; esac; done
42-
just lint-legacy-context
43-
cmake -S . -B {{build_dir}} -DCMAKE_BUILD_TYPE={{build_type}} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
44-
git diff --name-only -z --diff-filter=ACMR HEAD -- src | while IFS= read -r -d '' file; do case "$file" in *.c) {{clang_tidy}} -p {{build_dir}} "$file" ;; esac; done
23+
{{run_clang_tidy}} -clang-tidy-binary {{clang_tidy}} -p {{build_dir}} -j "$(nproc)" '^.*/src/(mux|btech)/.*[.]c$'
4524

4625
build:
4726
cmake -S . -B {{build_dir}} -DCMAKE_BUILD_TYPE={{build_type}} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
@@ -50,12 +29,14 @@ build:
5029
test:
5130
ctest --test-dir {{build_dir}} --output-on-failure
5231

53-
install: build
32+
install:
5433
cmake --install {{build_dir}} --prefix "$PWD/game"
5534

5635
run:
5736
cd game && ulimit -c unlimited && exec ./stompymux stompymux.toml
5837

38+
install-and-run: install run
39+
5940
docsite:
6041
npm --prefix docs run build
6142

src/mux/commands/command_invocation.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,3 @@ void command_invocation_call_two_vectors(CommandTwoVectorsHandler handler,
4343
invocation->first, invocation->vector, invocation->vector_count,
4444
invocation->command_arguments, invocation->command_argument_count);
4545
}
46-

src/mux/communication/comsys_context.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
void comsys_context_initialize(ComsysContext *context,
66
const ServerConfiguration *configuration,
7-
RuntimeClock *clock,
8-
ChannelRegistry *channels) {
9-
*context = (ComsysContext){.configuration = configuration,
10-
.clock = clock,
11-
.channels = channels};
7+
RuntimeClock *clock, ChannelRegistry *channels) {
8+
*context = (ComsysContext){
9+
.configuration = configuration, .clock = clock, .channels = channels};
1210
}

src/mux/network/connection_runtime.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ struct ConnectionRuntime {
2222
};
2323

2424
static inline void connection_runtime_initialize(
25-
ConnectionRuntime *runtime,
26-
const ServerConfiguration *configuration, RuntimeClock *clock,
27-
DescriptorRegistry *descriptors, ServerLog *log,
25+
ConnectionRuntime *runtime, const ServerConfiguration *configuration,
26+
RuntimeClock *clock, DescriptorRegistry *descriptors, ServerLog *log,
2827
AccessControlStore *access_control, FileCache **files_owner) {
2928
*runtime = (ConnectionRuntime){
3029
.configuration = configuration,

src/mux/server/diagnostics.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include "mux/server/diagnostics.h"
1313

1414
static void diagnostics_print_prefix(const char *file, int line,
15-
const char *func) {
15+
const char *func) {
1616
struct timeval tv;
1717
struct tm tm;
1818
time_t now;
@@ -25,7 +25,7 @@ static void diagnostics_print_prefix(const char *file, int line,
2525
}
2626

2727
void diagnostics_log(const char *file, int line, const char *func,
28-
const char *format, ...) {
28+
const char *format, ...) {
2929
va_list args;
3030

3131
diagnostics_print_prefix(file, line, func);
@@ -36,15 +36,15 @@ void diagnostics_log(const char *file, int line, const char *func,
3636
}
3737

3838
[[noreturn]] void diagnostics_assert_failed(const char *file, int line,
39-
const char *func,
40-
const char *expr) {
39+
const char *func,
40+
const char *expr) {
4141
diagnostics_print_prefix(file, line, func);
4242
fprintf(stderr, "failed assertion '%s'\n", expr);
4343
abort();
4444
}
4545

4646
void diagnostics_perror(const char *file, int line, const char *func,
47-
const char *expr, int saved_errno) {
47+
const char *expr, int saved_errno) {
4848
diagnostics_print_prefix(file, line, func);
4949
fprintf(stderr, "'%s' failed with '%s'\n", expr, strerror(saved_errno));
5050
}

src/mux/server/diagnostics.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
#include <errno.h>
66

77
void diagnostics_log(const char *file, int line, const char *func,
8-
const char *format, ...)
8+
const char *format, ...)
99
__attribute__((format(printf, 4, 5)));
1010
[[noreturn]] void diagnostics_assert_failed(const char *file, int line,
11-
const char *func,
12-
const char *expr);
11+
const char *func, const char *expr);
1312
void diagnostics_perror(const char *file, int line, const char *func,
14-
const char *expr, int saved_errno);
13+
const char *expr, int saved_errno);
1514

1615
/* dassert: abort with a timestamped message if `x` is false. Always active,
1716
* regardless of the DEBUG build option. */

0 commit comments

Comments
 (0)