From b87c163db8fed868a646f87b021f4fcee3235225 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:45:15 +0000 Subject: [PATCH 1/4] Initial plan From d7c585d1e79f0386535a90ce50af9dc21e3c023c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:47:33 +0000 Subject: [PATCH 2/4] feat: add automated patch upmerge workflow for issue #141 Co-authored-by: devlinjunker <1504590+devlinjunker@users.noreply.github.com> --- .github/workflows/patch-upmerge.yaml | 129 +++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 .github/workflows/patch-upmerge.yaml diff --git a/.github/workflows/patch-upmerge.yaml b/.github/workflows/patch-upmerge.yaml new file mode 100644 index 0000000..c615db5 --- /dev/null +++ b/.github/workflows/patch-upmerge.yaml @@ -0,0 +1,129 @@ +## This Action runs when a commit is made to a `release-*` branch +## - Detects if the current release branch is older than the most recent release +## - Creates PRs to upmerge the patch to the most recent release branch and main +## - Addresses issue #141: Merge older release patch to main + +name: "Patch-Upmerge" + +on: + push: + branches: + - release-* + +jobs: + check-and-create-upmerge-prs: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2.3.4 + with: + ## This is a Personal Access Token from Admin User that allows us to bypass branch protections + token: ${{ secrets.PAT }} + fetch-depth: 0 + + - name: "Get Current Release Version" + id: current_version + run: | + git fetch --all --tags; + CURRENT_BRANCH=${GITHUB_REF##*/} + echo "Current branch: $CURRENT_BRANCH" + + # Extract major.minor from release-X.Y branch name + if [[ $CURRENT_BRANCH =~ ^release-([0-9]+)\.([0-9]+)$ ]]; then + CURRENT_MAJOR="${BASH_REMATCH[1]}" + CURRENT_MINOR="${BASH_REMATCH[2]}" + echo "##[set-output name=major;]$CURRENT_MAJOR" + echo "##[set-output name=minor;]$CURRENT_MINOR" + echo "##[set-output name=version;]$CURRENT_MAJOR.$CURRENT_MINOR" + echo "##[set-output name=branch;]$CURRENT_BRANCH" + else + echo "::error::Invalid release branch format: $CURRENT_BRANCH" + exit 1 + fi + + - name: "Find Most Recent Release Branch" + id: latest_release + run: | + git fetch --all --tags; + + # Get the latest tag + LATEST_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1) + echo "Latest tag: $LATEST_TAG" + + if [ -z "$LATEST_TAG" ]; then + echo "No tags found" + echo "##[set-output name=is_latest;]true" + exit 0 + fi + + # Extract major.minor from tag (format: vX.Y.Z) + if [[ $LATEST_TAG =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + LATEST_MAJOR="${BASH_REMATCH[1]}" + LATEST_MINOR="${BASH_REMATCH[2]}" + LATEST_PATCH="${BASH_REMATCH[3]}" + LATEST_RELEASE_BRANCH="release-$LATEST_MAJOR.$LATEST_MINOR" + + echo "##[set-output name=major;]$LATEST_MAJOR" + echo "##[set-output name=minor;]$LATEST_MINOR" + echo "##[set-output name=patch;]$LATEST_PATCH" + echo "##[set-output name=branch;]$LATEST_RELEASE_BRANCH" + echo "##[set-output name=version;]$LATEST_MAJOR.$LATEST_MINOR" + + # Compare versions + CURRENT_MAJOR="${{ steps.current_version.outputs.major }}" + CURRENT_MINOR="${{ steps.current_version.outputs.minor }}" + + # Compare major.minor versions + if [ "$CURRENT_MAJOR" -gt "$LATEST_MAJOR" ]; then + echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is newer than latest ($LATEST_MAJOR.$LATEST_MINOR)" + echo "##[set-output name=is_latest;]true" + elif [ "$CURRENT_MAJOR" -eq "$LATEST_MAJOR" ] && [ "$CURRENT_MINOR" -ge "$LATEST_MINOR" ]; then + echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is the latest or newer" + echo "##[set-output name=is_latest;]true" + else + echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is older than latest ($LATEST_MAJOR.$LATEST_MINOR)" + echo "##[set-output name=is_latest;]false" + fi + fi + + - name: "Create PR to Latest Release Branch" + if: steps.latest_release.outputs.is_latest == 'false' + uses: repo-sync/pull-request@v2.6 + with: + github_token: ${{ secrets.PAT }} + source_branch: ${{ steps.current_version.outputs.branch }} + destination_branch: ${{ steps.latest_release.outputs.branch }} + pr_title: "Upmerge patch from ${{ steps.current_version.outputs.branch }} to ${{ steps.latest_release.outputs.branch }}" + pr_body: | + Automated upmerge of patch from older release branch. + + **Source:** `${{ steps.current_version.outputs.branch }}` + **Target:** `${{ steps.latest_release.outputs.branch }}` + + This PR ensures that patches to older releases are also applied to the most recent release. + + Please review for conflicts and merge manually. + + Related to issue #141 + pr_label: "- release -" + + - name: "Create PR to Main Branch" + if: steps.latest_release.outputs.is_latest == 'false' + uses: repo-sync/pull-request@v2.6 + with: + github_token: ${{ secrets.PAT }} + source_branch: ${{ steps.current_version.outputs.branch }} + destination_branch: "main" + pr_title: "Upmerge patch from ${{ steps.current_version.outputs.branch }} to main" + pr_body: | + Automated upmerge of patch from older release branch. + + **Source:** `${{ steps.current_version.outputs.branch }}` + **Target:** `main` + + This PR ensures that patches to older releases are also applied to main. + + Please review for conflicts and merge manually. + + Related to issue #141 + pr_label: "- release -" From 0acdcdcf207751b81912e3d4fafc8f04811bff52 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:54:33 +0000 Subject: [PATCH 3/4] fix: address code review feedback - update to GITHUB_OUTPUT, checkout v4, better version comparison Co-authored-by: devlinjunker <1504590+devlinjunker@users.noreply.github.com> --- .github/workflows/patch-upmerge.yaml | 48 +++++++++++++++++----------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/.github/workflows/patch-upmerge.yaml b/.github/workflows/patch-upmerge.yaml index c615db5..64ffa73 100644 --- a/.github/workflows/patch-upmerge.yaml +++ b/.github/workflows/patch-upmerge.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.3.4 + - uses: actions/checkout@v4 with: ## This is a Personal Access Token from Admin User that allows us to bypass branch protections token: ${{ secrets.PAT }} @@ -32,10 +32,10 @@ jobs: if [[ $CURRENT_BRANCH =~ ^release-([0-9]+)\.([0-9]+)$ ]]; then CURRENT_MAJOR="${BASH_REMATCH[1]}" CURRENT_MINOR="${BASH_REMATCH[2]}" - echo "##[set-output name=major;]$CURRENT_MAJOR" - echo "##[set-output name=minor;]$CURRENT_MINOR" - echo "##[set-output name=version;]$CURRENT_MAJOR.$CURRENT_MINOR" - echo "##[set-output name=branch;]$CURRENT_BRANCH" + echo "major=$CURRENT_MAJOR" >> $GITHUB_OUTPUT + echo "minor=$CURRENT_MINOR" >> $GITHUB_OUTPUT + echo "version=$CURRENT_MAJOR.$CURRENT_MINOR" >> $GITHUB_OUTPUT + echo "branch=$CURRENT_BRANCH" >> $GITHUB_OUTPUT else echo "::error::Invalid release branch format: $CURRENT_BRANCH" exit 1 @@ -44,15 +44,13 @@ jobs: - name: "Find Most Recent Release Branch" id: latest_release run: | - git fetch --all --tags; - # Get the latest tag LATEST_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1) echo "Latest tag: $LATEST_TAG" if [ -z "$LATEST_TAG" ]; then echo "No tags found" - echo "##[set-output name=is_latest;]true" + echo "is_latest=true" >> $GITHUB_OUTPUT exit 0 fi @@ -63,11 +61,11 @@ jobs: LATEST_PATCH="${BASH_REMATCH[3]}" LATEST_RELEASE_BRANCH="release-$LATEST_MAJOR.$LATEST_MINOR" - echo "##[set-output name=major;]$LATEST_MAJOR" - echo "##[set-output name=minor;]$LATEST_MINOR" - echo "##[set-output name=patch;]$LATEST_PATCH" - echo "##[set-output name=branch;]$LATEST_RELEASE_BRANCH" - echo "##[set-output name=version;]$LATEST_MAJOR.$LATEST_MINOR" + echo "major=$LATEST_MAJOR" >> $GITHUB_OUTPUT + echo "minor=$LATEST_MINOR" >> $GITHUB_OUTPUT + echo "patch=$LATEST_PATCH" >> $GITHUB_OUTPUT + echo "branch=$LATEST_RELEASE_BRANCH" >> $GITHUB_OUTPUT + echo "version=$LATEST_MAJOR.$LATEST_MINOR" >> $GITHUB_OUTPUT # Compare versions CURRENT_MAJOR="${{ steps.current_version.outputs.major }}" @@ -76,18 +74,30 @@ jobs: # Compare major.minor versions if [ "$CURRENT_MAJOR" -gt "$LATEST_MAJOR" ]; then echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is newer than latest ($LATEST_MAJOR.$LATEST_MINOR)" - echo "##[set-output name=is_latest;]true" - elif [ "$CURRENT_MAJOR" -eq "$LATEST_MAJOR" ] && [ "$CURRENT_MINOR" -ge "$LATEST_MINOR" ]; then - echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is the latest or newer" - echo "##[set-output name=is_latest;]true" + echo "is_latest=true" >> $GITHUB_OUTPUT + elif [ "$CURRENT_MAJOR" -eq "$LATEST_MAJOR" ] && [ "$CURRENT_MINOR" -gt "$LATEST_MINOR" ]; then + echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is newer than latest ($LATEST_MAJOR.$LATEST_MINOR)" + echo "is_latest=true" >> $GITHUB_OUTPUT + elif [ "$CURRENT_MAJOR" -eq "$LATEST_MAJOR" ] && [ "$CURRENT_MINOR" -eq "$LATEST_MINOR" ]; then + echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is the same as latest ($LATEST_MAJOR.$LATEST_MINOR)" + echo "is_latest=true" >> $GITHUB_OUTPUT else echo "Current release ($CURRENT_MAJOR.$CURRENT_MINOR) is older than latest ($LATEST_MAJOR.$LATEST_MINOR)" - echo "##[set-output name=is_latest;]false" + echo "is_latest=false" >> $GITHUB_OUTPUT + + # Check if latest release branch exists + if git show-ref --verify --quiet "refs/remotes/origin/$LATEST_RELEASE_BRANCH"; then + echo "branch_exists=true" >> $GITHUB_OUTPUT + echo "Latest release branch $LATEST_RELEASE_BRANCH exists" + else + echo "branch_exists=false" >> $GITHUB_OUTPUT + echo "::warning::Latest release branch $LATEST_RELEASE_BRANCH does not exist" + fi fi fi - name: "Create PR to Latest Release Branch" - if: steps.latest_release.outputs.is_latest == 'false' + if: steps.latest_release.outputs.is_latest == 'false' && steps.latest_release.outputs.branch_exists == 'true' uses: repo-sync/pull-request@v2.6 with: github_token: ${{ secrets.PAT }} From 3c4f6a85959c715e43d16a5cf85fad0cc33d34f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:00:32 +0000 Subject: [PATCH 4/4] fix: add explicit GITHUB_TOKEN permissions for security Co-authored-by: devlinjunker <1504590+devlinjunker@users.noreply.github.com> --- .github/workflows/patch-upmerge.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/patch-upmerge.yaml b/.github/workflows/patch-upmerge.yaml index 64ffa73..9826667 100644 --- a/.github/workflows/patch-upmerge.yaml +++ b/.github/workflows/patch-upmerge.yaml @@ -13,6 +13,10 @@ on: jobs: check-and-create-upmerge-prs: runs-on: ubuntu-latest + + permissions: + contents: read + pull-requests: write steps: - uses: actions/checkout@v4