Skip to content

Migrate pipeline from CircleCI to GitHub Actions - #214

Closed
phelma wants to merge 2 commits into
mainfrom
gha-migration
Closed

Migrate pipeline from CircleCI to GitHub Actions#214
phelma wants to merge 2 commits into
mainfrom
gha-migration

Conversation

@phelma

@phelma phelma commented Jul 20, 2026

Copy link
Copy Markdown

Cutover to GitHub Actions per the Variant B family plan (docker image).
Includes decommission — merging this PR completes the repo's migration.

  • main + pr workflows: check/test, prerelease, release environment gate
  • PR CI publishes a namespaced pre-release image (proves the publish path
    before merge — see the deliberate-decisions note below)
  • git-crypt unlock on the runner; encrypted CI GPG key moved to .github/
  • Docker builds/publishes use the runner's native docker daemon (replaces
    CircleCI's setup_remote_docker + install scripts); the integration suite
    builds the image and runs its docker-compose dependencies on the runner
  • Docker Hub credentials load guarded against a locked tree (dynamic block
    detecting the git-crypt \0GITCRYPT header, nil credentials when locked)
    so PR checks run without unlocking git-crypt — the one deliberate change
    inside the image namespace
  • Slack notifications via rake_slack; dependabot auto-merge job
  • Rakefile provisioning swapped to rake_github secrets/environments; rake_circle_ci dropped
  • CircleCI pipeline removed: .circleci/, scripts/ci/, the CI SSH deploy
    key pair and its keys:deploy/deploy_keys provisioning, and the stored
    CircleCI/GitHub API credentials (config/secrets/{circle_ci,github}/)

Deliberate decisions (not defects)

This cutover reproduces the CircleCI pipeline's behaviour, warts included;
fixing inherited hazards is post-migration work. In particular:

  • version:bump[rc]/version:release tag and push before
    image:publish runs — a failed publish leaves a version tag with no image
    behind it. Pre-existing ordering inside the untouched release logic.

  • An rc image is published to Docker Hub on every push to main with no
    approval gate; only full releases are gated (environment: release).

  • version:bump[rc] on a released version increments minor and starts
    rc.1 — every release cycle is a minor bump. Pre-existing
    lib/version.rb logic.

  • Dependabot auto-merge accepts any update type that passes checks, and the
    merge does not trigger a release build — on CircleCI the merge commit
    carried [skip ci], and the merge subject here carries the same literal
    marker (belt-and-braces against a future non-GITHUB_TOKEN token).
    Updates ship with the next human-triggered release.

  • The old pipeline ran CI only on main and dependabot/* branches;
    pr.yaml running on every pull request is a deliberate family-uniform
    improvement.

  • PR prerelease publish (permanent feature, not migration scaffolding).
    On every push to a same-repo human PR, the prerelease job builds the
    image and pushes it to Docker Hub under a single PR-namespaced tag
    (<next-version>.pr<PR>.<run>.<attempt>) — proving the publish path before
    merge instead of discovering a broken push only on main. It publishes
    that tag only, never latest, and pushes no git tag or commit
    (contents: read). Skipped for forks and dependabot (no secrets). The
    namespaced tags can never collide with main's rc sequence; they accumulate
    on Docker Hub, the same accepted cost as main's ungated rc publishes.

  • The release job pulls main (--ff-only, after the CI git author is
    set) at approval time, so a delayed approval releases main as it stands
    then, not the SHA this run tested — parity with the old release.sh
    (which also pulled; prerelease.sh did not, so the prerelease job has no
    pull). A non-fast-forward pull fails loudly rather than merging.

  • The release-gate job asserts the release environment has protection
    rules before approving — GitHub silently auto-creates an unprotected
    environment if provisioning never ran, which would release ungated.

  • Version tags live in git only — there is no version-bump commit, so no
    push-back commit to guard against.

  • asdf_install@v1 is our own action (infrablocks/github-actions); we are
    happy tracking its major version tag.

  • Jobs that resolve version tags (test, prerelease, release) check out
    with fetch-depth: 0 — the Rakefile's latest_tag needs the full tag set.

  • The test jobs carry a guard step installing standalone docker-compose
    only if the runner image lacks it (the Rakefile shells out to the
    standalone binary); it is a no-op where compose is present or unused.

  • Job scaffolding is repeated flat per job by design: the logic lives in the
    build system (./go/rake) and CI stays lean — it just triggers tasks and
    supplies secrets/context.

  • Where the repo's Ruby was older than 3.3.11, .tool-versions is bumped to
    3.3.11 per the org-wide Ruby policy (plan §4.5) — older Rubies cannot
    hold a stable lockfile on CI.

  • Gemfile.lock carries transitive major bumps — the unavoidable resolution
    of the targeted bundle lock --update, not scope creep.

  • Small hunks may appear where the refreshed toolchain's rubocop
    autocorrects existing code — required by the library:check verification
    gate, not drive-by refactoring.

  • Provisioning (pipeline:prepare) authenticates with the operator's ambient
    gh login (GITHUB_TOKEN fallback) instead of a stored PAT — a deliberate
    parity deviation; the stored token in config/secrets/github/config.yaml
    is deleted with the rest of the CircleCI-era credentials.

  • Deleting config/secrets/{circle_ci,github}/ removes the CircleCI API
    token and stored PAT from the tree but does not revoke them — both
    remain live at their issuers and recoverable (git-crypted) from history.
    Revocation is a host-side step on the end-of-migration sweep checklist,
    alongside disabling the CircleCI project and deleting the deploy key.

Do not merge manually — the pipeline merges once checks are green.
Disabling the CircleCI project, deleting the CircleCI deploy key, and
revoking the CircleCI API token + stored PAT are deferred to the
end-of-migration sweep.


🏭 This PR was opened by Foundry, Atomic's AI software development
factory. Implementation, review, and fixes are performed by AI agents;
merges happen automatically once the review and checks gates pass.
This task migrates a Docker image repo's CI from CircleCI to GitHub Actions.

Pipeline Task pack Family Run
migrate migrate-docker docker_image 2026-07-20T22-00-29-255Z

atomic-foundry-pr · foundry-pipeline: migrate · foundry-task: migrate-docker · foundry-run: 2026-07-20T22-00-29-255Z

phelma added 2 commits July 20, 2026 23:33
nokogiri 1.18.8 was yanked from rubygems, so bundle install failed in CI.
Targeted 'bundle lock --update=nokogiri' bumps it to 1.19.4 (linux platform
entry becomes x86_64-linux-gnu). No other gems changed.

@phelma phelma left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Code Review: #214 - Migrate pipeline from CircleCI to GitHub Actions

Verdict: COMMENT

Reviewed through five lenses (correctness, security, safety, standards, code quality) against the Variant B family plan. The diff is a faithful, near-verbatim implementation of the plan: both workflows reproduce §4.1/§4.2 exactly (job/step names and order, timeout-minutes, fetch-depth: 0 where tags matter, per-job permissions, the gate/slot concurrency split), the three retained/added scripts match their prescribed bodies, the Rakefile blocks and prerelease:publish task carry the correct node-exporter-aws substitutions, and decommission is complete (git grep -i circleci clean, config/secrets/ci/ holds only encryption.passphrase + the GPG pair, no prerelease gems in the lockfile, Ruby bumped to 3.3.11). Only two small in-scope deviations were found; the remaining findings all challenge decisions the plan or PR description documents as deliberate and are recorded below for a human to revisit at plan level.

Cross-Cutting Themes

  • queue: max concurrency key (flagged by: correctness, safety) — three lenses independently doubted this key exists in the Actions schema. It is prescribed verbatim by plan §4.2, which cites the 2026-05-07 GA changelog for larger concurrency queues. Plan concern, not a defect of this diff — but if the key is in fact invalid, main.yaml fails to parse fleet-wide, so it is worth one host-side confirmation before the family rolls out.
  • docker-compose pinned to v5.3.1 (flagged by: correctness, security, safety, code quality) — all four lenses read v5.x as implausible for docker/compose. Plan §4.7 pins exactly this version and checksum and records it as verified on 2026-07-20 against the release's checksums.txt, explicitly asking reviewers not to re-raise it. Plan concern. Same note as above: a wrong pin fails every test job.
  • Supply-chain pinning by mutable tag (flagged by: security) — asdf_install@v1 / actions/checkout@v4. Plan §1 explicitly accepts tracking the v1 major tag for our own action. Plan concern.

Tradeoff Analysis

  • Security vs. plan parity (PR prerelease publish): the security lens notes the prerelease job decrypts ENCRYPTION_PASSPHRASE and Docker Hub credentials while running branch-controlled code (Rakefile, go, scripts/ci/*), so push access is effectively promoted to secret-read access with no reviewer in the loop. This is D9 / §4.4 step 7 — deliberate and in scope for the plan. Worth revisiting at plan level (an environment: with reviewers, or a PR-namespace-scoped registry token) rather than blocking this PR.
  • Safety vs. parity (release checks out ref: main and pulls): an approver may approve run for commit A and ship commit C. Plan §4.2 prescribes this as parity with the old release.sh. Plan concern.

Strengths

  • ✅ Untrusted PR-controlled values (title, URL, number) are passed via env: rather than ${{ }}-interpolated into run: — the classic GHA script-injection sink is closed throughout.
  • gh pr merge --match-head-commit "$HEAD_SHA" closes the checks-pass-then-push race on dependabot auto-merge.
  • ✅ The \0GITCRYPT header guards (credentials dynamic block, provisioning passphrase, prerelease:publish) convert silent late failures into immediate, actionable ones — and the header check is correctly preferred over rescuing Psych::SyntaxError.
  • assert-release-environment-protected.sh turns GitHub's fail-open auto-created environment into a fail-closed gate.
  • ✅ Explicit repo_tag: on image.push correctly works around docker-api resolving the push repository from cached RepoTags, and the comment explains why.
  • git pull --ff-only, cancel-in-progress: false on all tag/publish jobs, and timeout-minutes on every job.
  • ✅ Decommission is complete and surgical; the GPG key move is a pure rename.
  • ✅ Comments are self-contained and never leak plan/D-number/migration-process context, per the plan's comment rule.

General Findings

  • 🔵 Standards: Two small deviations from the plan's prescribed shapes — see inline comments on Gemfile and Rakefile.
  • 🔵 Security: Docker Hub credentials are read inside Ruby from git-crypted YAML rather than passed as an Actions secret, so they are never registered with ::add-mask::. Any exception or push-error chunk echoing the auth hash would appear verbatim in public logs. The plan accepts credentials-in-git-crypted-YAML; a defensive mask after unlock would be cheap insurance. (Not plan-specified — genuinely open.)

Plan Concerns (deliberate decisions challenged by lenses — not blocking)

Recorded so a human can revisit the plan, per the parity principle in §1:

  • 🔴→PC queue: max on the prerelease and release jobs (main.yaml) — plan §4.2 verbatim.
  • 🔴→PC docker-compose v5.3.1 + sha256 pin — plan §4.7 verbatim, recorded as verified 2026-07-20.
  • 🟡→PC release-gate token scope: gh api .../environments/release may need more than the inherited contents: read GITHUB_TOKEN; if it 403s, [ "" -eq 0 ] is a confusing bash error rather than a clear message. Plan §4.7 prescribes the script body verbatim.
  • 🟡→PC release-gate assertion runs after approval, so it reports rather than prevents the unprotected-environment case; and environment: release sits on the gate, not on the privileged release job. Both are the plan's deliberate gate/slot split (§4.2).
  • 🟡→PC prerelease:publish arguments unvalidated — an empty arg yields …-rc.1.pr.., rejected only at push time after a full build. Plan §4.4 step 7 gives the exact task body.
  • 🟡→PC PR prerelease job exposes secrets to any branch pusher — D9, documented.
  • 🟡→PC release publishes main at approval time, not the approved SHA — plan §4.2 parity with release.sh.
  • 🟡→PC Actions pinned by mutable tag (asdf_install@v1) — plan §1 accepts.
  • 🔵→PC Tag-then-publish ordering leaves a version tag with no image on a failed publish; no recovery runbook documented. Plan §1 parity hazard.
  • 🔵→PC Deleted CircleCI secret files are not revoked at their issuers — plan §1 and "Out of scope"; tracked on the end-of-migration sweep.
  • 🔵→PC README's openssl … -md sha1 legacy KDF — pre-existing, untouched by this diff.
  • 🔵→PC Rakefile duplication / task length: the \0GITCRYPT sniff appears three times, node-exporter-aws is repeated four times in prerelease:publish, and the locked-tree credential skip is silent. All are the plan's verbatim templates; extracting helpers would be a family-wide plan amendment, not per-repo drift.
  • 🔵→PC latest_tag.rc! bang-method mutation in prerelease:publish — plan verbatim; benign given the current task ordering.

Review generated by /accelerator:review-pr

Comment thread Gemfile
gem 'rake_git'
gem 'rake_git_crypt'
gem 'rake_factory', '~> 0.33.0'
gem 'rake_git', '~> 0.2.0'

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Standards — severity: minor | confidence: medium

Plan §4.5 prescribes adding gem 'rake_slack' and gem 'rake_factory', and says version constraints should be added only where needed to hold a gem to its stable line (the no-prerelease-gems rule). Four pins appear here — rake_factory '~> 0.33.0', rake_git '~> 0.2.0', rake_git_crypt '~> 0.4.0', ruby_git_crypt '~> 0.1.0' — while every other gem stays unconstrained.

Impact: rake_git and ruby_git_crypt were previously unpinned and are now held at older lines; more pins than necessary is per-repo drift from the family-uniform Gemfile shape, which bites when the fleet upgrades.

Suggestion: Keep only the pins genuinely load-bearing for the anti-prerelease rule (likely rake_factory), drop the rest — or note in the PR description why each is required. Note plan §4.5 also requires rake_git_crypt >= 0.4.0 and rake_github >= 0.17.0 in the lockfile, which ~> 0.4.0 satisfies but also caps.

Comment thread Rakefile
end
end

# rubocop:disable Metrics/BlockLength

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Standards / Code Quality — severity: minor | confidence: high

A # rubocop:disable Metrics/BlockLength / # rubocop:enable pair has been added around the RakeGithub.define_repository_tasks block. Plan §4.4 step 3's template does not include it, and the plan's comment rule says the templates are "a ceiling, not a floor — reproduce them, do not add more".

Impact: Cosmetic drift from the family-uniform Rakefile. If the block genuinely exceeds the limit here it will exceed it in every sibling repo too, so the fix belongs in the plan rather than in one repo.

Suggestion: Confirm the disable is actually needed under this repo's rubocop config; if it is, raise it as a plan amendment so the whole family stays diffable against one template. (Extracting github_token / ci_passphrase helpers above the block would shrink it below the limit without a suppression — also a plan-level change.)

concurrency:
group: main-tags
cancel-in-progress: false
queue: max

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Plan concern (correctness + safety lenses) — not a defect of this diff

Both lenses independently flagged queue: max as absent from the Actions concurrency schema (which they read as accepting only group and cancel-in-progress). This line is prescribed verbatim by family plan §4.2, which cites the 2026-05-07 changelog announcing larger concurrency queues, so it is deliberate and out of scope for this PR.

Raising it only because the blast radius is fleet-wide: if the key is in fact unsupported, main.yaml fails to parse in every migrated repo, and if it is silently ignored the documented "keep every queued publish" property does not hold (Actions retains only the newest pending run). Worth one host-side confirmation on the pilot's first main run before the family rolls out. Same applies to the release job's identical block.

# fleet-wide change, not per-repo drift.
if ! command -v docker-compose >/dev/null 2>&1; then
curl -fsSL \
"https://github.com/docker/compose/releases/download/v5.3.1/docker-compose-linux-x86_64" \

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Plan concern (correctness, security, safety, code-quality lenses) — not a defect of this diff

All four lenses read v5.3.1 as implausible for docker/compose (they expect the v2.x line) and therefore could not corroborate the sha256. This pin and checksum are prescribed verbatim by plan §4.7, which records them as verified on 2026-07-20 against that release's checksums.txt and explicitly asks reviewers not to re-raise it — so this is deliberate.

Flagged only for blast radius: if the pin were wrong, curl -fsSL 404s under set -euo pipefail and every test job on both workflows fails at setup, fleet-wide. The PR's own test check is the authoritative proof — confirm it went green on a runner before merging.

The script's structure is otherwise sound: verify-before-install in a scratch path, sudo install only after sha256sum -c passes.

# step.
count=$(gh api \
"repos/${GITHUB_REPOSITORY}/environments/release" \
--jq '.protection_rules | length')

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Plan concern (correctness + safety lenses) — not a defect of this diff

This script body is prescribed verbatim by plan §4.7, so the shape is deliberate. Two lens observations worth carrying back to the plan rather than fixing here:

  1. Token scope: gh api repos/.../environments/release typically needs more than the workflow-level contents: read the release-gate job inherits. If it returns 403/404, --jq yields an empty string and [ "" -eq 0 ] fails with an opaque bash error — indistinguishable from "genuinely unprotected". A count=$(... || echo "") plus an explicit non-numeric check would separate "cannot check" from "not protected".
  2. Ordering: because environment: release suspends the job before any step runs, this assertion executes only after a human has already approved — so it reports the unprotected case rather than preventing it. (It still fails the release closed, which is the substantive guarantee.)

Both are family-wide, so they belong in the plan, not this repo.

Comment thread Rakefile
# Docker tags forbid '+', so we reuse the semver '-'/'.'-separated
# form and no build metadata. No git tag is created, pushed, or
# committed — unlike version:bump this only ever tags the built image.
pr_tag = "#{latest_tag.rc!}.pr#{args.pr_number}" \

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Plan concern (correctness lens) — not a defect of this diff

args.pr_number / args.run_number / args.run_attempt are interpolated straight into the image tag with no presence check. A misinvocation (or an empty env var in the workflow) yields e.g. 0.2.0-rc.1.pr.., which Docker rejects only at push time — after a full image build has already run.

The task body is prescribed verbatim by plan §4.4 step 7, so this is out of scope here. If the plan is revisited, a fail-fast guard at the top of the task would turn a late, opaque registry error into an immediate one:

%i[pr_number run_number run_attempt].each do |k|
  raise ArgumentError, "#{k} required" if args[k].to_s.empty?
end

Comment thread .github/workflows/pr.yaml
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login != 'dependabot[bot]'
concurrency:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Plan concern (security lens) — not a defect of this diff

The guard correctly excludes forks and dependabot, and keys on the immutable user.login rather than github.actor — both right. The lens notes the residual: anyone with push access can open a same-repo PR whose branch modifies Rakefile, go, or scripts/ci/common/*, and that modified code then runs in the job that decrypts ENCRYPTION_PASSPHRASE and the Docker Hub credentials — no reviewer in the loop.

This is D9 / plan §4.4 step 7, explicitly in scope and deliberate, so it does not block. Carrying it back to the plan: if PR-time publish proof is worth keeping (it is), binding this job to an environment: with reviewers, or issuing a push-only Docker Hub token scoped to the PR tag namespace, would close the gap without losing the feature.

- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Plan concern (safety lens) — not a defect of this diff

ref: main plus git pull --ff-only means the release publishes main as of approval time, not the SHA whose checks the approver saw. Approve for commit A, ship commit C.

Plan §4.2 prescribes exactly this as parity with the old release.sh (which also pulled), and the PR description documents it — deliberate. --ff-only correctly makes a non-fast-forward fail loudly rather than creating a CI merge commit. Noted only so the tradeoff is visible to a human revisiting the plan; pinning to github.sha would be the alternative.

@phelma
phelma marked this pull request as ready for review July 20, 2026 22:52
Copilot AI review requested due to automatic review settings July 20, 2026 22:52

Copilot AI 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.

Pull request overview

This PR completes the repository’s CI/CD migration from CircleCI to GitHub Actions, updating the build/release pipeline, secrets handling, and related tooling to align with the “Variant B family plan” for Docker image publishing.

Changes:

  • Replaces CircleCI config and step scripts with GitHub Actions workflows for PR and main (including prerelease + gated release).
  • Updates Rake tasks to provision GitHub secrets/environments, adds Slack notification tasks, and adjusts Docker Hub credential loading for locked git-crypt trees.
  • Refreshes the Ruby/tooling stack (Ruby 3.3.11 and dependency lock updates) and relocates the encrypted CI GPG key into .github/.

Reviewed changes

Copilot reviewed 21 out of 27 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
scripts/ci/steps/test.sh Removes CircleCI test step script (superseded by GHA jobs).
scripts/ci/steps/release.sh Removes CircleCI release step script (superseded by GHA release job).
scripts/ci/steps/prerelease.sh Removes CircleCI prerelease step script (superseded by GHA prerelease job).
scripts/ci/steps/merge-pull-request.sh Removes CircleCI dependabot merge script (replaced by GHA merge job).
scripts/ci/common/install-slack-deps.sh Removes CircleCI-specific Slack deps installer.
scripts/ci/common/install-gpg-key.sh Removes CircleCI-specific GPG key install script (key artifact moved).
scripts/ci/common/install-git-crypt.sh Updates git-crypt install script for GHA runners (sudo, stricter bash flags).
scripts/ci/common/install-docker.sh Removes CircleCI docker installer (runner daemon used in GHA).
scripts/ci/common/install-docker-compose.sh Adds pinned, checksum-verified docker-compose installer for integration tests.
scripts/ci/common/install-asdf.sh Removes CircleCI asdf install script (replaced by shared asdf action).
scripts/ci/common/install-asdf-dependencies.sh Removes CircleCI asdf dependency installation step.
scripts/ci/common/configure-git.sh Removes CircleCI git author config script (replaced by rake task).
scripts/ci/common/configure-asdf.sh Removes CircleCI asdf plugin configuration script.
scripts/ci/common/assert-release-environment-protected.sh Adds fail-closed guard ensuring release environment has protection rules.
README.md Updates CI key management docs for new encrypted key location under .github/.
Rakefile Swaps CircleCI provisioning for GitHub Actions provisioning; adds Slack + PR prerelease publish task; adds Docker Hub credential locking guard.
Gemfile.lock Updates lockfile for new/updated pipeline dependencies and Ruby/tooling changes.
Gemfile Removes CircleCI gems; pins/selects updated rake-related gems (GitHub/Slack/git-crypt).
.tool-versions Bumps Ruby version to 3.3.11.
.github/workflows/pr.yaml Adds PR workflow: check/test + PR prerelease publish + Dependabot merge job.
.github/workflows/main.yaml Adds main workflow: check/test + prerelease publish + protected release gate + release publish.
.github/gpg.private.enc Adds encrypted CI GPG private key artifact under .github/.
.circleci/config.yml Removes CircleCI pipeline configuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/pr.yaml
Comment on lines +2 to +4
on:
pull_request:

Comment thread .github/workflows/pr.yaml
Comment on lines +9 to +12
check:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Comment thread .github/workflows/pr.yaml
Comment on lines +25 to +28
test:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Comment thread .github/workflows/pr.yaml
Comment on lines +53 to +55
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login != 'dependabot[bot]'
Comment thread .github/workflows/pr.yaml
needs: [check, test]
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.event.pull_request.user.login == 'dependabot[bot]'
@phelma

phelma commented Jul 24, 2026

Copy link
Copy Markdown
Author

Closing to re-run this migration fresh through the updated pipeline.

@phelma phelma closed this Jul 24, 2026
@phelma
phelma deleted the gha-migration branch July 24, 2026 13:25
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.

2 participants