Repository navigation
chore: detect vnext release merge by ancestry, not branch name #714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,11 @@ name: Rebase vnext onto main | |
| # Triggered on every push to main. Force-rebases vnext onto the new main HEAD | ||
| # using the overture-pull-requester GitHub App (which has branch-protection bypass). | ||
| # | ||
| # Skipped for vnext→main release merges — vnext is already equal to main at that | ||
| # point so a rebase would be a no-op, and the GitHub API check catches this. | ||
| # Skipped for a vnext release merge — detected by ancestry (origin/vnext is | ||
| # already an ancestor of the new main HEAD), not by branch name, so a staging | ||
| # branch built on top of vnext's tip (e.g. `2_0_0`) is skipped the same as a | ||
| # PR literally named `vnext`. vnext is already equal to main at that point so | ||
| # a rebase would be a no-op. | ||
| # | ||
| # If the rebase fails a GitHub issue is opened and assigned to the PR author | ||
| # so the conflict can be resolved manually. | ||
|
|
@@ -41,38 +44,41 @@ jobs: | |
| permission-pull-requests: read # read PR on merge commit to detect vnext→main release | ||
| permission-workflows: write # vnext commits may touch .github/workflows/** | ||
|
|
||
| # Detect whether this push was a vnext→main release merge. | ||
| # The GitHub API returns the PR(s) associated with the merge commit. | ||
| - name: Detect vnext→main release merge | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| fetch-depth: 0 | ||
| # Use the app token so the subsequent force-push is authenticated. | ||
| token: ${{ steps.app-token.outputs.token }} | ||
| persist-credentials: true | ||
|
|
||
| # Detect whether this push was a vnext release merge, by ancestry rather | ||
| # than branch name: if origin/vnext is already an ancestor of the new | ||
| # main HEAD, all of vnext's commits are in main and rebasing is a no-op. | ||
| # The GitHub API additionally returns the PR associated with the merge | ||
| # commit, so a failure issue can still be filed against its author. | ||
| - name: Detect vnext release merge | ||
| id: skip | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| MAIN_SHA: ${{ github.sha }} | ||
| run: | | ||
| git fetch origin vnext | ||
|
|
||
| PR_JSON=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${MAIN_SHA}/pulls" \ | ||
| --jq '.[0] // empty' 2>/dev/null || true) | ||
|
|
||
| HEAD_REF=$(echo "$PR_JSON" | jq -r '.head.ref // empty' 2>/dev/null || true) | ||
| PR_NUMBER=$(echo "$PR_JSON" | jq -r '.number // empty' 2>/dev/null || true) | ||
| PR_AUTHOR=$(echo "$PR_JSON" | jq -r '.user.login // empty' 2>/dev/null || true) | ||
|
|
||
| if [ "$HEAD_REF" = "vnext" ]; then | ||
| echo "Skipping: this is a vnext→main release merge." | ||
| if git merge-base --is-ancestor origin/vnext "$MAIN_SHA"; then | ||
| echo "::notice::Skipping rebase: origin/vnext is already an ancestor of main, this is a release merge." | ||
|
Comment on lines
+73
to
+74
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest we drop the I think it's probably wrong also, in that after this change, the rebase won't run on every merge to Basically on the old system if you pushed a commit In the new system if this happens, then And this would continue if you keep tacking on new commits If we just get rid of the skip and always run the fast-forward I think we get rid of this problem, yes? (Note: This is a Claude-detected bug but it makes sense to me when I play it through.) |
||
| echo "skip=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "skip=false" >> "$GITHUB_OUTPUT" | ||
| echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT" | ||
| echo "pr_author=${PR_AUTHOR}" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| if: steps.skip.outputs.skip != 'true' | ||
| with: | ||
| fetch-depth: 0 | ||
| # Use the app token so the subsequent force-push is authenticated. | ||
| token: ${{ steps.app-token.outputs.token }} | ||
| persist-credentials: true | ||
|
|
||
| - name: Rebase vnext onto new main HEAD | ||
| if: steps.skip.outputs.skip != 'true' | ||
| id: rebase | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,12 @@ name: vnext compatibility check | |
| # exact commands to resolve it. | ||
| # | ||
| # Only PRs targeting main do that real work — compat-check is a no-op for | ||
| # anything else (including vnext→main release PRs, head_ref == 'vnext'). The | ||
| # noop job covers that inverse case, and both paths feed vnext-status so | ||
| # there's always a single, consistently-named check to require. | ||
| # anything else, including a vnext release merge. A release merge is detected | ||
| # by ancestry (origin/vnext is an ancestor of the PR head), not by branch name, | ||
| # so a staging branch built on top of vnext's tip (e.g. `2_0_0`) is recognized | ||
| # the same as a PR literally named `vnext`. The noop job covers that inverse | ||
| # case, and both paths feed vnext-status so there's always a single, | ||
| # consistently-named check to require. | ||
|
|
||
| on: | ||
| pull_request: | ||
|
|
@@ -23,9 +26,45 @@ concurrency: | |
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| detect-release: | ||
| name: Detect vnext release merge | ||
| runs-on: ubuntu-slim | ||
| permissions: | ||
| contents: read | ||
| outputs: | ||
| is_release: ${{ steps.check.outputs.is_release }} | ||
| steps: | ||
| # Runs unconditionally so noop/compat-check (which `need` this job) never | ||
| # get skipped by dependency propagation for non-main bases; skip the | ||
| # actual check with a fast is_release=false instead. | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| if: github.event.pull_request.base.ref == 'main' | ||
| with: | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
| - name: Check whether origin/vnext is an ancestor of this PR's head | ||
| id: check | ||
| env: | ||
| PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||
| PR_BASE_REF: ${{ github.event.pull_request.base.ref }} | ||
| run: | | ||
| if [ "$PR_BASE_REF" != "main" ]; then | ||
| echo "is_release=false" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
|
|
||
| git fetch origin vnext | ||
| if git merge-base --is-ancestor origin/vnext "$PR_HEAD_SHA"; then | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [2/2] LLM overlord is reporting that |
||
| echo "is_release=true" >> "$GITHUB_OUTPUT" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same root cause as the comment on the skip issue, the My understanding of what we're trying to do here is that Current check is saying "if git fetch --no-tags origin \
'+refs/heads/main:refs/remotes/origin/main' \ # This +refs business is meant to ensure
'+refs/heads/vnext:refs/remotes/origin/vnext' # you can validly refer to `origin/vnext and origin/main`
if git merge-base --is-ancestor origin/vnext "$PR_HEAD_SHA" \
&& ! git merge-base --is-ancestor origin/vnext origin/main; then
echo "is_release=true" >> "$GITHUB_OUTPUT"
else
echo "is_release=false" >> "$GITHUB_OUTPUT"
fi |
||
| else | ||
| echo "is_release=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| compat-check: | ||
| name: Check vnext compatibility | ||
| if: github.event.pull_request.base.ref == 'main' && github.head_ref != 'vnext' | ||
| needs: detect-release | ||
| if: github.event.pull_request.base.ref == 'main' && needs.detect-release.outputs.is_release != 'true' | ||
| runs-on: ubuntu-slim | ||
| permissions: | ||
| contents: read | ||
|
|
@@ -160,10 +199,11 @@ jobs: | |
|
|
||
| noop: | ||
| name: Skip vnext compatibility check | ||
| if: github.event.pull_request.base.ref != 'main' || github.head_ref == 'vnext' | ||
| needs: detect-release | ||
| if: github.event.pull_request.base.ref != 'main' || needs.detect-release.outputs.is_release == 'true' | ||
| runs-on: ubuntu-slim | ||
| steps: | ||
| - run: echo "Base isn't main, or this is the vnext release PR — nothing to check here." | ||
| - run: echo "::notice::Base isn't main, or this is the vnext release merge — nothing to check here." | ||
|
|
||
| vnext-status: | ||
| name: vnext compatibility status | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am informed by my LLM overlords that this will fail open if The mechanism is apparently this dependency graph The claim is that GitHub action dependency propagation causes Can you double-check this? |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[1/2] LLM overlord is reporting that
origin/vnextmay not be populated aftergit fetch origin vnextdue to Git quirks. Apparently an alternative that is certain to work/can't break unexpectedly is to refer toFETCH_HEADinstead oforigin/vnext.