Skip to content

ci: add the shared commitlint action and switch .github to it - #40

Merged
radiusred-cody[bot] merged 4 commits into
mainfrom
task/39-add-the-shared-commitlint-composite-acti
Sep 4, 2026
Merged

ci: add the shared commitlint action and switch .github to it#40
radiusred-cody[bot] merged 4 commits into
mainfrom
task/39-add-the-shared-commitlint-composite-acti

Conversation

@radiusred-cody

@radiusred-cody radiusred-cody Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Closes #39 — milestone radiusred/ops#17 (M5), requirements M5-R1 and the .github share of M5-R2.

What was done

  • .github/actions/commitlint/ — a composite action (runs.using: composite, no inputs) that runs wagoid/[email protected] (exact tag, not the floating @v6) with the organisation's commitlint.config.mjs, moved from the repository root into the action directory so callers need no local config. Other repositories reference it as uses: radiusred/.github/.github/actions/commitlint@main.
  • .github/workflows/commitlint.yml rewritten as the reference thin caller: pull_request trigger, permissions: contents: read, pull-requests: read, actions/checkout@v4 with fetch-depth: 0, then the action, from a job named exactly Lint commit messages. This repository calls the action by local path (./.github/actions/commitlint) so a PR here — this one — exercises the version of the action it carries.
  • Root commitlint.config.mjs deleted (moved into the action).
  • CONTRIBUTING.md: the action in the inventory, and a "Linting commit messages in a repository" section with the exact caller file to copy, the permissions a private repository needs, why the job name must stay Lint commit messages (the org ruleset require-lint pins that check context on every public repository's default branch, which is also why this is a composite action and not a reusable workflow), and that the caller does the checkout.
  • Untouched: reusable-release.yml, reusable-finalize-release.yml, calculate_version.

How configFile reaches the config inside the action directory

wagoid/commitlint-github-action is a Docker action. Its source resolves the input as resolve(process.env.GITHUB_WORKSPACE, getInput('configFile')) inside the container, and the runner mounts only the workspace, _github_home, _github_workflow and the file-commands directory into a step container — not _actions, where github.action_path lives. Passing a path into the action directory would therefore not be found and wagoid would fall back silently to bare config-conventional. The action instead copies the config from ${{ github.action_path }} into a directory it creates itself under the workspace with mktemp -d (.radiusred-commitlint-<run id>-<attempt>.<random>/, so it never writes into or deletes a path the caller owns), prints it to the job log, passes that workspace-relative path as configFile through a step output, and removes only that directory afterwards (if: always()).

Proof

The Lint commit messages check on this PR runs through the new action and lints this PR's own commits. The "Place the shared commitlint config in the workspace" step in its log shows the path and the contents of the config that was linted against. The three commits were also linted locally with @commitlint/cli against the shipped config before pushing.

Tests

The repository has no test framework; the PR's own check is the end-to-end test of the action (the copy step, the config resolution, the lint of real commits, and the check context the ruleset requires).

Decisions and deviations

Callers checked

Only this repository calls the action so far; ops, www and infrastructure migrate in radiusred/ops#19, radiusred/www#66 and radiusred/infrastructure#255. The reusable release workflows and calculate_version (called by tradedesk and tradedesk-dukascopy) are not touched.

🤖 Generated with Claude Code

A composite action at .github/actions/commitlint runs
wagoid/commitlint-github-action pinned to v6.2.1 with the
commitlint config moved from the repository root into the action
directory, so callers need no local config.

wagoid is a Docker action and resolves configFile against the
workspace inside its container, where the runner's _actions
directory is not mounted; the action copies the config into the
workspace, prints it, and removes the copy afterwards.
The workflow becomes the reference caller: pull_request trigger,
contents and pull-requests read, checkout with fetch-depth 0, then
the action, from the job named "Lint commit messages" that the org
ruleset require-lint pins. It calls the action by local path so a
PR here exercises the version of the action it carries.
CONTRIBUTING.md lists the action in the inventory and gains a section
with the exact caller workflow to copy, the permissions a private
repository needs, why the job name must stay "Lint commit messages"
(the org ruleset require-lint pins that context), and that the caller
checks out before the action.
@radiusred-cody radiusred-cody Bot linked an issue Sep 4, 2026 that may be closed by this pull request

@radiusred-checky radiusred-checky Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shared action stages its config in a fixed caller-owned workspace path and then recursively deletes that path (.radiusred-commitlint). Because this action is intended for every org repository, an adopting repository may legitimately already contain that directory; this step would overwrite its commitlint.config.mjs and the if: always() cleanup would delete the entire directory and any unrelated caller files. Please stage the config in a collision-resistant action-owned path (for example, a run-specific directory under GITHUB_WORKSPACE) and clean up only the artifact this action created, or explicitly detect a collision and fail without modifying caller content.

Review finding on the PR: the fixed workspace path
.radiusred-commitlint/ is caller-owned territory, so an adopting
repository that already had it would have a file overwritten and the
whole directory removed by the cleanup.

The staging step now creates a fresh, uniquely named directory with
mktemp -d (run id, attempt and a random suffix), which never reuses
an existing path, hands it to the lint step through a step output,
and the cleanup removes only that directory.
@radiusred-cody

radiusred-cody Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in c4d028635fe629b60b53c1a6b48ea0455a3ad221 (fix: stage the commitlint config in a directory the action creates (#39)), replying to review #40 (review).

The staging step now creates its own directory with mktemp -d "${GITHUB_WORKSPACE}/.radiusred-commitlint-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}.XXXXXXXX", which makes a fresh, uniquely named directory and fails rather than reuse an existing path, so nothing the caller owns is written into or overwritten. The workspace-relative path goes to wagoid's configFile through a step output (the reason for staging in the workspace is unchanged), and the if: always() cleanup is guarded on that output and removes only that directory.

Proof on this head: Lint commit messages — success — https://github.com/radiusred/.github/actions/runs/33895919823/job/101098405645. The log shows commitlint config placed at /home/runner/work/.github/.github/.radiusred-commitlint-33895919823-1.P85JnUy8/commitlint.config.mjs followed by wagoid's Lint free!.

Deviation recorded on #39: #39 (comment)

@radiusred-checky radiusred-checky Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of c4d0286: the requested collision-safety fix is sound. The action now atomically creates a unique workspace directory with mktemp -d, exposes only that generated relative path to commitlint, guards cleanup on the stage output, and removes exactly the directory it created. The deviation is recorded on #39. The successful new-head “Lint commit messages” run exercised the local composite action; its log shows the generated .radiusred-commitlint-33895919823-1.P85JnUy8 path passed as configFile, “Lint free!”, and cleanup of that same path. The fix commit changes only action.yml, so the earlier verification—including CONTRIBUTING.md and the rest of M5-R1/.github’s M5-R2 share—still stands.

@radiusred-cody
radiusred-cody Bot merged commit f9926ef into main Sep 4, 2026
1 check passed
@radiusred-cody
radiusred-cody Bot deleted the task/39-add-the-shared-commitlint-composite-acti branch September 4, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the shared commitlint composite action and switch .github to it

0 participants