upstream_upgrade_pr #8
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: upstream_upgrade_pr | |
| on: | |
| repository_dispatch: | |
| types: | |
| - upstream_release | |
| workflow_dispatch: | |
| inputs: | |
| allow_prerelease: | |
| description: Process beta/prerelease tags | |
| required: false | |
| default: "false" | |
| type: choice | |
| options: | |
| - "false" | |
| - "true" | |
| patch_branch: | |
| description: Branch containing webmonitoring patches | |
| required: false | |
| default: wm/patches | |
| type: string | |
| permissions: | |
| contents: write | |
| issues: write | |
| concurrency: | |
| group: webmonitoring-upstream-upgrade-pr | |
| cancel-in-progress: false | |
| jobs: | |
| upgrade: | |
| permissions: | |
| contents: write | |
| issues: write | |
| runs-on: ubuntu-latest | |
| env: | |
| UPSTREAM_REMOTE: upstream | |
| UPSTREAM_URL: https://github.com/uBlockOrigin/uBOL-home.git | |
| MAIN_BRANCH: main | |
| PATCH_BRANCH: ${{ github.event.client_payload.patch_branch || github.event.inputs.patch_branch || 'wm/patches' }} | |
| ALLOW_PRERELEASE: ${{ github.event.client_payload.allow_prerelease || github.event.inputs.allow_prerelease || 'false' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Fetch origin and upstream refs | |
| run: | | |
| git remote add "$UPSTREAM_REMOTE" "$UPSTREAM_URL" 2>/dev/null || true | |
| git fetch origin --prune | |
| git fetch "$UPSTREAM_REMOTE" --tags --prune | |
| - name: Validate patch branch exists on origin | |
| run: | | |
| PATCH_BRANCH="${PATCH_BRANCH:-wm/patches}" | |
| if ! git ls-remote --exit-code --heads origin "$PATCH_BRANCH" >/dev/null 2>&1; then | |
| echo "Remote patch branch origin/$PATCH_BRANCH does not exist." | |
| echo "Create it first (for example: git push -u origin $PATCH_BRANCH)." | |
| exit 1 | |
| fi | |
| - name: Detect latest upstream tag and type | |
| id: detect | |
| run: | | |
| PATCH_BRANCH="${PATCH_BRANCH:-wm/patches}" | |
| ALLOW_PRERELEASE="${ALLOW_PRERELEASE:-false}" | |
| latest_tag="$(git describe --tags --abbrev=0 "$UPSTREAM_REMOTE/$MAIN_BRANCH")" | |
| release_kind="stable" | |
| if [[ "$latest_tag" == *"-beta"* ]]; then | |
| release_kind="beta" | |
| fi | |
| api_json="$(curl -fsSL -H "Accept: application/vnd.github+json" \ | |
| "https://api.github.com/repos/uBlockOrigin/uBOL-home/releases/tags/$latest_tag" || true)" | |
| api_prerelease="$(jq -r '.prerelease // empty' <<< "$api_json")" | |
| if [[ "$api_prerelease" == "true" ]]; then | |
| release_kind="beta" | |
| elif [[ "$api_prerelease" == "false" ]]; then | |
| release_kind="stable" | |
| fi | |
| if [[ "$release_kind" == "beta" && "$ALLOW_PRERELEASE" != "true" ]]; then | |
| echo "Skipping beta tag $latest_tag because ALLOW_PRERELEASE=false" | |
| echo "should_continue=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "should_continue=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "latest_tag=$latest_tag" >> "$GITHUB_OUTPUT" | |
| echo "release_kind=$release_kind" >> "$GITHUB_OUTPUT" | |
| echo "patch_branch=$PATCH_BRANCH" >> "$GITHUB_OUTPUT" | |
| - name: Skip info | |
| if: steps.detect.outputs.should_continue != 'true' | |
| run: | | |
| echo "No upgrade issue created." | |
| echo "Latest upstream tag is ${{ steps.detect.outputs.latest_tag }} (${{ steps.detect.outputs.release_kind }})." | |
| - name: Check if tag already processed | |
| if: steps.detect.outputs.should_continue == 'true' | |
| id: marker | |
| run: | | |
| marker_tag="ci/upstream-seen/${{ steps.detect.outputs.latest_tag }}" | |
| if git ls-remote --exit-code --tags origin "refs/tags/$marker_tag" >/dev/null 2>&1; then | |
| echo "already_processed=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "already_processed=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "marker_tag=$marker_tag" >> "$GITHUB_OUTPUT" | |
| - name: Exit when this tag is already processed | |
| if: steps.detect.outputs.should_continue == 'true' && steps.marker.outputs.already_processed == 'true' | |
| run: | | |
| echo "Tag ${{ steps.detect.outputs.latest_tag }} was already processed. Nothing to do." | |
| - name: Fast-forward main from upstream/main | |
| if: steps.detect.outputs.should_continue == 'true' && steps.marker.outputs.already_processed != 'true' | |
| run: | | |
| git checkout -B "$MAIN_BRANCH" "origin/$MAIN_BRANCH" | |
| before_sha="$(git rev-parse HEAD)" | |
| git merge --ff-only "$UPSTREAM_REMOTE/$MAIN_BRANCH" | |
| after_sha="$(git rev-parse HEAD)" | |
| if [[ "$before_sha" != "$after_sha" ]]; then | |
| git push origin "$MAIN_BRANCH" | |
| echo "Updated origin/$MAIN_BRANCH: $before_sha -> $after_sha" | |
| else | |
| echo "$MAIN_BRANCH already up to date." | |
| fi | |
| - name: Check if integration issue is needed | |
| if: steps.detect.outputs.should_continue == 'true' && steps.marker.outputs.already_processed != 'true' | |
| id: issue_needed | |
| run: | | |
| patch_branch="${{ steps.detect.outputs.patch_branch }}" | |
| ahead_count="$(git rev-list --count "origin/$patch_branch..$MAIN_BRANCH")" | |
| if [[ "$ahead_count" -eq 0 ]]; then | |
| echo "needed=false" >> "$GITHUB_OUTPUT" | |
| echo "No new commits to integrate from $MAIN_BRANCH into $patch_branch." | |
| else | |
| echo "needed=true" >> "$GITHUB_OUTPUT" | |
| echo "Found $ahead_count commit(s) to integrate from $MAIN_BRANCH into $patch_branch." | |
| fi | |
| - name: Open or update upgrade issue | |
| if: steps.detect.outputs.should_continue == 'true' && steps.marker.outputs.already_processed != 'true' && steps.issue_needed.outputs.needed == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| patch_branch="${{ steps.detect.outputs.patch_branch }}" | |
| latest_tag="${{ steps.detect.outputs.latest_tag }}" | |
| release_kind="${{ steps.detect.outputs.release_kind }}" | |
| repo="${{ github.repository }}" | |
| copilot_assignee="${COPILOT_ASSIGNEE:-@copilot}" | |
| title="Integrate upstream UBOL $latest_tag into $patch_branch" | |
| body="$(printf '%s\n' \ | |
| "Automated upstream integration request." \ | |
| "" \ | |
| "- Upstream tag: \`$latest_tag\`" \ | |
| "- Release type: \`$release_kind\`" \ | |
| "- Source branch: \`$MAIN_BRANCH\`" \ | |
| "- Target branch: \`$patch_branch\`" \ | |
| "" \ | |
| "Current workflow state:" \ | |
| "- \`main\` was synced from \`upstream/main\`." \ | |
| "- New upstream commits are ready to be integrated into \`$patch_branch\`." \ | |
| "" \ | |
| "Goal:" \ | |
| "- Merge \`main\` into \`$patch_branch\` to bring upstream changes into our patched branch." \ | |
| "" \ | |
| "Required work:" \ | |
| "1. Merge \`main\` into \`$patch_branch\`." \ | |
| "2. Resolve any merge conflicts." \ | |
| "3. Ensure the branch is in a releasable state after conflict resolution." \ | |
| "" \ | |
| "Please assign this task to Copilot for conflict resolution and integration support." \ | |
| "" \ | |
| "This issue was opened by \`upstream_upgrade_pr.yml\`." \ | |
| )" | |
| existing_issue="$(gh issue list \ | |
| --repo "$repo" \ | |
| --state open \ | |
| --search "$title in:title" \ | |
| --json number \ | |
| --jq '.[0].number')" | |
| if [[ -n "$existing_issue" && "$existing_issue" != "null" ]]; then | |
| gh issue edit "$existing_issue" --repo "$repo" --title "$title" --body "$body" | |
| gh issue edit "$existing_issue" --repo "$repo" --add-assignee "$copilot_assignee" | |
| echo "Updated existing issue #$existing_issue" | |
| else | |
| issue_url="$(gh issue create --repo "$repo" --title "$title" --body "$body")" | |
| issue_number="${issue_url##*/}" | |
| gh issue edit "$issue_number" --repo "$repo" --add-assignee "$copilot_assignee" | |
| echo "Created new upgrade issue: $issue_url" | |
| fi | |
| - name: Mark upstream tag as processed | |
| if: steps.detect.outputs.should_continue == 'true' && steps.marker.outputs.already_processed != 'true' | |
| run: | | |
| git tag "${{ steps.marker.outputs.marker_tag }}" "$MAIN_BRANCH" | |
| git push origin "refs/tags/${{ steps.marker.outputs.marker_tag }}" |