diff --git a/.github/workflows/create_ifu_tag.yml b/.github/workflows/create_ifu_tag.yml new file mode 100644 index 0000000000000..e54bb35e6982c --- /dev/null +++ b/.github/workflows/create_ifu_tag.yml @@ -0,0 +1,116 @@ +name: Create git tags for IFU PRs + +on: + pull_request: + types: [closed] + +permissions: + contents: write # create/push tags + pull-requests: write # edit PR body + +jobs: + tag-ifu: + # Only proceed if: merged AND title has both markers + if: > + github.event.pull_request.merged == true && + contains(github.event.pull_request.title, '[AUTOGENERATED]') && + contains(github.event.pull_request.title, 'IFU') + runs-on: ubuntu-latest + + steps: + - name: Checkout base repo (full history) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.ref }} + fetch-depth: 0 + + - name: Configure Git user + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Derive key SHAs (rocm base, upstream main, merge) + id: shas + shell: bash + run: | + set -euo pipefail + + PR_NUM="${{ github.event.pull_request.number }}" + BASE_REF="${{ github.event.pull_request.base.ref }}" + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + MERGE_SHA="${{ github.event.pull_request.merge_commit_sha }}" + + # The ROCm base commit is the first parent of the merge commit that landed the PR + # (i.e., the base branch tip BEFORE this PR merged). + ROCM_BASE_SHA=$(git rev-parse "${MERGE_SHA}^1") + + # Add and fetch upstream to identify the upstream/main commit that HEAD integrated. + git remote add upstream "https://github.com/pytorch/pytorch.git" + git fetch upstream "$BASE_REF" + + # Heuristic: the upstream commit integrated by the PR's head is the merge-base + # between the PR head commit and upstream/main as fetched now. + # This gives you the exact upstream commit (or the best common ancestor) that HEAD included. + UPSTREAM_MAIN_SHA=$(git merge-base "${HEAD_SHA}" "upstream/$BASE_REF") + echo "PR_NUM=$PR_NUM" + echo "BASE_REF=$BASE_REF" + echo "HEAD_SHA=$HEAD_SHA" + echo "MERGE_SHA=$MERGE_SHA" + echo "ROCM_BASE_SHA=$ROCM_BASE_SHA" + echo "UPSTREAM_MAIN_SHA=$UPSTREAM_MAIN_SHA" + + + echo "PR_NUM=$PR_NUM" >> "$GITHUB_OUTPUT" + echo "BASE_REF=$BASE_REF" >> "$GITHUB_OUTPUT" + echo "HEAD_SHA=$HEAD_SHA" >> "$GITHUB_OUTPUT" + echo "MERGE_SHA=$MERGE_SHA" >> "$GITHUB_OUTPUT" + echo "ROCM_BASE_SHA=$ROCM_BASE_SHA" >> "$GITHUB_OUTPUT" + echo "UPSTREAM_MAIN_SHA=$UPSTREAM_MAIN_SHA" >> "$GITHUB_OUTPUT" + + - name: Extract tag base from PR title + id: tagname + run: | + TITLE="${{ github.event.pull_request.title }}" + # Remove everything up to and including "[AUTOGENERATED]" + BASE_TAG=$(echo "$TITLE" | sed -E 's/^\[AUTOGENERATED\][[:space:]]*//') + + echo "BASE_TAG=$BASE_TAG" + echo "PRE_TAG=${BASE_TAG}_pre" + echo "POST_TAG=${BASE_TAG}_post" + + echo "BASE_TAG=$BASE_TAG" >> $GITHUB_OUTPUT + echo "PRE_TAG=${BASE_TAG}_pre" >> $GITHUB_OUTPUT + echo "POST_TAG=${BASE_TAG}_post" >> $GITHUB_OUTPUT + + - name: Create pre/post tags + shell: bash + run: | + set -euo pipefail + echo "Tagging:" + echo " ${{ steps.tagname.outputs.PRE_TAG }} @ ${{ steps.shas.outputs.ROCM_BASE_SHA }}" + echo " ${{ steps.tagname.outputs.POST_TAG }} @ ${{ steps.shas.outputs.MERGE_SHA }}" + + git tag -a "${{ steps.tagname.outputs.PRE_TAG }}" -m "IFU pre (PR #${{ steps.shas.outputs.PR_NUM }})" "${{ steps.shas.outputs.ROCM_BASE_SHA }}" + git tag -a "${{ steps.tagname.outputs.POST_TAG }}" -m "IFU post (PR #${{ steps.shas.outputs.PR_NUM }})" "${{ steps.shas.outputs.MERGE_SHA }}" + + #Force pushing is safe. If we land a new PR, we'd wanna retag a commit if we have to. + git push origin "refs/tags/${{ steps.tagname.outputs.PRE_TAG }}" -f + git push origin "refs/tags/${{ steps.tagname.outputs.POST_TAG }}" -f + + - name: Append rocm_base & upstream_main to PR body + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + set -euo pipefail + # Read current body + PR="${{ steps.shas.outputs.PR_NUM }}" + CURR=$(gh api repos/${{ github.repository }}/pulls/$PR --jq .body) + APPEND=$'\n'"rocm_base: ${{ steps.shas.outputs.ROCM_BASE_SHA }}"$'\n'"upstream_main: ${{ steps.shas.outputs.UPSTREAM_MAIN_SHA }}"$'\n' + NEW_BODY="${CURR}${APPEND}" + + # Write to a temp file and update PR body + printf '%s' "$NEW_BODY" > body.txt + gh api --method PATCH -H "Accept: application/vnd.github+json" \ + repos/${{ github.repository }}/pulls/$PR -F body=@body.txt + diff --git a/.github/workflows/pytorch_ifu.yml b/.github/workflows/pytorch_ifu.yml new file mode 100644 index 0000000000000..fe7439e2e7475 --- /dev/null +++ b/.github/workflows/pytorch_ifu.yml @@ -0,0 +1,145 @@ +name: PyTorch IFU (Sync with upstream) + +on: + workflow_dispatch: + inputs: + ifu_target_repo: + description: "Target repo for IFU" + required: false + default: "ROCm/pytorch" + type: string + ifu_target_branch: + description: "Target branch for IFU" + required: true + default: "rocm7.1_internal_testing" + type: string + ifu_source_repo: + description: "Source repo for IFU" + required: false + default: "pytorch/pytorch" + type: string + ifu_source_branch: + description: "Source branch for IFU" + required: false + default: "main" + type: string + # schedule: + # # Runs every 14 days at 09:00 AM UTC/ 04:00 AM CST + # - cron: "0 9 */14 * *" + +permissions: + contents: write # push branches/tags + pull-requests: write # create PRs + +concurrency: + group: ifu + # If two jobs are running simultaneously, we will queue them (not cancel the one running) + cancel-in-progress: false + +jobs: + ifu: + runs-on: ubuntu-latest + env: + UPSTREAM_REMOTE: upstream # IFU source remote name + UPSTREAM_REPO: ${{ inputs.ifu_source_repo }} # source repo for IFU + UPSTREAM_BRANCH: ${{ inputs.ifu_source_branch }} # source branch for IFU + DOWNSTREAM_REMOTE: origin # IFU target remote name + DOWNSTREAM_REPO: ${{ inputs.ifu_target_repo }} # target repo for IFU (fork); actions/checkout sets this to origin + DOWNSTREAM_BRANCH: ${{ inputs.ifu_target_branch }} # target branch for IFU + GH_TOKEN: ${{ secrets.IFU_GITHUB_TOKEN }} # used by gh; provided by Action + steps: + - name: Checkout repository (${{ env.DOWNSTREAM_REPO }}) (full history) + uses: actions/checkout@v4 + with: + repository: ${{ env.DOWNSTREAM_REPO }} + path: ${{ env.DOWNSTREAM_REPO }} + ref: ${{ env.DOWNSTREAM_BRANCH }} + token: ${{ env.GH_TOKEN }} + fetch-depth: 0 # need full history for merges/tags + submodules: recursive + + - name: Add upstream remote (${{ env.UPSTREAM_REPO }}) + working-directory: ${{ env.DOWNSTREAM_REPO }} + run: | + if ! git remote get-url ${UPSTREAM_REMOTE} >/dev/null 2>&1; then + git remote add ${UPSTREAM_REMOTE} https://github.com/${UPSTREAM_REPO}.git + fi + # Confirm remotes + git remote -v + + - name: Configure Git user + working-directory: ${{ env.DOWNSTREAM_REPO }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Fetch upstream and local branch + working-directory: ${{ env.DOWNSTREAM_REPO }} + run: | + git fetch ${UPSTREAM_REMOTE} ${UPSTREAM_BRANCH} + git fetch ${DOWNSTREAM_REMOTE} ${DOWNSTREAM_BRANCH} + + - name: Compute date tag and create working branch + working-directory: ${{ env.DOWNSTREAM_REPO }} + id: tag + shell: bash + run: | + DATE="$(date +"%Y-%m-%d")" + TAG="${DOWNSTREAM_BRANCH}_IFU_${DATE}" + echo "TAG=${TAG}" >> $GITHUB_OUTPUT + # Start from rocm branch + git checkout -b "$TAG" "${DOWNSTREAM_REMOTE}/${DOWNSTREAM_BRANCH}" + + - name: Save ROCm base commit + working-directory: ${{ env.DOWNSTREAM_REPO }} + id: rocm_base + run: | + base_commit=`git rev-parse --short HEAD` + echo "ROCM_BASE_COMMIT=$base_commit" >> $GITHUB_OUTPUT + + - name: Merge upstream into working branch (non-interactive) + working-directory: ${{ env.DOWNSTREAM_REPO }} + id: merge + run: | + if git merge "${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH}" --no-edit; then + echo "merge_status=clean" >> $GITHUB_OUTPUT + else + echo "Merge conflicts detected. Committing current resolution snapshot." + git submodule sync + git submodule update --init --recursive + git add -A + git status + git commit --no-edit + echo "merge_status=conflict" >> $GITHUB_OUTPUT + fi + + - name: Push branch & tag to fork + working-directory: ${{ env.DOWNSTREAM_REPO }} + run: | + git push ${DOWNSTREAM_REMOTE} "${{ steps.tag.outputs.TAG }}" + + - name: Authenticate gh (non-interactive) + working-directory: ${{ env.DOWNSTREAM_REPO }} + run: | + # The GitHub-hosted runner has gh preinstalled. + gh auth status || echo "$GH_TOKEN" | gh auth login --with-token + gh repo set-default "${{ env.DOWNSTREAM_REPO }}" + + - name: Create Pull Request with gh + working-directory: ${{ env.DOWNSTREAM_REPO }} + run: | + BASE="${DOWNSTREAM_BRANCH}" + HEAD="${{ steps.tag.outputs.TAG }}" + TITLE="[AUTOGENERATED] $HEAD" + BODY="rocm_base: ${{ steps.rocm_base.outputs.ROCM_BASE_COMMIT }}" + + # If a PR for this head already exists, skip creating a new one + if gh pr list --head "$HEAD" --base "$BASE" --state all --json number | grep -q '[0-9]'; then + echo "PR already exists for $HEAD -> $BASE. Skipping creation." + else + gh pr create --base "$BASE" --head "$HEAD" --title "$TITLE" --body "$BODY" + fi + + - name: Summarize + run: | + echo "::notice title=IFU Completed::Branch ${{ steps.tag.outputs.TAG }} pushed. PR created (or already existed). Merge status: ${{ steps.merge.outputs.merge_status }}"