Skip to content

Squash-merged release PRs hide issue identifiers present in the commit body #147

Description

@petergrau

Summary

We run two continuous pipelines (staging + production) via linear-release-action. Most
releases end up with zero linked issues, although the identifiers are in the commit
message — one line below where the CLI looks. Both detectors needed already exist; they
are scoped to the subject line only.

Our release process

  • Feature branches are squash-merged into an integration branch. Subjects carry the
    identifier, e.g. ENG-123 fix: <title> (#12).
  • Periodically the integration branch is squash-merged into main as a single release PR,
    producing one commit with the subject Release (#99).
  • Staging deploys from main; the scanned HEAD is that squash commit.
  • Production is cut from a GitHub release. By the time the release job runs, HEAD is an
    automated bump version to <x> [skip ci] commit created by our build.
  • The repo uses GitHub's defaults, including squash_merge_commit_message: COMMIT_MESSAGES.

Where it breaks

Staging — correct range, nothing linked:

Found 2 commits between <sha> and <sha>
Synced to release <name>: pull requests [#99], links [CI]

#99 is the release PR. No issues are linked to it, so the PR reference resolves to
nothing and the dozens of squashed commits stay invisible.

Production — HEAD is the version bump:

Inspected current commit <sha>; found 1 commit
Synced to release <name>: no new issues or pull requests, links [...]

The data is already in the message

With GitHub's default squash message, the body is a list of the original subjects:

* ENG-123 fix: <title> (#12)
* ENG-124 feat: <title> (#13)

Each line carries both signals the CLI already understands: an identifier in the
ENG-123 subject form matched by COMMON_SUBJECT_PATTERNS, and a trailing (#N) matched
by the GitHub squash regex — and those PRs are linked to the issues. Both are dropped
because these detectors run against getCommitSubject(message).

We understand the reasoning behind the subject-only scoping and stripSquashBlock():
avoiding attribution of already-shipped work. Worth noting for the GitHub squash case
specifically — the body lists only commits unique to the head branch, i.e. exactly the new
work in that release.

What we had to build

Two workarounds we would happily delete:

  1. A script deriving the previous GitHub release tag via API and passing it as base_ref,
    so a production release scans a real range instead of a single version-bump commit.
  2. A shim that parses identifiers out of commit bodies and creates throwaway local branches
    named after them, pointing at those commits, purely to trigger branch-ref detection.
    This is a hack against an implementation detail and not something users should need.

What would make the stock action work for us

  1. Opt-in body scanning for squash commits, e.g. --scan-squash-body: run
    COMMON_SUBJECT_PATTERNS and (#N) extraction per body line. For us, either one alone
    would resolve every missing issue. A smaller variant that would also unblock us: let
    --issue-pattern target the full message, e.g. --issue-pattern-scope=subject|message.
    Today it is documented as subject-only, so it cannot reach this data.
  2. A first-class scan base for release-event pipelines, e.g.
    base_ref: previous-release-tag. base_ref already exists and works well — the gap is
    that every "GitHub release publishes production" setup has to script the same lookup,
    and without it the first sync degrades to HEAD only.
  3. Alternative to (1): resolve issues from the PRs contained in an already-detected
    release PR, server-side, without any commit message parsing.

Environment

  • linear/linear-release-action pinned to v0.17.2, CLI v0.17.2
  • GitHub Actions, ubuntu-24.04, actions/checkout@v4 with fetch-depth: 0
  • Two continuous pipelines, GitHub provider

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions