Files
2026-05-23 15:11:48 +09:00

20 KiB

Ta4j Release Process

This document is the operator guide for shipping ta4j releases safely and repeatedly.

Default branch: master

Core release invariant:

  • the release tag must point to the intended release commit
  • that release commit must be reachable from master

1. At a Glance

Preferred path (PR mode):

  1. Scheduler (release-scheduler.yml) builds a release dossier, validates the configured GitHub Models catalog entry, asks the model for a SemVer decision, and dispatches prepare when appropriate.
  2. Prepare release (prepare-release.yml) creates release + next-snapshot commits on release/<version>.
  3. Maintainer reviews and merges release PR into master using a merge commit.
  4. Publish release (publish-release.yml) validates metadata/ancestry, runs the release-candidate gate, validates the artifact manifest, tags, deploys to Maven Central, pushes tag, and explicitly dispatches snapshot publication.
  5. GitHub release (github-release.yml) runs on tag push.
  6. Release health (release-health.yml) audits drift, verifies the current snapshot version is published once snapshot publication is authoritative, and posts summary.

Emergency path (direct push mode):

  1. prepare-release.yml pushes both commits directly to master when RELEASE_DIRECT_PUSH=true.
  2. It then dispatches publish-release.yml.

Validation path (dry run):

  1. Manually run any mutating release workflow and keep its default dryRun=true.
  2. Inspect the computed release/tag/snapshot values, workflow summary, and audit artifacts.
  3. Rerun manually with dryRun=false only when intentionally mutating, or let the scheduled/push/merge release path run with its explicit dryRun=false.
  4. Prepare dry-runs still run the read-only release-ready and next-cycle deprecation scans and upload their reports.
  5. No release commits, managed cleanup issue mutations, branch/tag push, Maven Central deploy, GitHub Release creation, snapshot deploy, or discussion/comment mutation occur.

2. Release Modes

Mode How it starts Git changes Tag/deploy Typical use
PR mode (default) scheduler or manual prepare release branch + merged PR yes normal production releases
Direct push manual prepare + RELEASE_DIRECT_PUSH=true commits land directly on master yes emergency/unblocked maintenance
Dry run manual mutating release workflow, default dryRun=true none no inspection-first preflight validation

3. Preconditions (Do This Before Releasing)

Code and docs:

  1. Update CHANGELOG.md under Unreleased.
  2. Keep README version references current.
  3. Run scripts/docs-integrity-check.sh and resolve failures before preparing a release.
    • This gate verifies canonical docs presence, link validity, command references, and TODO-free user-facing entry docs.
  4. Ensure release notes can be generated cleanly (release/<version>.md).
  5. Confirm release PRs are visible to release owner:
    • release PR must be labeled release.
    • release PR is auto-assigned to TheCookieLab.
    • TheCookieLab is auto-requested as reviewer.
  6. While any labeled release PR is open, only that release PR can be merged.
  7. Open PRs will receive an automatic release-freeze notice comment while the freeze is active. The workflow removes that notice once no release PR remains open.

Repository settings:

  1. Actions workflow permissions must allow write operations (dispatch, PR updates, tag push).
  2. Use merge-commit discipline for release PRs (no squash/rebase for those PRs).
  3. Add Release Merge Freeze as a required status check on master in branch protection.

Secrets and variables:

  1. Required secrets for publish/snapshot must be configured.
  2. Scheduler-related variables must be set intentionally (especially RELEASE_SCHEDULER_ENABLED).

4. Production Runbook (PR Mode)

  1. Trigger Prepare Release
  • Via scheduler or manual workflow_dispatch.
  • Inputs: releaseVersion (optional if auto-detected), nextVersion (optional), dryRun.
  • Manual runs default dryRun=true. Set dryRun=false only for an intentional mutating run after reviewing a dry-run. Scheduled release automation dispatches prepare with explicit dryRun=false.
  • For scheduled production runs, confirm release-scheduler.yml logs audit:dry_run_normalized=false and audit:dispatch_workflow workflow=prepare-release.yml ... dryRun=false, then confirm prepare-release.yml logs audit:dry_run_input_raw='false' and audit:dry_run_normalized=false.
  • If nextVersion is omitted and releaseVersion is a plain X.Y.Z, it is auto-generated as <major>.<minor>.<patch+1>-SNAPSHOT (for example 0.22.2 -> 0.22.3-SNAPSHOT).
  • For RC/non-plain release versions, provide nextVersion explicitly.
  • Before the workflow commits the next snapshot version, it runs the Java-based ta4jexamples.doc.RemovalReadyDeprecationScanner against the release version and fails if any @Deprecated(forRemoval = true) symbols are due or overdue for removal. This read-only scan also runs in dry-run mode.
  • After the next snapshot version is known, it scans sources scheduled for that planned snapshot or any earlier removal version because ta4j versions may jump across major, minor, or patch positions. Non-dry-run runs then sync deduplicated GitHub cleanup issues, including reopening still-valid managed issues and closing stale managed issues for the same removal version; dry-runs only upload the scan report.
  • The workflow uploads release-gate and next-snapshot removal-ready deprecation report artifacts with grouped findings, symbols, lifecycle status, replacement hints when available, and synced issue links when issue sync runs.
  • The scanner JSON is the stable handoff contract for future automation: it includes schemaVersion, automationNamespace, grouped issue planKind, and per-symbol trackingKey fields so a later AI-driven planner can split work into one issue per deprecated item while remaining restart-safe by searching managed markers before mutation.
  • The workflow auto-labels the PR with release, assigns it to TheCookieLab, and requests review from TheCookieLab.
  • In PR mode, the successful handoff is the release branch push plus release PR creation. In direct-push mode, the successful handoff is prepare-release.yml dispatching publish-release.yml with dryRun=false.
  • Opening a release PR automatically triggers freeze notices on other open PRs.
  1. Review generated release PR
  • Confirm release commit + next snapshot commit are present.
  • Confirm release notes file exists (release/<version>.md).
  • Confirm docs delta is complete for changed APIs/examples (README/wiki/examples index/changelog consistency).
  • Confirm canonical documentation artifacts are present and linked (Home, Getting-started, journey/runbook/checklist/troubleshooting, decision matrix, migration map, expected outputs, performance characterization).
  • If a release PR is open, wait for it to merge before merging any non-release PRs to master.
  1. Merge release PR to master
  • Use a merge commit.
  • Do not squash/rebase release PRs.
  • This merge is allowed because the Release Merge Freeze check allows only release PRs to merge during freeze.
  1. Observe Publish Release
  • Workflow validates release metadata and ancestry.
  • Creates annotated tag.
  • Deploys to Maven Central.
  • Pushes tag only after successful deploy.
  • Verifies pushed tag points to expected release commit and is reachable from default branch.
  1. Observe post-publish workflows
  • github-release.yml should run from tag push.
  • release-health.yml may first report snapshot publication as pending during the async handoff, then should report OK after snapshot.yml completes.

5. Dry-Run Runbook

Manual release workflows are inspection-first. release-scheduler.yml, prepare-release.yml, publish-release.yml, github-release.yml, snapshot.yml, and release-health.yml all default manual workflow_dispatch runs to dryRun=true.

Operator flow:

  1. Run the workflow manually and leave dryRun=true.
  2. Inspect the computed values in the workflow summary and audit artifacts: release version, next snapshot, tag, publish target, snapshot version, and planned mutation steps.
  3. If the computed values are correct and mutation is intended, rerun the same workflow with dryRun=false.
  4. If no manual mutation is needed, let the official scheduled, push, merge, tag-push, or workflow-run trigger continue; those paths normalize to dryRun=false.

Prepare dry-runs may leave releaseVersion and nextVersion blank where auto-detection is supported. Publish dry-runs require releaseVersion; releaseCommit remains optional and can be auto-detected.

Expected behavior:

  • dry-run can warn about missing deploy secrets/resources.
  • no managed cleanup issue sync, release PR creation, branch push, tag push, Maven Central deployment, GitHub Release creation, snapshot deployment, or discussion/comment mutation.
  • prepare dry-runs still run push capability probes with git push --dry-run.
  • prepare dry-runs run deprecation scans and upload report artifacts, but skip managed GitHub cleanup issue sync. If the release-ready gate finds due or overdue removals, the dry-run fails after the reports are available.
  • publish dry-runs run the same metadata, ancestry, release-candidate, and artifact manifest checks without deploying. If the release tag already exists, the dry-run records a warning and continues so historical release validation remains possible.
  • GitHub Release dry-runs build and validate the exact release artifact manifest from the selected tag while using workflow support files from the workflow commit.
  • release-candidate checks use the repository default integration,slow test-tag exclusions and log that policy in the workflow output.
  • workflows upload audit artifacts such as release dossiers, decisions, manifests, logs, and tag-resolution files so failures can be diagnosed from the exact phase that produced them.

6. Workflow Map (Trigger + Responsibility)

Workflow Trigger(s) Primary responsibility Critical guardrails
release-scheduler.yml schedule, manual decide whether/how to release manual runs default dry-run; schedule normalizes to production; binary-impact gate, model catalog preflight, release dossier, semver safety, tag collision checks
prepare-release.yml manual (or scheduler dispatch) generate release artifacts and release PR/direct-push commits manual runs default dry-run; scheduler passes dryRun; docs-integrity checks, version validation, metadata validation, dry-run push capability probes
publish-release.yml merged release PR close, manual release-candidate verification + tag + Maven Central deploy + snapshot dispatch + release summary manual runs default dry-run; merged release PRs normalize to production; merge discipline + ancestry checks, artifact manifest checks, post-push tag integrity/reachability checks
release-health.yml push to master, publish workflow completion, snapshot workflow completion, schedule, manual detect drift in release state manual runs default dry-run; non-manual triggers normalize to production; fails on tag reachability drift, snapshot version drift, missing snapshot publication once snapshot publication is authoritative, missing notes, stale release PRs
github-release.yml semver-like tag push, manual GitHub release publication manual runs default dry-run; tag pushes normalize to production; semver tag validation, exact artifact manifest using current workflow support files
snapshot.yml push to master, publish workflow dispatch, manual publish snapshots manual runs default dry-run; master pushes and publish handoff normalize to production; build/test/deploy prechecks and source-release audit fields

Tag metrics used by release automation:

  • latest tag: newest release tag by tag creation date, preferring bare numeric tags before v-prefixed tags.
  • last reachable tag: newest release tag merged into master; release-scheduler.yml uses this as its diff and version baseline.
  • last first-parent tag: nearest release tag visible on master's first-parent chain; informational only for diagnosing merge topology.
  • latest tag reachable: whether the newest release tag is an ancestor of master.

7. Verification Checklist (Post-Release)

  1. prepare-release.yml and publish-release.yml succeeded.
  2. Tag exists for released version.
  3. Tag reachability from master is true.
  4. Maven Central artifacts are visible (allow propagation time).
  5. GitHub release exists with expected notes/artifacts.
  6. Release-ready deprecation gate report exists for the released version and did not find due or overdue removals.
  7. Removal-ready deprecation report artifact exists for the new snapshot version, due or overdue removal versions were included, and any matching cleanup issues were created, refreshed, reopened, or closed as stale successfully.
  8. The chained snapshot.yml run succeeded for the next -SNAPSHOT version.
  9. master is on next -SNAPSHOT version.
  10. release-health.yml reports no drift and confirms the current snapshot version is published after snapshot.yml completes.

Quick checks:

git fetch origin --tags
VERSION=0.22.3

git rev-list -n 1 "refs/tags/${VERSION}"
git merge-base --is-ancestor "${VERSION}" origin/master && echo "reachable"

8. Troubleshooting

8.1 Publish succeeded, Health failed

Is this possible?

  • Yes. publish-release.yml and release-health.yml are separate workflows.

What should fail earlier now?

  • If the just-pushed tag is wrong/unreachable, publish should fail first due to post-push tag checks.

Why health can still fail afterward:

  • pom.xml snapshot not ahead of latest tag.
  • current snapshot version is missing from the Maven snapshot repository after snapshot publication becomes authoritative.
  • missing release/<version>.md for latest tag.
  • stale release PRs.
  • existing repository drift not introduced by this publish run.

Why a large last first-parent tag gap can still be healthy:

  • release PRs merge back to master with merge commits, so the tagged release commit often lives on the merge's second parent rather than the first-parent spine.
  • release-health.yml only fails when the newest release tag is not reachable from master; a lagging first-parent tag is diagnostic context, not drift by itself.

Remediation playbook:

  1. Open the failed release-health.yml run and read Drift reasons.
  2. Apply targeted fix:
    • latest tag not reachable from <branch>: make tagged commit reachable from master (typically a reachability merge commit; avoid retagging published releases).
    • pom.xml snapshot version not ahead of latest tag: bump master to next -SNAPSHOT.
    • current snapshot version not published to Maven snapshot repository: inspect the latest snapshot.yml run, fix the publication failure, and rerun health after the snapshot version appears in metadata.
    • missing release notes for latest tag: add release/<version>.md.
    • stale release PRs detected: merge or close stale release PRs.
  3. Re-run health via workflow_dispatch.
  4. If Maven deploy already succeeded, treat this as repo-state remediation, not republish.

8.2 Release PR waiting for merge

  • Ensure required checks pass.
  • Ensure required maintainer approval exists.
  • Merge with merge commit.

8.3 Tag exists error

  • Version already tagged.
  • Use a new version unless you have an explicit rollback/recovery plan.

8.4 Release notes missing

  • Ensure release/<version>.md exists in the release commit.

8.5 Branch advanced during prepare/push

  • master moved while workflow was preparing/pushing.
  • Re-run prepare once branch is stable.

8.6 Dry-run warnings

  • Missing deploy secrets in dry-run are expected warnings.
  • Fix before production run.

8.7 Finding the failure point

Release workflows use grouped log sections and upload audit artifacts on every run.

Look for these files first:

  • release-dossier.md: scheduler context sent to the model.
  • release-decision.json: normalized AI release decision.
  • release-audit.json: workflow-local release metadata.
  • tag-resolution.txt: resolved latest/reachable/first-parent tag state.
  • artifact-manifest.txt: exact jars expected for publish/GitHub Release.
  • javadoc-warnings.txt: Javadoc warning baseline comparison from release artifact/deploy logs; new warnings beyond the tracked scripts/release/javadoc-warning-baseline.txt debt fail publish.
  • .agents/logs/full-build-*.log: release-candidate full build log.

If a grouped section fails, inspect the matching artifact before rerunning. Avoid rerunning publish until tag state, artifact state, and Central deployment state are understood.


9. Discussion Posts (Markers and Cleanup)

Non-dry-run release-related workflows post to GitHub Discussions with machine-readable markers:

<!-- ta4j:post-type=<type>;run=<real|dry-run> -->

Post types:

  • release-scheduler
  • publish-release
  • release-health

Cleanup rules:

  • manual dry-runs do not create, update, or delete discussion comments; their dry-run details remain in workflow summaries and audit artifacts.
  • release-health: removes prior real health posts before posting the latest real summary.
  • release-scheduler: posts real scheduler summaries only.
  • publish-release: posts real publish summaries and keeps historical posts as an audit trail.

Do not key automation off author/body heuristics; key off marker metadata.


10. Required Resources

10.1 Required secrets

Secret Used by Purpose
MAVEN_CENTRAL_TOKEN_USER publish, snapshot Maven Central auth user/token
MAVEN_CENTRAL_TOKEN_PASS publish, snapshot Maven Central auth password/token
GPG_PRIVATE_KEY publish, snapshot artifact signing key
GPG_PASSPHRASE publish, snapshot signing key passphrase
GH_MODELS_TOKEN scheduler model API access
GH_TA4J_REPO_TOKEN prepare, publish, github-release PAT for release pushes/release creation

10.2 Optional secrets

Secret Used by Purpose
MAVEN_MASTER_PASSPHRASE publish, snapshot optional Maven settings-security

10.3 Variables

Variable Used by Purpose
RELEASE_DIRECT_PUSH prepare direct-push mode switch
RELEASE_NOTIFY_USER publish, scheduler, health discussion mention target
RELEASE_DISCUSSION_NUMBER publish publish summary discussion
RELEASE_SCHEDULER_DISCUSSION_NUMBER scheduler, health scheduler/health discussion
RELEASE_SCHEDULER_ENABLED scheduler enable scheduled release decisions
RELEASE_AI_MODEL scheduler GitHub Models model override; default should be openai/gpt-4.1
RELEASE_PR_STALE_DAYS health stale release PR threshold

10.4 Environment

Environment Purpose
major-release manual approval gate for major bumps
release-recovery manual approval gate for publish-release.yml recovery mode when an explicit release commit is not reachable from master

11. Repository Policy Notes

  1. Keep release tags reachable from master.
  2. Use merge commits for release PRs.
  3. Avoid force-retagging already-published versions.
  4. Prefer PR mode; use direct push only when justified.
  5. Keep RELEASE_DIRECT_PUSH=false for normal releases.
  6. Use recoveryMode=true only for manual publish recovery when the release commit is intentionally not reachable from master; this path is protected by the release-recovery environment.

12. Responsibilities Summary

Task Maintainer/manual GitHub Actions
maintain changelog/readme release readiness yes no
generate release notes yes (via prepare script/workflow) yes
set release version + next snapshot no yes
create/push release tag no yes (non-dry-run)
deploy to Maven Central no yes (non-dry-run)
publish GitHub release no yes (non-dry-run)
release drift auditing no yes

13. RC Builds

RC versions are supported if they are Maven-valid (for example 0.22.2-rc1). Use the same workflows and verification checklist.