Skip to content

Commit 6584b39

Browse files
hyperpolymathclaude
andcommitted
feat(reusables): add working_directory input to rust-ci + elixir-ci (#186)
## Summary Stacked on #174. Adds a `working_directory` string input (default `.`) to both reusable workflows so wrappers can target a sub-crate or sub-app layout without re-implementing the workflow. ## What changes **rust-ci-reusable.yml:** - New `working_directory` input (default `.`) - Each job declares `defaults.run.working-directory: ${{ inputs.working_directory }}` - `hashFiles('Cargo.toml')` guards now use `hashFiles(format('{0}/Cargo.toml', inputs.working_directory))` - Swatinem/rust-cache `workspaces:` parameter passes the working directory so caches are keyed per sub-crate **elixir-ci-reusable.yml:** - New `working_directory` input (default `.`) - Job declares `defaults.run.working-directory` - `mix.exs` and `mix.lock` lookups + cache `path:` entries all consult the input via `format()` ## Why Audit of the 6 remaining elixir-ci.yml consumers + the 5 complex rust-ci.yml consumers (as of 2026-05-26): **elixir (3 of 6 need this):** - burble → `server/` - feedback-o-tron → (working-directory) - verisimdb → (working-directory) **rust (1 of 5 needs this; the rest use matrix dimensions):** - reasonably-good-token-vault → per-crate (`vault-broker`, `rgtv-cli`) ## Explicitly out of scope Multi-OS / multi-Rust-version / multi-crate matrices and `cross build` support are deferred. The 4 matrix-using rust-ci repos each use a **different** matrix dimension (`os` / `rust` / `workspaces` / `manifests`) — no single shared abstraction fits cleanly. They stay bespoke for now; re-evaluate after the current wrapper sweep completes. | Repo | Matrix dimension | |---|---| | julia-the-viper | `os` (linux/macos/windows) | | verisimiser | `rust` (1.85, stable) | | reasonably-good-token-vault | `crate` (multi-workspace — covered by `working_directory` per-job) | | verisimdb | `manifest` (fuzz/Cargo.toml + rust-core/fuzz/Cargo.toml) + coverage + audit | ## Test plan - [x] YAML parse OK locally (python3 yaml.safe_load both files) - [ ] CI on this PR — but circular-validation caveat applies (per #174 PR description) — `pull_request` runs target-branch workflow, not the PR's - [ ] Owner merge order: #174 → this PR (this is stacked on `feat/rust-ci-reusable`; GitHub will retarget to `main` automatically once #174 merges) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a03e5a3 commit 6584b39

2 files changed

Lines changed: 77 additions & 9 deletions

File tree

.github/workflows/elixir-ci-reusable.yml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
4343
# with:
4444
# elixir-version: "1.18"
4545
# enable_dialyzer: true
46+
#
47+
# Sub-directory project (mix.exs lives in a subfolder — applies to
48+
# burble's server/, feedback-o-tron, verisimdb):
49+
#
50+
# jobs:
51+
# elixir-ci:
52+
# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@main
53+
# with:
54+
# working_directory: server
4655

4756
name: Elixir CI (reusable)
4857

@@ -74,6 +83,16 @@ on:
7483
type: boolean
7584
required: false
7685
default: true
86+
working_directory:
87+
description: |
88+
Directory containing `mix.exs` (relative to the repo root). All
89+
mix invocations and cache lookups consult this directory.
90+
Default `.` keeps single-app repos unchanged. Set to e.g.
91+
`server` for a sub-app layout (burble, feedback-o-tron,
92+
verisimdb at audit time).
93+
type: string
94+
required: false
95+
default: "."
7796

7897
permissions:
7998
contents: read
@@ -83,11 +102,14 @@ jobs:
83102
name: Compile + test
84103
runs-on: ${{ inputs.runs-on }}
85104
# Guard on mix.exs so the wrapper is safe to add unconditionally.
86-
if: hashFiles('mix.exs') != ''
105+
if: hashFiles(format('{0}/mix.exs', inputs.working_directory)) != ''
87106
permissions:
88107
contents: read
89108
env:
90109
MIX_ENV: test
110+
defaults:
111+
run:
112+
working-directory: ${{ inputs.working_directory }}
91113
steps:
92114
- name: Checkout repository
93115
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -104,14 +126,14 @@ jobs:
104126
- name: Cache deps
105127
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
106128
with:
107-
path: deps
108-
key: deps-${{ inputs.elixir-version }}-${{ hashFiles('mix.lock') }}
129+
path: ${{ inputs.working_directory }}/deps
130+
key: deps-${{ inputs.elixir-version }}-${{ hashFiles(format('{0}/mix.lock', inputs.working_directory)) }}
109131

110132
- name: Cache _build
111133
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
112134
with:
113-
path: _build
114-
key: build-${{ inputs.elixir-version }}-${{ hashFiles('mix.lock') }}
135+
path: ${{ inputs.working_directory }}/_build
136+
key: build-${{ inputs.elixir-version }}-${{ hashFiles(format('{0}/mix.lock', inputs.working_directory)) }}
115137

116138
- name: Install deps
117139
run: mix deps.get

.github/workflows/rust-ci-reusable.yml

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@
2929
# with:
3030
# enable_audit: true
3131
# enable_coverage: true
32+
#
33+
# Sub-crate / monorepo workspace (Cargo.toml lives in a subdirectory):
34+
#
35+
# jobs:
36+
# rust-ci-cli:
37+
# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@main
38+
# with:
39+
# working_directory: crates/cli
40+
# rust-ci-server:
41+
# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@main
42+
# with:
43+
# working_directory: crates/server
44+
#
45+
# Out-of-scope (left bespoke per-repo): multi-OS matrices, cross-compile
46+
# (`cross build`), multi-Rust-version matrices. Each has too much per-repo
47+
# variance to share a single abstraction cleanly (verified against the 5
48+
# matrix-using repos as of 2026-05-26: julia-the-viper / verisimdb /
49+
# verisimiser / reasonably-good-token-vault use four different matrix
50+
# dimensions).
3251

3352
name: Rust CI (reusable)
3453

@@ -65,6 +84,17 @@ on:
6584
type: string
6685
required: false
6786
default: "--all-targets"
87+
working_directory:
88+
description: |
89+
Directory containing `Cargo.toml` (relative to the repo root). All
90+
cargo invocations cd into this directory; `hashFiles()` guards also
91+
consult it. Default `.` keeps single-crate repos unchanged. Set
92+
to e.g. `crates/server` for a sub-crate, or pass a different
93+
value per wrapper call when running the reusable in a workspace
94+
via separate jobs.
95+
type: string
96+
required: false
97+
default: "."
6898

6999
permissions:
70100
contents: read
@@ -76,9 +106,12 @@ jobs:
76106
check:
77107
name: Cargo check + clippy + fmt
78108
runs-on: ${{ inputs.runs-on }}
79-
if: hashFiles('Cargo.toml') != ''
109+
if: hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != ''
80110
permissions:
81111
contents: read
112+
defaults:
113+
run:
114+
working-directory: ${{ inputs.working_directory }}
82115
steps:
83116
- name: Checkout repository
84117
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -93,6 +126,8 @@ jobs:
93126

94127
- name: Cache cargo registry and build
95128
uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
129+
with:
130+
workspaces: ${{ inputs.working_directory }}
96131

97132
- name: Cargo check
98133
run: cargo check ${{ inputs.check_args }}
@@ -107,9 +142,12 @@ jobs:
107142
name: Cargo test
108143
runs-on: ${{ inputs.runs-on }}
109144
needs: check
110-
if: hashFiles('Cargo.toml') != ''
145+
if: hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != ''
111146
permissions:
112147
contents: read
148+
defaults:
149+
run:
150+
working-directory: ${{ inputs.working_directory }}
113151
steps:
114152
- name: Checkout repository
115153
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -122,6 +160,8 @@ jobs:
122160

123161
- name: Cache cargo registry and build
124162
uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
163+
with:
164+
workspaces: ${{ inputs.working_directory }}
125165

126166
- name: Run tests
127167
run: cargo test ${{ inputs.test_args }}
@@ -139,9 +179,12 @@ jobs:
139179
audit:
140180
name: Cargo audit (security)
141181
runs-on: ${{ inputs.runs-on }}
142-
if: ${{ inputs.enable_audit && hashFiles('Cargo.toml') != '' }}
182+
if: ${{ inputs.enable_audit && hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
143183
permissions:
144184
contents: read
185+
defaults:
186+
run:
187+
working-directory: ${{ inputs.working_directory }}
145188
steps:
146189
- name: Checkout repository
147190
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -164,9 +207,12 @@ jobs:
164207
coverage:
165208
name: Coverage (tarpaulin + codecov)
166209
runs-on: ${{ inputs.runs-on }}
167-
if: ${{ inputs.enable_coverage && hashFiles('Cargo.toml') != '' }}
210+
if: ${{ inputs.enable_coverage && hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
168211
permissions:
169212
contents: read
213+
defaults:
214+
run:
215+
working-directory: ${{ inputs.working_directory }}
170216
steps:
171217
- name: Checkout repository
172218
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

0 commit comments

Comments
 (0)