Sync upstream stable #52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sync upstream stable | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "17 */6 * * *" | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| env: | |
| UPSTREAM_REPO: pingdotgg/t3code | |
| STABLE_BRANCH: stable | |
| PLUS_BRANCH: plus | |
| BUMP_PREFIX: version-bump/ | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout fork | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Configure Git | |
| run: | | |
| git config user.name "T3 Code Plus Bot" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Get latest upstream stable release | |
| id: release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG=$(gh api "repos/${UPSTREAM_REPO}/releases/latest" --jq '.tag_name') | |
| if [ -z "$TAG" ]; then | |
| echo "Could not determine latest upstream release." | |
| exit 1 | |
| fi | |
| echo "Latest upstream stable release: $TAG" | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| - name: Fetch latest upstream release | |
| run: | | |
| TAG="${{ steps.release.outputs.tag }}" | |
| git remote add upstream "https://github.com/${UPSTREAM_REPO}.git" || true | |
| # Fetch only the release tag we actually care about. | |
| git fetch upstream \ | |
| "refs/tags/$TAG:refs/tags/$TAG" \ | |
| --force | |
| - name: Determine release state | |
| id: state | |
| run: | | |
| TAG="${{ steps.release.outputs.tag }}" | |
| RELEASE_SHA=$(git rev-list -n 1 "$TAG") | |
| CURRENT_STABLE=$(git ls-remote origin \ | |
| "refs/heads/${STABLE_BRANCH}" | cut -f1) | |
| BUMP_BRANCH="${BUMP_PREFIX}${TAG}" | |
| echo "Release tag: $TAG" | |
| echo "Release SHA: $RELEASE_SHA" | |
| echo "Current stable: ${CURRENT_STABLE:-<missing>}" | |
| echo "Bump branch: $BUMP_BRANCH" | |
| echo "release_sha=$RELEASE_SHA" >> "$GITHUB_OUTPUT" | |
| echo "bump_branch=$BUMP_BRANCH" >> "$GITHUB_OUTPUT" | |
| if [ "$CURRENT_STABLE" = "$RELEASE_SHA" ]; then | |
| echo "new_release=false" >> "$GITHUB_OUTPUT" | |
| echo "Stable is already on $TAG." | |
| else | |
| echo "new_release=true" >> "$GITHUB_OUTPUT" | |
| echo "New stable release detected." | |
| fi | |
| # Always clean up PRs for older upstream releases. | |
| - name: Close stale version bump PRs | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| CURRENT_BRANCH="${{ steps.state.outputs.bump_branch }}" | |
| gh pr list \ | |
| --state open \ | |
| --base "$PLUS_BRANCH" \ | |
| --json number,headRefName \ | |
| --jq '.[] | select(.headRefName | startswith("'"$BUMP_PREFIX"'")) | "\(.number) \(.headRefName)"' \ | |
| | while read -r PR_NUMBER HEAD_BRANCH; do | |
| if [ "$HEAD_BRANCH" != "$CURRENT_BRANCH" ]; then | |
| echo "Closing stale PR #$PR_NUMBER ($HEAD_BRANCH)" | |
| gh pr comment "$PR_NUMBER" \ | |
| --body "Closing automatically because a newer upstream stable release is available." | |
| gh pr close "$PR_NUMBER" \ | |
| --delete-branch | |
| fi | |
| done | |
| # If this is genuinely a new release, move stable. | |
| - name: Update stable branch | |
| if: steps.state.outputs.new_release == 'true' | |
| run: | | |
| RELEASE_SHA="${{ steps.state.outputs.release_sha }}" | |
| echo "Moving ${STABLE_BRANCH} to $RELEASE_SHA" | |
| git push origin \ | |
| "$RELEASE_SHA:refs/heads/${STABLE_BRANCH}" \ | |
| --force | |
| # Check whether a PR for the CURRENT release is already open. | |
| - name: Find existing version bump PR | |
| id: existing_pr | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| BUMP_BRANCH="${{ steps.state.outputs.bump_branch }}" | |
| PR_NUMBER=$(gh pr list \ | |
| --state open \ | |
| --base "$PLUS_BRANCH" \ | |
| --head "$BUMP_BRANCH" \ | |
| --json number \ | |
| --jq '.[0].number // empty') | |
| echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | |
| if [ -n "$PR_NUMBER" ]; then | |
| echo "Existing PR: #$PR_NUMBER" | |
| echo "exists=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "No existing PR for current release." | |
| echo "exists=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| # Only create a bump branch for an ACTUAL new release. | |
| - name: Create version bump branch | |
| if: steps.state.outputs.new_release == 'true' | |
| run: | | |
| RELEASE_SHA="${{ steps.state.outputs.release_sha }}" | |
| BUMP_BRANCH="${{ steps.state.outputs.bump_branch }}" | |
| echo "Creating $BUMP_BRANCH at $RELEASE_SHA" | |
| git push origin \ | |
| "$RELEASE_SHA:refs/heads/$BUMP_BRANCH" \ | |
| --force | |
| # Only create a PR when: | |
| # - this is a new release | |
| # - and one doesn't already exist | |
| - name: Create version bump PR | |
| if: > | |
| steps.state.outputs.new_release == 'true' && | |
| steps.existing_pr.outputs.exists == 'false' | |
| id: create_pr | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ steps.release.outputs.tag }}" | |
| BUMP_BRANCH="${{ steps.state.outputs.bump_branch }}" | |
| PR_URL=$(gh pr create \ | |
| --base "$PLUS_BRANCH" \ | |
| --head "$BUMP_BRANCH" \ | |
| --title "chore: update upstream to $TAG" \ | |
| --body "## Upstream version update | |
| Updates **T3 Code Plus** to upstream stable release **$TAG**. | |
| - Upstream: \`$UPSTREAM_REPO\` | |
| - Stable tag: \`$TAG\` | |
| - Stable branch: \`$STABLE_BRANCH\` | |
| - Target branch: \`$PLUS_BRANCH\` | |
| This PR was created automatically. | |
| If it can be merged cleanly, the workflow will merge it automatically. | |
| If there is a merge conflict or another merge failure, this PR will remain open for manual resolution.") | |
| PR_NUMBER=$(gh pr view "$PR_URL" \ | |
| --json number \ | |
| --jq '.number') | |
| echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | |
| # Pick either: | |
| # - the already-open PR | |
| # - or the newly-created PR | |
| - name: Resolve current PR | |
| id: current_pr | |
| run: | | |
| EXISTING="${{ steps.existing_pr.outputs.number }}" | |
| CREATED="${{ steps.create_pr.outputs.number }}" | |
| if [ -n "$EXISTING" ]; then | |
| PR_NUMBER="$EXISTING" | |
| elif [ -n "$CREATED" ]; then | |
| PR_NUMBER="$CREATED" | |
| else | |
| PR_NUMBER="" | |
| fi | |
| echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | |
| if [ -n "$PR_NUMBER" ]; then | |
| echo "Current version bump PR: #$PR_NUMBER" | |
| echo "exists=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "There is no version bump PR to process." | |
| echo "exists=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check PR mergeability | |
| if: steps.current_pr.outputs.exists == 'true' | |
| id: mergeability | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| PR_NUMBER="${{ steps.current_pr.outputs.number }}" | |
| MERGEABLE="UNKNOWN" | |
| for i in {1..10}; do | |
| MERGEABLE=$(gh pr view "$PR_NUMBER" \ | |
| --json mergeable \ | |
| --jq '.mergeable') | |
| echo "Mergeability: $MERGEABLE" | |
| if [ "$MERGEABLE" != "UNKNOWN" ]; then | |
| break | |
| fi | |
| sleep 3 | |
| done | |
| echo "mergeable=$MERGEABLE" >> "$GITHUB_OUTPUT" | |
| - name: Merge clean version bump | |
| if: > | |
| steps.current_pr.outputs.exists == 'true' && | |
| steps.mergeability.outputs.mergeable == 'MERGEABLE' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| PR_NUMBER="${{ steps.current_pr.outputs.number }}" | |
| echo "PR #$PR_NUMBER is mergeable." | |
| if gh pr merge "$PR_NUMBER" \ | |
| --merge \ | |
| --delete-branch; then | |
| echo "Version bump merged successfully." | |
| else | |
| echo "Automatic merge failed." | |
| echo "Leaving PR #$PR_NUMBER open." | |
| fi | |
| - name: Report unresolved version bump | |
| if: > | |
| steps.current_pr.outputs.exists == 'true' && | |
| steps.mergeability.outputs.mergeable != 'MERGEABLE' | |
| run: | | |
| echo "Version bump PR #${{ steps.current_pr.outputs.number }} could not be merged automatically." | |
| echo "Leaving the PR open for manual resolution." | |
| - name: Nothing to do | |
| if: > | |
| steps.state.outputs.new_release == 'false' && | |
| steps.current_pr.outputs.exists == 'false' | |
| run: | | |
| echo "Stable already matches the latest upstream release." | |
| echo "There is no pending version bump PR." | |
| echo "Nothing to do." |