create-merge-from-previous-release-branch #1521
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: create-merge-from-previous-release-branch | |
| on: | |
| push: | |
| branches: ["release/*"] | |
| workflow_dispatch: | |
| permissions: {} | |
| jobs: | |
| setup: | |
| if: github.repository == 'opf/openproject' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| previous_release_branch: ${{ steps.find_release_branches.outputs.previous_branch }} | |
| latest_release_branch: ${{ steps.find_release_branches.outputs.latest_branch }} | |
| steps: | |
| - id: find_release_branches | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| run: | | |
| LATEST_BRANCHES=$(gh api --paginate \ | |
| "repos/$GITHUB_REPOSITORY/branches?protected=true&per_page=100" \ | |
| --jq '.[].name' | grep '^release/' | sort --version-sort | tail -2 | |
| ) | |
| LATEST_BRANCH=$(echo "$LATEST_BRANCHES" | tail -1) | |
| PREVIOUS_BRANCH=$(echo "$LATEST_BRANCHES" | head -1) | |
| if [ -z "$LATEST_BRANCH" ] || [ -z "$PREVIOUS_BRANCH" ]; then | |
| echo "Invalid release branches found: latest=$LATEST_BRANCH, previous=$PREVIOUS_BRANCH" | |
| exit 1 | |
| fi | |
| echo "Found previous release branch: $PREVIOUS_BRANCH" | |
| echo "previous_branch=${PREVIOUS_BRANCH}" >> $GITHUB_OUTPUT | |
| echo "Found latest release branch: $LATEST_BRANCH" | |
| echo "latest_branch=${LATEST_BRANCH}" >> $GITHUB_OUTPUT | |
| merge-or-create-pr: | |
| if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_name == needs.setup.outputs.previous_release_branch) | |
| env: | |
| RELEASE_BRANCH: ${{ needs.setup.outputs.latest_release_branch }} | |
| PREVIOUS_RELEASE_BRANCH: ${{ needs.setup.outputs.previous_release_branch }} | |
| permissions: | |
| contents: write # for git push | |
| pull-requests: write # for creating pull request | |
| runs-on: ubuntu-latest | |
| needs: setup | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| ref: ${{ env.RELEASE_BRANCH }} | |
| - name: Fetch both release branches with sufficient history | |
| run: | | |
| # Calculate a reasonable date to fetch from (e.g., 6 months ago) | |
| SINCE_DATE=$(date -d '3 months ago' '+%Y-%m-%d') | |
| echo "Fetching commits since: $SINCE_DATE" | |
| # Fetch both branches with commits since the calculated date | |
| git fetch --shallow-since="$SINCE_DATE" origin "$RELEASE_BRANCH" "$PREVIOUS_RELEASE_BRANCH" || { | |
| echo "Shallow-since fetch failed, trying with depth strategy..." | |
| # Fallback: Use progressive deepening | |
| git fetch --depth=50 origin "$RELEASE_BRANCH" "$PREVIOUS_RELEASE_BRANCH" | |
| for depth in 100 200 500 1000; do | |
| if git merge-base --is-ancestor "origin/$PREVIOUS_RELEASE_BRANCH" "origin/$RELEASE_BRANCH" 2>/dev/null || \ | |
| git merge-base --is-ancestor "origin/$RELEASE_BRANCH" "origin/$PREVIOUS_RELEASE_BRANCH" 2>/dev/null || \ | |
| git merge-base "origin/$RELEASE_BRANCH" "origin/$PREVIOUS_RELEASE_BRANCH" >/dev/null 2>&1; then | |
| echo "Found sufficient history at depth $depth" | |
| break | |
| fi | |
| echo "Deepening to $depth commits..." | |
| git fetch --deepen=$((depth-50)) origin "$RELEASE_BRANCH" "$PREVIOUS_RELEASE_BRANCH" || true | |
| done | |
| } | |
| - name: Resolve bug in git https://stackoverflow.com/a/63879454/96823 | |
| run: git repack -d | |
| - name: Verify we have sufficient history | |
| run: | | |
| echo "Checking if we can find merge-base between branches..." | |
| if git merge-base "origin/$RELEASE_BRANCH" "origin/$PREVIOUS_RELEASE_BRANCH" >/dev/null 2>&1; then | |
| MERGE_BASE=$(git merge-base "origin/$RELEASE_BRANCH" "origin/$PREVIOUS_RELEASE_BRANCH") | |
| echo "✅ Found merge-base: $MERGE_BASE" | |
| else | |
| echo "⚠️ Could not find merge-base, operations may be limited" | |
| fi | |
| echo "Branch $RELEASE_BRANCH has $(git rev-list --count origin/$RELEASE_BRANCH) commits" | |
| echo "Branch $PREVIOUS_RELEASE_BRANCH has $(git rev-list --count origin/$PREVIOUS_RELEASE_BRANCH) commits" | |
| - name: Create local tracking branches | |
| run: | | |
| git branch "$PREVIOUS_RELEASE_BRANCH" "origin/$PREVIOUS_RELEASE_BRANCH" || true | |
| git branch "$RELEASE_BRANCH" "origin/$RELEASE_BRANCH" || true | |
| - name: Required git config | |
| run: | | |
| git config user.name "OpenProject Actions CI" | |
| git config user.email "operations+ci@openproject.com" | |
| - name: Show diff | |
| run: git diff ..."$PREVIOUS_RELEASE_BRANCH" | |
| - name: Try merging or create a PR | |
| run: | | |
| if git diff --exit-code --quiet ..."$PREVIOUS_RELEASE_BRANCH"; then | |
| echo "Nothing to merge from $PREVIOUS_RELEASE_BRANCH into $RELEASE_BRANCH" | |
| else | |
| if git merge --no-edit --no-ff "$PREVIOUS_RELEASE_BRANCH" && git push origin "$RELEASE_BRANCH"; then | |
| echo "Successfully merged $PREVIOUS_RELEASE_BRANCH into $RELEASE_BRANCH and pushed" | |
| else | |
| # Close all previous PRs with label | |
| pr_numbers=$(gh pr list --label merge-previous-release-branch --json number --jq='.[].number') | |
| for pr_number in $pr_numbers; do | |
| gh pr close "$pr_number" --delete-branch | |
| done | |
| pr_body=$( | |
| echo 'Created by GitHub action' | |
| for pr_number in $pr_numbers; do | |
| echo "Replaces #$pr_number" | |
| done | |
| ) | |
| TEMP_BRANCH="merge-$PREVIOUS_RELEASE_BRANCH-$(date "+%Y%m%d%H%M%S")" | |
| git branch "$TEMP_BRANCH" "$PREVIOUS_RELEASE_BRANCH" | |
| git push origin "$TEMP_BRANCH" | |
| gh pr create \ | |
| --base "$RELEASE_BRANCH" \ | |
| --head "$TEMP_BRANCH" \ | |
| --title "Merge $PREVIOUS_RELEASE_BRANCH into $RELEASE_BRANCH" \ | |
| --body "$pr_body" \ | |
| --label merge-previous-release-branch | |
| echo "Created a PR to merge $PREVIOUS_RELEASE_BRANCH ($TEMP_BRANCH) into $RELEASE_BRANCH" | |
| fi | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }} |