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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions