Skip to content

Implement ADR 0002: trunk-based automated release process #21597

Description

@screendriver

Context

ADR 0002 defines the target release process for wire-webapp:

  • main becomes the trunk branch.
  • Every merge to main deploys to Edge.
  • Release branches use release/YYYY-MM-DD.N.
  • Release branch updates deploy to Beta.
  • Successful Beta deployments create YYYY-MM-DD.N-beta.M tags.
  • Production waits for GitHub Environment approval.
  • Production promotes the Beta-tested artifact and does not rebuild from source.
  • Successful Production deployments create YYYY-MM-DD.N-production tags.
  • Production tags are immutable release history.
  • Rollback is handled by a dedicated GitHub Actions workflow.
  • On-premises maintenance releases are handled separately from the normal cloud release flow.

ADR:

docs/decision-records/0002-trunk-based-automated-release-process.md

Goal

Implement ADR 0002 in small, reviewable, low-risk steps.

The final release process should be GitHub-driven, auditable, and safe:

  • build once
  • deploy to Beta
  • validate on Beta
  • approve Production through GitHub Environment approval
  • promote the same artifact to Production
  • create the Production tag only after successful Production deployment
  • keep rollback explicit and auditable

Non-goals for the first phase

The first phase should not try to do everything at once.

Out of scope initially:

  • Deleting dev.
  • Deleting or renaming master.
  • Removing all old release triggers immediately.
  • Full on-premises maintenance release automation.
  • Perfect durable artifact storage for rollback.
  • Full feature flag governance automation.
  • Large workflow rewrites without intermediate compatibility.

Progress checklist

  • Inspect the current release implementation.
  • Add release metadata helpers.
  • Prepare reusable E2E / Testiny support.
  • Add Edge deployment from trunk.
  • Add release branch to Beta workflow.
  • Add Production approval and artifact promotion.
  • Add release branch creation workflow.
  • Add first-class Production rollback workflow.
  • Cut over branch model from dev / master to main.
  • Retire old tag-driven release path.
  • Add maintenance release automation separately.

Phase 1: Inspect the current release implementation

Create an implementation inventory before changing code.

The inventory should cover:

  • existing workflows for build, deploy, release, E2E, rollback, Docker, Helm, and notifications
  • existing scripts for release tagging and changelog generation
  • current branch assumptions
  • current tag assumptions
  • current deployment targets and environment names
  • Testiny integration
  • Wire / Deployoholics notification integration
  • conflicts between the current implementation and ADR 0002
  • a proposed PR sequence with small, reviewable steps

Acceptance criteria:

  • No files are changed.
  • No branch is created.
  • No PR is opened.
  • The current implementation is documented well enough to plan the first implementation PR.

Phase 2: Add release metadata helpers

Add small deterministic helpers for release metadata.

Required behavior:

  • validate release branch names matching release/YYYY-MM-DD.N
  • extract the release identifier YYYY-MM-DD.N
  • compute the next Beta tag from existing tags matching YYYY-MM-DD.N-beta.M
  • compute the Production tag YYYY-MM-DD.N-production
  • detect whether the Production tag already exists
  • detect whether an existing Production tag points to the current release commit
  • never move, delete, or force-push tags
  • add tests for the pure release metadata logic

Acceptance criteria:

  • Release naming rules are test-covered.
  • Tag selection behavior is deterministic.
  • No workflow behavior changes yet.

Phase 3: Prepare reusable E2E / Testiny support

Prepare .github/workflows/e2e-tests.yml so it can be called by the future release workflow.

Required behavior:

  • support testinyRunName through workflow_call
  • support TESTINY_API_KEY through workflow_call secrets
  • keep existing manual dispatch behavior unchanged
  • keep Playwright sharding and report generation unchanged

Acceptance criteria:

  • A caller workflow can run E2E against a provided webapp URL.
  • A caller workflow can upload the result to a named Testiny run.
  • Existing manual E2E usage still works.

Phase 4: Add Edge deployment from trunk

Add a dedicated Edge deployment workflow.

Required behavior:

  • trigger on pushes to main
  • during transition, support the current branch setup only if needed
  • build/package the webapp
  • deploy to Edge
  • do not require GitHub Environment approval
  • use concurrency so superseded Edge runs can be cancelled

Acceptance criteria:

  • Edge follows trunk.
  • Edge deployment is separate from the old release/tag-driven Production flow.
  • Existing Production release behavior is not changed in this phase.

Phase 5: Add release branch to Beta workflow

Add the first version of the cloud release workflow.

Required behavior:

  • trigger on pushes to release/**
  • validate the branch name as release/YYYY-MM-DD.N
  • build the release artifact once
  • deploy the artifact to Beta
  • create YYYY-MM-DD.N-beta.M only after successful Beta deployment
  • fetch tags before computing the next Beta tag
  • fail if a concurrent workflow created the same Beta tag
  • never force-push tags
  • run E2E against Beta
  • report E2E results to Testiny
  • add a GitHub step summary with release identifier, commit SHA, artifact checksum, Beta tag, Beta URL, E2E result, and Testiny run name
  • notify the release channel / Deployoholics on failure

Acceptance criteria:

  • Pushing to a valid release branch automatically deploys Beta.
  • Beta tags are created only after successful Beta deployment.
  • E2E and Testiny are part of the release branch workflow.
  • No Production deployment is added yet.

Phase 6: Add Production approval and promotion

Extend the release workflow with the Production part.

Required behavior:

  • Production waits for GitHub Environment approval.
  • Production deploys the same artifact that was deployed to Beta.
  • Production does not rebuild from source.
  • Production deployment is serialized across the repository.
  • Production deployments are not cancelled automatically.
  • Before deploying, check whether YYYY-MM-DD.N-production already exists.
  • If the Production tag already points to the same commit, skip redeployment.
  • If the Production tag exists and points to a different commit, fail.
  • Create YYYY-MM-DD.N-production only after successful Production deployment.
  • Never move, delete, or force-push Production tags.
  • Notify the release channel / Deployoholics on failure.

Acceptance criteria:

  • Beta-tested artifact is promoted to Production.
  • Production tag represents a successful Production deployment.
  • Existing Production tags remain immutable.
  • Re-running the workflow does not redeploy a commit that already has the matching Production tag.

Phase 7: Add release branch creation workflow

Add a manual workflow for creating release branches from GitHub Actions.

Required behavior:

  • use workflow_dispatch
  • input: release_identifier in format YYYY-MM-DD.N
  • input: source_ref, defaulting to main
  • input: confirmation boolean
  • create release/YYYY-MM-DD.N
  • fail if the branch already exists
  • do not create tags
  • do not deploy directly; the pushed branch should trigger the release workflow

Acceptance criteria:

  • Release branches can be created without local machine release operations.
  • Branch creation is auditable in GitHub Actions.

Phase 8: Add first-class rollback workflow

Add or adapt a dedicated Production rollback workflow.

Required behavior:

  • use workflow_dispatch
  • input: previous known-good Production tag
  • input: rollback reason
  • input: optional incident reference
  • input: confirmation boolean
  • validate the tag exists
  • deploy to Production through GitHub Actions
  • use the Production GitHub Environment
  • serialize against other Production deployments
  • notify the release channel / Deployoholics
  • do not create, move, delete, or rewrite release tags

Acceptance criteria:

  • Rollback is explicit and auditable.
  • Rollback is owned by engineering release owners, not QA.
  • Runtime state is visible through GitHub deployment metadata, logs, and notifications.

Phase 9: Cut over branch model

After the new workflows are proven:

  • rename master to main
  • retire dev as a long-lived release branch
  • update branch protection rules
  • update GitHub workflow branch filters
  • update documentation
  • update external integrations
  • update any wire-builds mappings if still needed

Acceptance criteria:

  • main is the single trunk branch.
  • Edge follows main.
  • Release branches are cut from main.
  • dev and master no longer carry release meaning.

Phase 10: Retire old tag-driven release path

After the new release workflow is proven:

  • stop Production deployment from pre-created Production tags
  • deprecate or remove local release tagging commands
  • remove outdated staging / production release tag assumptions where no longer needed
  • keep compatibility only where explicitly required

Acceptance criteria:

  • Production tags are created after successful Production deployment.
  • Local machines are no longer required for normal release operations.
  • Old release paths cannot accidentally bypass the new process.

Phase 11: Add maintenance release automation separately

Add maintenance release automation only after the cloud release path is stable.

Required behavior:

  • create maintenance branches only when needed
  • use branch names like maintenance/<maintenance-line-key>
  • do not deploy maintenance branches to normal Beta or Production
  • validate maintenance artifacts through a dedicated maintenance path
  • create maintenance tags like <maintenance-line-key>-maintenance.X

Acceptance criteria:

  • On-premises maintenance releases are separate from cloud releases.
  • Normal cloud cadence is not constrained by maintenance lines.

Open questions

  • Which existing environment maps to ADR “Beta” during the transition?
  • Should wire-webapp-staging be renamed conceptually or physically?
  • Where should immutable release artifacts live long term?
  • Is GitHub Actions artifact retention sufficient for the first iteration?
  • Should Elastic Beanstalk application versions become the durable promotion unit?
  • What exact Testiny run naming convention should release workflows use?
  • Which GitHub Environment reviewers should approve Production?
  • Which Wire channel should receive release workflow failure and stalled approval notifications?
  • What is the planned date for master to main rename?
  • Which external integrations still depend on dev or master?
  • Which parts of wire-builds still need updates from the webapp release workflow?

Risks

  • Accidentally keeping both old and new Production paths active.
  • Creating Production tags before deployment instead of after deployment.
  • Rebuilding for Production and invalidating Beta validation.
  • Cancelling an in-progress Production deployment.
  • Losing rollback ability because the artifact is not durable enough.
  • Blocking release migration on branch renaming too early.
  • Mixing maintenance release automation into the cloud release workflow.

Suggested first PR

Start with release metadata helpers and tests.

This should not change any workflow behavior.

Suggested scope:

  • validate release/YYYY-MM-DD.N
  • extract release identifier
  • compute next Beta tag
  • compute Production tag
  • detect existing Production tag behavior
  • add tests
  • no GitHub Actions changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions