name: Merge Upstream on: schedule: # Weekdays at 08:07 UTC — ~9am CET / 10am CEST, start-of-day for # Central Europe reviewers. Overnight in the US so PRs are ready to # land first thing. Off-the-hour to avoid cron-fleet pile-ups. - cron: '7 8 * * 1-5' workflow_dispatch: # Allow manual triggering concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: contents: write # Push branches pull-requests: write # Create PRs jobs: merge-upstream: runs-on: ubuntu-latest steps: - name: Generate GitHub App token id: app-token uses: actions/create-github-app-token@v1 with: app-id: ${{ secrets.MERGE_APP_ID }} private-key: ${{ secrets.MERGE_APP_PRIVATE_KEY }} - name: Checkout repository uses: actions/checkout@v4 with: ref: amd-staging fetch-depth: 0 token: ${{ steps.app-token.outputs.token }} - name: Configure git run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - name: Add upstream remote run: | git remote add upstream https://github.com/KhronosGroup/SPIRV-LLVM-Translator.git git fetch upstream main - name: Get timestamp id: timestamp run: | echo "datetime=$(TZ='America/New_York' date +'%Y-%m-%d %H:%M %Z')" >> $GITHUB_OUTPUT - name: Check for new commits id: check-commits run: | UPSTREAM_SHA=$(git rev-parse upstream/main) if git merge-base --is-ancestor $UPSTREAM_SHA HEAD; then echo "No new upstream commits" echo "has_changes=false" >> $GITHUB_OUTPUT else echo "New upstream commits found" echo "has_changes=true" >> $GITHUB_OUTPUT fi - name: Create merge branch id: merge if: steps.check-commits.outputs.has_changes == 'true' run: | BRANCH_NAME="upstream-merge-$(date +%Y%m%d%H%M%S)" PR_TITLE="Upstream merge ${{ steps.timestamp.outputs.datetime }}" git checkout -b $BRANCH_NAME echo "pr_title=$PR_TITLE" >> $GITHUB_OUTPUT if git merge upstream/main --no-edit; then echo "Merge successful" echo "conflict=false" >> $GITHUB_OUTPUT else echo "Merge has conflicts" # Capture conflicting files before aborting CONFLICTS=$(git diff --name-only --diff-filter=U | head -10) CONFLICT_COUNT=$(git diff --name-only --diff-filter=U | wc -l) echo "conflict_files<> $GITHUB_OUTPUT echo "$CONFLICTS" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "conflict_count=$CONFLICT_COUNT" >> $GITHUB_OUTPUT git merge --abort echo "conflict=true" >> $GITHUB_OUTPUT fi echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT - name: Push branch if: steps.merge.outputs.conflict == 'false' run: | git push origin ${{ steps.merge.outputs.branch }} - name: Create Pull Request id: create-pr if: steps.merge.outputs.conflict == 'false' env: GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | PR_URL=$(gh pr create \ --repo ${{ github.repository }} \ --base amd-staging \ --head ${{ steps.merge.outputs.branch }} \ --title "${{ steps.merge.outputs.pr_title }}" \ --reviewer maarquitos14,MrSidims,AlexVlx,lamb-j,steffenlarsen,mgcarrasco \ --body "$(cat <<'EOF' Automated merge of upstream KhronosGroup/SPIRV-LLVM-Translator main branch. **Merge this PR using "Create a merge commit" — do NOT squash.** Squash-merging destroys upstream ancestry tracking and will cause conflicts on every future merge. This PR was created automatically by the upstream-merge workflow. EOF )") echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT - name: Enable auto-merge (merge commit) if: steps.merge.outputs.conflict == 'false' env: GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | # Lock merge method to "Create a merge commit" to preserve upstream ancestry. gh pr merge "${{ steps.create-pr.outputs.pr_url }}" --auto --merge \ || echo "::warning::Could not enable auto-merge; reviewers must pick 'Create a merge commit' manually." - name: Notify Teams - PR Created if: steps.merge.outputs.conflict == 'false' run: | curl -H "Content-Type: application/json" -d '{ "@type": "MessageCard", "themeColor": "00FF00", "summary": "Upstream merge PR created", "sections": [{ "activityTitle": "✅ Upstream Merge PR Created", "facts": [{ "name": "Time", "value": "${{ steps.timestamp.outputs.datetime }}" }, { "name": "Branch", "value": "${{ steps.merge.outputs.branch }}" }], "text": "[View PR](${{ steps.create-pr.outputs.pr_url }})", "markdown": true }] }' "${{ secrets.TEAMS_WEBHOOK_URL }}" - name: Notify Teams - No Changes if: steps.check-commits.outputs.has_changes == 'false' run: | curl -H "Content-Type: application/json" -d '{ "@type": "MessageCard", "themeColor": "808080", "summary": "No upstream changes", "sections": [{ "activityTitle": "ℹ️ No New Upstream Commits", "facts": [{ "name": "Time", "value": "${{ steps.timestamp.outputs.datetime }}" }], "text": "amd-staging is already up to date with upstream main.", "markdown": true }] }' "${{ secrets.TEAMS_WEBHOOK_URL }}" - name: Notify Teams - Merge Conflict if: steps.merge.outputs.conflict == 'true' env: CONFLICT_FILES: ${{ steps.merge.outputs.conflict_files }} run: | # Format conflict files for display (replace newlines with
) FORMATTED_FILES=$(echo "$CONFLICT_FILES" | sed ':a;N;$!ba;s/\n/
/g') CONFLICT_COUNT="${{ steps.merge.outputs.conflict_count }}" # Add note if there are more than 10 files if [ "$CONFLICT_COUNT" -gt 10 ]; then FORMATTED_FILES="${FORMATTED_FILES}
... and $((CONFLICT_COUNT - 10)) more" fi curl -H "Content-Type: application/json" -d '{ "@type": "MessageCard", "themeColor": "FF0000", "summary": "Upstream merge conflict", "sections": [{ "activityTitle": "⚠️ Merge Conflicts Detected", "facts": [{ "name": "Time", "value": "${{ steps.timestamp.outputs.datetime }}" }, { "name": "Conflicting Files", "value": "'"$FORMATTED_FILES"'" }, { "name": "Total Conflicts", "value": "'"$CONFLICT_COUNT"' file(s)" }], "text": "Automatic merge of upstream main into amd-staging failed due to conflicts. Manual intervention required.

[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) · [View repository](${{ github.server_url }}/${{ github.repository }})", "markdown": true }] }' "${{ secrets.TEAMS_WEBHOOK_URL }}"