Skip to content

ci: migrate from CircleCI to GitHub Actions - #28

Merged
rgamba merged 2 commits into
mainfrom
claude/circleci-github-actions-migration-bd642e
Sep 15, 2026
Merged

rgamba merged 2 commits into
mainfrom
claude/circleci-github-actions-migration-bd642e

Conversation

@rgamba

@rgamba rgamba commented Sep 15, 2026 •

Copy link
Copy Markdown
Member

Summary

Now that the repository is public, CI moves from CircleCI to GitHub Actions. This PR reproduces the existing pipeline job for job and removes .circleci/config.yml.

Architecture

Three workflow files under .github/workflows/:

File Role
jvm-build.yml Reusable (workflow_call) JVM build: compile, full test suite, publishToMavenLocal validation, Gradle cache, test-report and jar artifacts. Takes jackson_version.
build.yml On every pull request and push to main: the Jackson matrix (2.9.10 default, 2.13.5, 2.17.3, 2.22.2) calling jvm-build.yml, format-check, examples, the jvm-build fan-in, web-build; on main only, web-publish and tag-release.
release.yml On a vX.Y.Z tag: jvm-build.yml once, then publish-release to Maven Central.

The JVM build is one reusable workflow rather than two copies, so the release runs exactly the build pull requests were gated on.

Key decisions and trade-offs

  • Triggers. CircleCI built every push; this runs on pull_request plus pushes to main. That covers pull requests from forks (which CircleCI never built) without running every branch twice. A branch with no PR gets no CI, which matches how the repo is worked on (squash merges through PRs).
  • No deploy key. The gh-pages push and the release tag push use the run's own GITHUB_TOKEN with contents: write. One fewer credential to rotate, and nothing to configure.
  • Tag-release dispatches the release. A push made with GITHUB_TOKEN deliberately starts no workflow, so tag-release runs gh workflow run release.yml --ref vX.Y.Z after pushing the tag. A hand-pushed tag still starts the release through its own push trigger. release.yml guards against a workflow_dispatch on anything that is not a release tag.
  • Context to repository secrets. The CircleCI skipper-publish context becomes four repository secrets of the same names, so the values move over unchanged. GitHub Environments are not available on this repository, so the tag-only restriction they would have given is not possible; forks never see the secrets, and push access is the boundary.
  • Required check name. The fan-in job is named jvm-build, so the ruleset's required check changes from ci/circleci: jvm-build to jvm-build.
  • Examples depend on the whole matrix. A job cannot depend on a single matrix leg, so examples waits for all four Jackson builds instead of only 2.9.10. They run in parallel, so the cost is small.
  • Examples cache hygiene. The examples' Maven cache is scrubbed of the 0.0.0-CI tree before the download and before saving, so a cached copy can never shadow the artifacts the run just built.
  • Runner. ubuntu-22.04 where the MariaDB4j native libraries (libaio1, libncurses5) are needed, since those package names do not exist on 24.04; ubuntu-latest elsewhere.
  • Dropped. The optional SKIPPER_ARTIFACTORY_MIRROR variable, since an internal mirror is unreachable from GitHub-hosted runners. CircleCI's per-test timing and flaky-test detection have no equivalent; the JUnit XML and HTML reports are uploaded as run artifacts instead.
  • Concurrency. A newer push to a PR branch cancels the in-flight run. Runs on main are never cancelled, so a tag is never pushed without its release started.

Cutover steps (repository settings, outside this PR)

  1. Add repository secrets ORG_GRADLE_PROJECT_mavenCentralUsername, ORG_GRADLE_PROJECT_mavenCentralPassword, SIGNING_KEY, SIGNING_PASSWORD (Settings > Secrets and variables > Actions), with the values from the CircleCI context.
  2. Change the main ruleset's required status check from ci/circleci: jvm-build to jvm-build. Until this is done the PR cannot merge, since the CircleCI check will never report on it.
  3. After merge, disconnect the project in CircleCI and delete the write-access deploy key it used.

Testing

  • actionlint (with shellcheck) passes on all three workflows.
  • bash -n scripts/publish-web.sh passes; only its header comments changed.
  • scripts/next-version.sh was run locally on this branch: exits 3 (nothing releasable) as expected for a ci: commit.
  • The build workflow ran on this PR: run 35020678764 is green across all four Jackson legs, format-check, examples (all five projects including both Docker smoke tests), web-build and the jvm-build fan-in. Wall clock about 22 minutes; the JVM legs take about 5 minutes each in parallel, examples about 4 minutes after them.
  • One leg (Jackson 2.22.2) failed on the first attempt in SqliteWorkflowIntegTest > testReplaySignal_reusesSameRowAndDoesNotDuplicate with an OptimisticLockingError at the replaySignal call; the other three legs passed on identical bytecode and the re-run passed. That is a pre-existing race in the test (it replays before the engine has finished writing the first signal), tracked separately, not a CI change.
  • web-publish, tag-release and release.yml only run on main or a tag, so they are verified on the first merge and first release. The four release secrets are already set.

@rgamba
rgamba force-pushed the claude/circleci-github-actions-migration-bd642e branch from 96ae702 to add6fa3 Compare September 15, 2026 19:43
Replaces .circleci/config.yml with three workflows that reproduce the same
pipeline: build.yml (Jackson matrix, format-check, examples, the jvm-build
fan-in, web-build, and on main web-publish and tag-release), release.yml
(tag-triggered test-then-publish to Maven Central) and a reusable
jvm-build.yml shared by both so the release cannot drift from what pull
requests were tested with.

Differences forced by the platform: the deploy key is replaced by the run's
GITHUB_TOKEN for the gh-pages push and the tag push; because a GITHUB_TOKEN
push starts no workflow, tag-release dispatches release.yml on the tag
explicitly (a hand-pushed tag still arrives through `push`). The
skipper-publish CircleCI context becomes a GitHub environment of the same
name with the same four secrets. The examples job depends on the whole
Jackson matrix rather than the 2.9.10 entry alone, since a job cannot depend
on a single matrix leg. Test results and reports are run artifacts, since
Actions has no store_test_results.
@rgamba
rgamba force-pushed the claude/circleci-github-actions-migration-bd642e branch from add6fa3 to 147ff2e Compare September 15, 2026 20:03
…ronment

GitHub Environments are not available on this repository, so publish-release
reads the four secrets directly. Same names as the CircleCI context.
@rgamba
rgamba marked this pull request as ready for review September 15, 2026 21:00
@rgamba
rgamba merged commit 04729dd into main Sep 15, 2026
19 of 21 checks passed
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.

1 participant