From 0fd38db400c2e4230eddc0194cffb9bf156cd964 Mon Sep 17 00:00:00 2001 From: Molly He Date: Mon, 23 Mar 2026 11:35:56 -0700 Subject: [PATCH 1/9] Test workflow file --- .../workflows/conda-forge-release-chain.yml | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 .github/workflows/conda-forge-release-chain.yml diff --git a/.github/workflows/conda-forge-release-chain.yml b/.github/workflows/conda-forge-release-chain.yml new file mode 100644 index 0000000000..2d0c7f7a52 --- /dev/null +++ b/.github/workflows/conda-forge-release-chain.yml @@ -0,0 +1,240 @@ +name: Conda Forge Release Chain + +on: + workflow_dispatch: + inputs: + poll_interval_seconds: + description: 'Seconds between polls (default: 300)' + required: false + default: '300' + timeout_attempts: + description: 'Max poll attempts per package before failing (default: 60 = 5hrs at 300s)' + required: false + default: '60' + +env: + GH_TOKEN: ${{ secrets.GH_PAT }} + POLL_INTERVAL: ${{ github.event.inputs.poll_interval_seconds }} + MAX_ATTEMPTS: ${{ github.event.inputs.timeout_attempts }} + +jobs: + # ── Read versions from VERSION files ──────────────────────────────────────── + read-versions: + runs-on: ubuntu-latest + outputs: + core: ${{ steps.v.outputs.core }} + train: ${{ steps.v.outputs.train }} + serve: ${{ steps.v.outputs.serve }} + mlops: ${{ steps.v.outputs.mlops }} + pysdk: ${{ steps.v.outputs.pysdk }} + meta: ${{ steps.v.outputs.meta }} + steps: + - uses: actions/checkout@v4 + - name: Read versions + id: v + run: | + echo "core=$(cat sagemaker-core/VERSION)" >> $GITHUB_OUTPUT + echo "train=$(cat sagemaker-train/VERSION)" >> $GITHUB_OUTPUT + echo "serve=$(cat sagemaker-serve/VERSION)" >> $GITHUB_OUTPUT + echo "mlops=$(cat sagemaker-mlops/VERSION)" >> $GITHUB_OUTPUT + echo "pysdk=$(cat VERSION)" >> $GITHUB_OUTPUT + echo "meta=$(cat VERSION)" >> $GITHUB_OUTPUT + - name: Print versions + run: | + echo "sagemaker-core: $(cat sagemaker-core/VERSION)" + echo "sagemaker-train: $(cat sagemaker-train/VERSION)" + echo "sagemaker-serve: $(cat sagemaker-serve/VERSION)" + echo "sagemaker-mlops: $(cat sagemaker-mlops/VERSION)" + echo "sagemaker-python-sdk: $(cat VERSION)" + echo "sagemaker (meta): $(cat VERSION)" + + # ── 1. Wait for sagemaker-core (automerges on its own) ────────────────────── + wait-sagemaker-core: + needs: read-versions + runs-on: ubuntu-latest + steps: + - name: Wait for sagemaker-core feedstock PR to merge + run: | + VERSION="${{ needs.read-versions.outputs.core }}" + REPO="conda-forge/sagemaker-core-feedstock" + echo "Waiting for: [bot-automerge] sagemaker-core v${VERSION}" + for i in $(seq 1 $MAX_ATTEMPTS); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-core v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep $POLL_INTERVAL + done + echo "Timed out." && exit 1 + + # ── 2. sagemaker-train ─────────────────────────────────────────────────────── + release-sagemaker-train: + needs: [read-versions, wait-sagemaker-core] + runs-on: ubuntu-latest + steps: + - name: Rerun failed checks + run: | + VERSION="${{ needs.read-versions.outputs.train }}" + REPO="conda-forge/sagemaker-train-feedstock" + PR=$(gh pr list --repo "$REPO" --state open \ + --search "[bot-automerge] sagemaker-train v${VERSION}" \ + --json number -q '.[0].number') + echo "PR #${PR}" + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ + || echo "No failed runs." + - name: Wait for merge + run: | + VERSION="${{ needs.read-versions.outputs.train }}" + REPO="conda-forge/sagemaker-train-feedstock" + for i in $(seq 1 $MAX_ATTEMPTS); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-train v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep $POLL_INTERVAL + done + echo "Timed out." && exit 1 + + # ── 3. sagemaker-serve ─────────────────────────────────────────────────────── + release-sagemaker-serve: + needs: [read-versions, release-sagemaker-train] + runs-on: ubuntu-latest + steps: + - name: Rerun failed checks + run: | + VERSION="${{ needs.read-versions.outputs.serve }}" + REPO="conda-forge/sagemaker-serve-feedstock" + PR=$(gh pr list --repo "$REPO" --state open \ + --search "[bot-automerge] sagemaker-serve v${VERSION}" \ + --json number -q '.[0].number') + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ + || echo "No failed runs." + - name: Wait for merge + run: | + VERSION="${{ needs.read-versions.outputs.serve }}" + REPO="conda-forge/sagemaker-serve-feedstock" + for i in $(seq 1 $MAX_ATTEMPTS); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-serve v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep $POLL_INTERVAL + done + echo "Timed out." && exit 1 + + # ── 4. sagemaker-mlops ─────────────────────────────────────────────────────── + release-sagemaker-mlops: + needs: [read-versions, release-sagemaker-serve] + runs-on: ubuntu-latest + steps: + - name: Rerun failed checks + run: | + VERSION="${{ needs.read-versions.outputs.mlops }}" + REPO="conda-forge/sagemaker-mlops-feedstock" + PR=$(gh pr list --repo "$REPO" --state open \ + --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ + --json number -q '.[0].number') + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ + || echo "No failed runs." + - name: Wait for merge + run: | + VERSION="${{ needs.read-versions.outputs.mlops }}" + REPO="conda-forge/sagemaker-mlops-feedstock" + for i in $(seq 1 $MAX_ATTEMPTS); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep $POLL_INTERVAL + done + echo "Timed out." && exit 1 + + # ── 5. sagemaker-python-sdk-feedstock ─────────────────────────────────────── + release-sagemaker-python-sdk: + needs: [read-versions, release-sagemaker-mlops] + runs-on: ubuntu-latest + steps: + - name: Rerun failed checks + run: | + VERSION="${{ needs.read-versions.outputs.pysdk }}" + REPO="conda-forge/sagemaker-python-sdk-feedstock" + PR=$(gh pr list --repo "$REPO" --state open \ + --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ + --json number -q '.[0].number') + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ + || echo "No failed runs." + - name: Wait for merge + run: | + VERSION="${{ needs.read-versions.outputs.pysdk }}" + REPO="conda-forge/sagemaker-python-sdk-feedstock" + for i in $(seq 1 $MAX_ATTEMPTS); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep $POLL_INTERVAL + done + echo "Timed out." && exit 1 + + # ── 6. sagemaker (meta-package) ────────────────────────────────────────────── + release-sagemaker: + needs: [read-versions, release-sagemaker-python-sdk] + runs-on: ubuntu-latest + steps: + - name: Rerun failed checks + run: | + VERSION="${{ needs.read-versions.outputs.meta }}" + REPO="conda-forge/sagemaker-feedstock" + PR=$(gh pr list --repo "$REPO" --state open \ + --search "[bot-automerge] sagemaker v${VERSION}" \ + --json number -q '.[0].number') + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ + || echo "No failed runs." + - name: Wait for merge + run: | + VERSION="${{ needs.read-versions.outputs.meta }}" + REPO="conda-forge/sagemaker-feedstock" + for i in $(seq 1 $MAX_ATTEMPTS); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep $POLL_INTERVAL + done + echo "Timed out." && exit 1 + + - name: Release chain complete + run: | + echo "All packages released on conda-forge:" + echo " sagemaker-core ${{ needs.read-versions.outputs.core }}" + echo " sagemaker-train ${{ needs.read-versions.outputs.train }}" + echo " sagemaker-serve ${{ needs.read-versions.outputs.serve }}" + echo " sagemaker-mlops ${{ needs.read-versions.outputs.mlops }}" + echo " sagemaker-python-sdk ${{ needs.read-versions.outputs.pysdk }}" + echo " sagemaker ${{ needs.read-versions.outputs.meta }}" From 9a703f1280d70f12096a1fa341bb23f2666f2909 Mon Sep 17 00:00:00 2001 From: Molly He Date: Mon, 23 Mar 2026 11:56:05 -0700 Subject: [PATCH 2/9] Add skip if already merged --- .../workflows/conda-forge-release-chain.yml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/conda-forge-release-chain.yml b/.github/workflows/conda-forge-release-chain.yml index 2d0c7f7a52..29948e8a3b 100644 --- a/.github/workflows/conda-forge-release-chain.yml +++ b/.github/workflows/conda-forge-release-chain.yml @@ -77,9 +77,16 @@ jobs: run: | VERSION="${{ needs.read-versions.outputs.train }}" REPO="conda-forge/sagemaker-train-feedstock" + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-train v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + if [ "$STATE" = "MERGED" ]; then + echo "Already merged, skipping rerun."; exit 0 + fi PR=$(gh pr list --repo "$REPO" --state open \ --search "[bot-automerge] sagemaker-train v${VERSION}" \ --json number -q '.[0].number') + [ -z "$PR" ] && echo "No open PR found." && exit 1 echo "PR #${PR}" BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ @@ -110,9 +117,16 @@ jobs: run: | VERSION="${{ needs.read-versions.outputs.serve }}" REPO="conda-forge/sagemaker-serve-feedstock" + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-serve v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + if [ "$STATE" = "MERGED" ]; then + echo "Already merged, skipping rerun."; exit 0 + fi PR=$(gh pr list --repo "$REPO" --state open \ --search "[bot-automerge] sagemaker-serve v${VERSION}" \ --json number -q '.[0].number') + [ -z "$PR" ] && echo "No open PR found." && exit 1 BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ --json databaseId,conclusion -q \ @@ -142,9 +156,16 @@ jobs: run: | VERSION="${{ needs.read-versions.outputs.mlops }}" REPO="conda-forge/sagemaker-mlops-feedstock" + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + if [ "$STATE" = "MERGED" ]; then + echo "Already merged, skipping rerun."; exit 0 + fi PR=$(gh pr list --repo "$REPO" --state open \ --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ --json number -q '.[0].number') + [ -z "$PR" ] && echo "No open PR found." && exit 1 BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ --json databaseId,conclusion -q \ @@ -174,9 +195,16 @@ jobs: run: | VERSION="${{ needs.read-versions.outputs.pysdk }}" REPO="conda-forge/sagemaker-python-sdk-feedstock" + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + if [ "$STATE" = "MERGED" ]; then + echo "Already merged, skipping rerun."; exit 0 + fi PR=$(gh pr list --repo "$REPO" --state open \ --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ --json number -q '.[0].number') + [ -z "$PR" ] && echo "No open PR found." && exit 1 BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ --json databaseId,conclusion -q \ @@ -206,9 +234,16 @@ jobs: run: | VERSION="${{ needs.read-versions.outputs.meta }}" REPO="conda-forge/sagemaker-feedstock" + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "[bot-automerge] sagemaker v${VERSION}" \ + --json state -q '.[0].state // "NOT_FOUND"') + if [ "$STATE" = "MERGED" ]; then + echo "Already merged, skipping rerun."; exit 0 + fi PR=$(gh pr list --repo "$REPO" --state open \ --search "[bot-automerge] sagemaker v${VERSION}" \ --json number -q '.[0].number') + [ -z "$PR" ] && echo "No open PR found." && exit 1 BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ --json databaseId,conclusion -q \ From 3fae0eeeca37d0a7d8b9636c175a6a10376d133f Mon Sep 17 00:00:00 2001 From: Molly He Date: Mon, 23 Mar 2026 12:03:39 -0700 Subject: [PATCH 3/9] Update so that the pr check is found --- .../workflows/conda-forge-release-chain.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/conda-forge-release-chain.yml b/.github/workflows/conda-forge-release-chain.yml index 29948e8a3b..b401d25cb4 100644 --- a/.github/workflows/conda-forge-release-chain.yml +++ b/.github/workflows/conda-forge-release-chain.yml @@ -78,13 +78,13 @@ jobs: VERSION="${{ needs.read-versions.outputs.train }}" REPO="conda-forge/sagemaker-train-feedstock" STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-train v${VERSION}" \ + --search "sagemaker-train v${VERSION}" \ --json state -q '.[0].state // "NOT_FOUND"') if [ "$STATE" = "MERGED" ]; then echo "Already merged, skipping rerun."; exit 0 fi PR=$(gh pr list --repo "$REPO" --state open \ - --search "[bot-automerge] sagemaker-train v${VERSION}" \ + --search "sagemaker-train v${VERSION}" \ --json number -q '.[0].number') [ -z "$PR" ] && echo "No open PR found." && exit 1 echo "PR #${PR}" @@ -100,7 +100,7 @@ jobs: REPO="conda-forge/sagemaker-train-feedstock" for i in $(seq 1 $MAX_ATTEMPTS); do STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-train v${VERSION}" \ + --search "sagemaker-train v${VERSION}" \ --json state -q '.[0].state // "NOT_FOUND"') echo "Attempt $i: ${STATE}" [ "$STATE" = "MERGED" ] && exit 0 @@ -118,13 +118,13 @@ jobs: VERSION="${{ needs.read-versions.outputs.serve }}" REPO="conda-forge/sagemaker-serve-feedstock" STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-serve v${VERSION}" \ + --search "sagemaker-serve v${VERSION}" \ --json state -q '.[0].state // "NOT_FOUND"') if [ "$STATE" = "MERGED" ]; then echo "Already merged, skipping rerun."; exit 0 fi PR=$(gh pr list --repo "$REPO" --state open \ - --search "[bot-automerge] sagemaker-serve v${VERSION}" \ + --search "sagemaker-serve v${VERSION}" \ --json number -q '.[0].number') [ -z "$PR" ] && echo "No open PR found." && exit 1 BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) @@ -139,7 +139,7 @@ jobs: REPO="conda-forge/sagemaker-serve-feedstock" for i in $(seq 1 $MAX_ATTEMPTS); do STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-serve v${VERSION}" \ + --search "sagemaker-serve v${VERSION}" \ --json state -q '.[0].state // "NOT_FOUND"') echo "Attempt $i: ${STATE}" [ "$STATE" = "MERGED" ] && exit 0 @@ -157,13 +157,13 @@ jobs: VERSION="${{ needs.read-versions.outputs.mlops }}" REPO="conda-forge/sagemaker-mlops-feedstock" STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ + --search "sagemaker-mlops v${VERSION}" \ --json state -q '.[0].state // "NOT_FOUND"') if [ "$STATE" = "MERGED" ]; then echo "Already merged, skipping rerun."; exit 0 fi PR=$(gh pr list --repo "$REPO" --state open \ - --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ + --search "sagemaker-mlops v${VERSION}" \ --json number -q '.[0].number') [ -z "$PR" ] && echo "No open PR found." && exit 1 BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) @@ -178,7 +178,7 @@ jobs: REPO="conda-forge/sagemaker-mlops-feedstock" for i in $(seq 1 $MAX_ATTEMPTS); do STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-mlops v${VERSION}" \ + --search "sagemaker-mlops v${VERSION}" \ --json state -q '.[0].state // "NOT_FOUND"') echo "Attempt $i: ${STATE}" [ "$STATE" = "MERGED" ] && exit 0 From 57bee5121df88215b72dc330e032420244352a43 Mon Sep 17 00:00:00 2001 From: Molly He Date: Mon, 23 Mar 2026 12:44:01 -0700 Subject: [PATCH 4/9] Rename token secret to CONDA_FORGE_RELEASE --- .../_conda-forge-package-release.yml | 66 +++++ .../workflows/conda-forge-release-chain.yml | 280 ++++-------------- 2 files changed, 127 insertions(+), 219 deletions(-) create mode 100644 .github/workflows/_conda-forge-package-release.yml diff --git a/.github/workflows/_conda-forge-package-release.yml b/.github/workflows/_conda-forge-package-release.yml new file mode 100644 index 0000000000..0a54f03ca5 --- /dev/null +++ b/.github/workflows/_conda-forge-package-release.yml @@ -0,0 +1,66 @@ +name: _Conda Forge Package Release + +on: + workflow_call: + inputs: + package: + description: 'Package name (e.g. sagemaker-train)' + required: true + type: string + feedstock: + description: 'Feedstock repo (e.g. conda-forge/sagemaker-train-feedstock)' + required: true + type: string + pr_search: + description: 'PR title search string (e.g. sagemaker-train v1.6.0)' + required: true + type: string + poll_interval: + required: true + type: string + max_attempts: + required: true + type: string + secrets: + token: + required: true + +jobs: + release: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.token }} + steps: + - name: Rerun failed checks or skip if already merged + run: | + REPO="${{ inputs.feedstock }}" + SEARCH="${{ inputs.pr_search }}" + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') + echo "Current state: ${STATE}" + if [ "$STATE" = "MERGED" ]; then + echo "Already merged, skipping."; exit 0 + fi + PR=$(gh pr list --repo "$REPO" --state open \ + --search "$SEARCH" --json number -q '.[0].number') + [ -z "$PR" ] && echo "No open PR found." && exit 1 + echo "PR #${PR}" + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ + || echo "No failed runs." + + - name: Wait for merge + run: | + REPO="${{ inputs.feedstock }}" + SEARCH="${{ inputs.pr_search }}" + for i in $(seq 1 ${{ inputs.max_attempts }}); do + STATE=$(gh pr list --repo "$REPO" --state all \ + --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') + echo "Attempt $i: ${STATE}" + [ "$STATE" = "MERGED" ] && exit 0 + sleep ${{ inputs.poll_interval }} + done + echo "Timed out waiting for ${{ inputs.package }}." && exit 1 diff --git a/.github/workflows/conda-forge-release-chain.yml b/.github/workflows/conda-forge-release-chain.yml index b401d25cb4..6f515c2617 100644 --- a/.github/workflows/conda-forge-release-chain.yml +++ b/.github/workflows/conda-forge-release-chain.yml @@ -12,13 +12,7 @@ on: required: false default: '60' -env: - GH_TOKEN: ${{ secrets.GH_PAT }} - POLL_INTERVAL: ${{ github.event.inputs.poll_interval_seconds }} - MAX_ATTEMPTS: ${{ github.event.inputs.timeout_attempts }} - jobs: - # ── Read versions from VERSION files ──────────────────────────────────────── read-versions: runs-on: ubuntu-latest outputs: @@ -33,243 +27,91 @@ jobs: - name: Read versions id: v run: | - echo "core=$(cat sagemaker-core/VERSION)" >> $GITHUB_OUTPUT - echo "train=$(cat sagemaker-train/VERSION)" >> $GITHUB_OUTPUT - echo "serve=$(cat sagemaker-serve/VERSION)" >> $GITHUB_OUTPUT - echo "mlops=$(cat sagemaker-mlops/VERSION)" >> $GITHUB_OUTPUT - echo "pysdk=$(cat VERSION)" >> $GITHUB_OUTPUT - echo "meta=$(cat VERSION)" >> $GITHUB_OUTPUT - - name: Print versions - run: | - echo "sagemaker-core: $(cat sagemaker-core/VERSION)" - echo "sagemaker-train: $(cat sagemaker-train/VERSION)" - echo "sagemaker-serve: $(cat sagemaker-serve/VERSION)" - echo "sagemaker-mlops: $(cat sagemaker-mlops/VERSION)" - echo "sagemaker-python-sdk: $(cat VERSION)" - echo "sagemaker (meta): $(cat VERSION)" + echo "core=$(cat sagemaker-core/VERSION)" >> $GITHUB_OUTPUT + echo "train=$(cat sagemaker-train/VERSION)" >> $GITHUB_OUTPUT + echo "serve=$(cat sagemaker-serve/VERSION)" >> $GITHUB_OUTPUT + echo "mlops=$(cat sagemaker-mlops/VERSION)" >> $GITHUB_OUTPUT + echo "pysdk=$(cat VERSION)" >> $GITHUB_OUTPUT + echo "meta=$(cat VERSION)" >> $GITHUB_OUTPUT + cat sagemaker-core/VERSION sagemaker-train/VERSION sagemaker-serve/VERSION \ + sagemaker-mlops/VERSION VERSION | paste - - - - - \ + | awk '{print "core="$1" train="$2" serve="$3" mlops="$4" pysdk/meta="$5}' - # ── 1. Wait for sagemaker-core (automerges on its own) ────────────────────── wait-sagemaker-core: needs: read-versions runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GH_PAT }} steps: - - name: Wait for sagemaker-core feedstock PR to merge + - name: Wait for sagemaker-core to merge (automerges on its own) run: | - VERSION="${{ needs.read-versions.outputs.core }}" REPO="conda-forge/sagemaker-core-feedstock" - echo "Waiting for: [bot-automerge] sagemaker-core v${VERSION}" - for i in $(seq 1 $MAX_ATTEMPTS); do + SEARCH="[bot-automerge] sagemaker-core v${{ needs.read-versions.outputs.core }}" + for i in $(seq 1 ${{ github.event.inputs.timeout_attempts }}); do STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-core v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') + --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') echo "Attempt $i: ${STATE}" [ "$STATE" = "MERGED" ] && exit 0 - sleep $POLL_INTERVAL + sleep ${{ github.event.inputs.poll_interval_seconds }} done echo "Timed out." && exit 1 - # ── 2. sagemaker-train ─────────────────────────────────────────────────────── release-sagemaker-train: needs: [read-versions, wait-sagemaker-core] - runs-on: ubuntu-latest - steps: - - name: Rerun failed checks - run: | - VERSION="${{ needs.read-versions.outputs.train }}" - REPO="conda-forge/sagemaker-train-feedstock" - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "sagemaker-train v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping rerun."; exit 0 - fi - PR=$(gh pr list --repo "$REPO" --state open \ - --search "sagemaker-train v${VERSION}" \ - --json number -q '.[0].number') - [ -z "$PR" ] && echo "No open PR found." && exit 1 - echo "PR #${PR}" - BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) - RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ - --json databaseId,conclusion -q \ - '[.[] | select(.conclusion=="failure")][0].databaseId') - [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ - || echo "No failed runs." - - name: Wait for merge - run: | - VERSION="${{ needs.read-versions.outputs.train }}" - REPO="conda-forge/sagemaker-train-feedstock" - for i in $(seq 1 $MAX_ATTEMPTS); do - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "sagemaker-train v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - echo "Attempt $i: ${STATE}" - [ "$STATE" = "MERGED" ] && exit 0 - sleep $POLL_INTERVAL - done - echo "Timed out." && exit 1 + uses: ./.github/workflows/_conda-forge-package-release.yml + with: + package: sagemaker-train + feedstock: conda-forge/sagemaker-train-feedstock + pr_search: "sagemaker-train v${{ needs.read-versions.outputs.train }}" + poll_interval: ${{ github.event.inputs.poll_interval_seconds }} + max_attempts: ${{ github.event.inputs.timeout_attempts }} + secrets: + token: ${{ secrets.GH_PAT }} - # ── 3. sagemaker-serve ─────────────────────────────────────────────────────── release-sagemaker-serve: needs: [read-versions, release-sagemaker-train] - runs-on: ubuntu-latest - steps: - - name: Rerun failed checks - run: | - VERSION="${{ needs.read-versions.outputs.serve }}" - REPO="conda-forge/sagemaker-serve-feedstock" - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "sagemaker-serve v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping rerun."; exit 0 - fi - PR=$(gh pr list --repo "$REPO" --state open \ - --search "sagemaker-serve v${VERSION}" \ - --json number -q '.[0].number') - [ -z "$PR" ] && echo "No open PR found." && exit 1 - BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) - RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ - --json databaseId,conclusion -q \ - '[.[] | select(.conclusion=="failure")][0].databaseId') - [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ - || echo "No failed runs." - - name: Wait for merge - run: | - VERSION="${{ needs.read-versions.outputs.serve }}" - REPO="conda-forge/sagemaker-serve-feedstock" - for i in $(seq 1 $MAX_ATTEMPTS); do - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "sagemaker-serve v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - echo "Attempt $i: ${STATE}" - [ "$STATE" = "MERGED" ] && exit 0 - sleep $POLL_INTERVAL - done - echo "Timed out." && exit 1 + uses: ./.github/workflows/_conda-forge-package-release.yml + with: + package: sagemaker-serve + feedstock: conda-forge/sagemaker-serve-feedstock + pr_search: "sagemaker-serve v${{ needs.read-versions.outputs.serve }}" + poll_interval: ${{ github.event.inputs.poll_interval_seconds }} + max_attempts: ${{ github.event.inputs.timeout_attempts }} + secrets: + token: ${{ secrets.GH_PAT }} - # ── 4. sagemaker-mlops ─────────────────────────────────────────────────────── release-sagemaker-mlops: needs: [read-versions, release-sagemaker-serve] - runs-on: ubuntu-latest - steps: - - name: Rerun failed checks - run: | - VERSION="${{ needs.read-versions.outputs.mlops }}" - REPO="conda-forge/sagemaker-mlops-feedstock" - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "sagemaker-mlops v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping rerun."; exit 0 - fi - PR=$(gh pr list --repo "$REPO" --state open \ - --search "sagemaker-mlops v${VERSION}" \ - --json number -q '.[0].number') - [ -z "$PR" ] && echo "No open PR found." && exit 1 - BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) - RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ - --json databaseId,conclusion -q \ - '[.[] | select(.conclusion=="failure")][0].databaseId') - [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ - || echo "No failed runs." - - name: Wait for merge - run: | - VERSION="${{ needs.read-versions.outputs.mlops }}" - REPO="conda-forge/sagemaker-mlops-feedstock" - for i in $(seq 1 $MAX_ATTEMPTS); do - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "sagemaker-mlops v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - echo "Attempt $i: ${STATE}" - [ "$STATE" = "MERGED" ] && exit 0 - sleep $POLL_INTERVAL - done - echo "Timed out." && exit 1 + uses: ./.github/workflows/_conda-forge-package-release.yml + with: + package: sagemaker-mlops + feedstock: conda-forge/sagemaker-mlops-feedstock + pr_search: "sagemaker-mlops v${{ needs.read-versions.outputs.mlops }}" + poll_interval: ${{ github.event.inputs.poll_interval_seconds }} + max_attempts: ${{ github.event.inputs.timeout_attempts }} + secrets: + token: ${{ secrets.GH_PAT }} - # ── 5. sagemaker-python-sdk-feedstock ─────────────────────────────────────── release-sagemaker-python-sdk: needs: [read-versions, release-sagemaker-mlops] - runs-on: ubuntu-latest - steps: - - name: Rerun failed checks - run: | - VERSION="${{ needs.read-versions.outputs.pysdk }}" - REPO="conda-forge/sagemaker-python-sdk-feedstock" - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping rerun."; exit 0 - fi - PR=$(gh pr list --repo "$REPO" --state open \ - --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ - --json number -q '.[0].number') - [ -z "$PR" ] && echo "No open PR found." && exit 1 - BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) - RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ - --json databaseId,conclusion -q \ - '[.[] | select(.conclusion=="failure")][0].databaseId') - [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ - || echo "No failed runs." - - name: Wait for merge - run: | - VERSION="${{ needs.read-versions.outputs.pysdk }}" - REPO="conda-forge/sagemaker-python-sdk-feedstock" - for i in $(seq 1 $MAX_ATTEMPTS); do - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker-python-sdk v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - echo "Attempt $i: ${STATE}" - [ "$STATE" = "MERGED" ] && exit 0 - sleep $POLL_INTERVAL - done - echo "Timed out." && exit 1 + uses: ./.github/workflows/_conda-forge-package-release.yml + with: + package: sagemaker-python-sdk + feedstock: conda-forge/sagemaker-python-sdk-feedstock + pr_search: "[bot-automerge] sagemaker-python-sdk v${{ needs.read-versions.outputs.pysdk }}" + poll_interval: ${{ github.event.inputs.poll_interval_seconds }} + max_attempts: ${{ github.event.inputs.timeout_attempts }} + secrets: + token: ${{ secrets.GH_PAT }} - # ── 6. sagemaker (meta-package) ────────────────────────────────────────────── release-sagemaker: needs: [read-versions, release-sagemaker-python-sdk] - runs-on: ubuntu-latest - steps: - - name: Rerun failed checks - run: | - VERSION="${{ needs.read-versions.outputs.meta }}" - REPO="conda-forge/sagemaker-feedstock" - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping rerun."; exit 0 - fi - PR=$(gh pr list --repo "$REPO" --state open \ - --search "[bot-automerge] sagemaker v${VERSION}" \ - --json number -q '.[0].number') - [ -z "$PR" ] && echo "No open PR found." && exit 1 - BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) - RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ - --json databaseId,conclusion -q \ - '[.[] | select(.conclusion=="failure")][0].databaseId') - [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ - || echo "No failed runs." - - name: Wait for merge - run: | - VERSION="${{ needs.read-versions.outputs.meta }}" - REPO="conda-forge/sagemaker-feedstock" - for i in $(seq 1 $MAX_ATTEMPTS); do - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "[bot-automerge] sagemaker v${VERSION}" \ - --json state -q '.[0].state // "NOT_FOUND"') - echo "Attempt $i: ${STATE}" - [ "$STATE" = "MERGED" ] && exit 0 - sleep $POLL_INTERVAL - done - echo "Timed out." && exit 1 - - - name: Release chain complete - run: | - echo "All packages released on conda-forge:" - echo " sagemaker-core ${{ needs.read-versions.outputs.core }}" - echo " sagemaker-train ${{ needs.read-versions.outputs.train }}" - echo " sagemaker-serve ${{ needs.read-versions.outputs.serve }}" - echo " sagemaker-mlops ${{ needs.read-versions.outputs.mlops }}" - echo " sagemaker-python-sdk ${{ needs.read-versions.outputs.pysdk }}" - echo " sagemaker ${{ needs.read-versions.outputs.meta }}" + uses: ./.github/workflows/_conda-forge-package-release.yml + with: + package: sagemaker + feedstock: conda-forge/sagemaker-feedstock + pr_search: "[bot-automerge] sagemaker v${{ needs.read-versions.outputs.meta }}" + poll_interval: ${{ github.event.inputs.poll_interval_seconds }} + max_attempts: ${{ github.event.inputs.timeout_attempts }} + secrets: + token: ${{ secrets.GH_PAT }} From 5a451327992a957e19ef112bbfed54c54f72fadd Mon Sep 17 00:00:00 2001 From: Molly He Date: Mon, 23 Mar 2026 14:48:50 -0700 Subject: [PATCH 5/9] Update logic to modular, pending testing for next release --- .../_conda-forge-package-release.yml | 40 ++++++++++-- .../workflows/conda-forge-release-chain.yml | 65 ++++++++++--------- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/.github/workflows/_conda-forge-package-release.yml b/.github/workflows/_conda-forge-package-release.yml index 0a54f03ca5..ed03f00af9 100644 --- a/.github/workflows/_conda-forge-package-release.yml +++ b/.github/workflows/_conda-forge-package-release.yml @@ -4,7 +4,7 @@ on: workflow_call: inputs: package: - description: 'Package name (e.g. sagemaker-train)' + description: 'Package being released (e.g. sagemaker-train)' required: true type: string feedstock: @@ -15,6 +15,18 @@ on: description: 'PR title search string (e.g. sagemaker-train v1.6.0)' required: true type: string + version: + description: 'Version of this package being released (e.g. 1.6.0)' + required: true + type: string + dep_package: + description: 'Conda dependency to wait for before retrying CI (e.g. sagemaker-core)' + required: true + type: string + dep_version: + description: 'Version of the dependency to wait for (e.g. 2.6.0)' + required: true + type: string poll_interval: required: true type: string @@ -31,15 +43,31 @@ jobs: env: GH_TOKEN: ${{ secrets.token }} steps: - - name: Rerun failed checks or skip if already merged + - name: Wait for dependency (${{ inputs.dep_package }}==${{ inputs.dep_version }}) on conda-forge + run: | + PACKAGE="${{ inputs.dep_package }}" + VERSION="${{ inputs.dep_version }}" + echo "Waiting for ${PACKAGE}==${VERSION} on conda-forge..." + for i in $(seq 1 ${{ inputs.max_attempts }}); do + RESULT=$(conda search -c conda-forge --override-channels \ + "${PACKAGE}==${VERSION}" --json 2>/dev/null \ + | python3 -c "import sys,json; d=json.load(sys.stdin); print('found' if d.get('$PACKAGE') else 'not_found')" \ + 2>/dev/null || echo "not_found") + echo "Attempt $i: ${RESULT}" + [ "$RESULT" = "found" ] && echo "${PACKAGE}==${VERSION} is available." && exit 0 + sleep ${{ inputs.poll_interval }} + done + echo "Timed out waiting for ${PACKAGE}==${VERSION}." && exit 1 + + - name: Rerun failed checks on ${{ inputs.package }} feedstock PR run: | REPO="${{ inputs.feedstock }}" SEARCH="${{ inputs.pr_search }}" STATE=$(gh pr list --repo "$REPO" --state all \ --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') - echo "Current state: ${STATE}" + echo "PR state: ${STATE}" if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping."; exit 0 + echo "Already merged, skipping rerun."; exit 0 fi PR=$(gh pr list --repo "$REPO" --state open \ --search "$SEARCH" --json number -q '.[0].number') @@ -52,7 +80,7 @@ jobs: [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ || echo "No failed runs." - - name: Wait for merge + - name: Wait for ${{ inputs.package }} feedstock PR to merge run: | REPO="${{ inputs.feedstock }}" SEARCH="${{ inputs.pr_search }}" @@ -63,4 +91,4 @@ jobs: [ "$STATE" = "MERGED" ] && exit 0 sleep ${{ inputs.poll_interval }} done - echo "Timed out waiting for ${{ inputs.package }}." && exit 1 + echo "Timed out waiting for ${{ inputs.package }} PR to merge." && exit 1 diff --git a/.github/workflows/conda-forge-release-chain.yml b/.github/workflows/conda-forge-release-chain.yml index 6f515c2617..8c49014b74 100644 --- a/.github/workflows/conda-forge-release-chain.yml +++ b/.github/workflows/conda-forge-release-chain.yml @@ -8,9 +8,9 @@ on: required: false default: '300' timeout_attempts: - description: 'Max poll attempts per package before failing (default: 60 = 5hrs at 300s)' + description: 'Max poll attempts per package before failing (default: 20 = 100min at 300s)' required: false - default: '60' + default: '20' jobs: read-versions: @@ -33,41 +33,31 @@ jobs: echo "mlops=$(cat sagemaker-mlops/VERSION)" >> $GITHUB_OUTPUT echo "pysdk=$(cat VERSION)" >> $GITHUB_OUTPUT echo "meta=$(cat VERSION)" >> $GITHUB_OUTPUT - cat sagemaker-core/VERSION sagemaker-train/VERSION sagemaker-serve/VERSION \ - sagemaker-mlops/VERSION VERSION | paste - - - - - \ - | awk '{print "core="$1" train="$2" serve="$3" mlops="$4" pysdk/meta="$5}' - - wait-sagemaker-core: - needs: read-versions - runs-on: ubuntu-latest - env: - GH_TOKEN: ${{ secrets.GH_PAT }} - steps: - - name: Wait for sagemaker-core to merge (automerges on its own) - run: | - REPO="conda-forge/sagemaker-core-feedstock" - SEARCH="[bot-automerge] sagemaker-core v${{ needs.read-versions.outputs.core }}" - for i in $(seq 1 ${{ github.event.inputs.timeout_attempts }}); do - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') - echo "Attempt $i: ${STATE}" - [ "$STATE" = "MERGED" ] && exit 0 - sleep ${{ github.event.inputs.poll_interval_seconds }} - done - echo "Timed out." && exit 1 + echo "Versions:" + echo " sagemaker-core: $(cat sagemaker-core/VERSION)" + echo " sagemaker-train: $(cat sagemaker-train/VERSION)" + echo " sagemaker-serve: $(cat sagemaker-serve/VERSION)" + echo " sagemaker-mlops: $(cat sagemaker-mlops/VERSION)" + echo " sagemaker-python-sdk: $(cat VERSION)" + echo " sagemaker (meta): $(cat VERSION)" + # sagemaker-train waits for sagemaker-core release-sagemaker-train: - needs: [read-versions, wait-sagemaker-core] + needs: read-versions uses: ./.github/workflows/_conda-forge-package-release.yml with: package: sagemaker-train feedstock: conda-forge/sagemaker-train-feedstock pr_search: "sagemaker-train v${{ needs.read-versions.outputs.train }}" + version: ${{ needs.read-versions.outputs.train }} + dep_package: sagemaker-core + dep_version: ${{ needs.read-versions.outputs.core }} poll_interval: ${{ github.event.inputs.poll_interval_seconds }} max_attempts: ${{ github.event.inputs.timeout_attempts }} secrets: - token: ${{ secrets.GH_PAT }} + token: ${{ secrets.CONDA_FORGE_RELEASE }} + # sagemaker-serve waits for sagemaker-train release-sagemaker-serve: needs: [read-versions, release-sagemaker-train] uses: ./.github/workflows/_conda-forge-package-release.yml @@ -75,11 +65,15 @@ jobs: package: sagemaker-serve feedstock: conda-forge/sagemaker-serve-feedstock pr_search: "sagemaker-serve v${{ needs.read-versions.outputs.serve }}" + version: ${{ needs.read-versions.outputs.serve }} + dep_package: sagemaker-train + dep_version: ${{ needs.read-versions.outputs.train }} poll_interval: ${{ github.event.inputs.poll_interval_seconds }} max_attempts: ${{ github.event.inputs.timeout_attempts }} secrets: - token: ${{ secrets.GH_PAT }} + token: ${{ secrets.CONDA_FORGE_RELEASE }} + # sagemaker-mlops waits for sagemaker-serve release-sagemaker-mlops: needs: [read-versions, release-sagemaker-serve] uses: ./.github/workflows/_conda-forge-package-release.yml @@ -87,11 +81,15 @@ jobs: package: sagemaker-mlops feedstock: conda-forge/sagemaker-mlops-feedstock pr_search: "sagemaker-mlops v${{ needs.read-versions.outputs.mlops }}" + version: ${{ needs.read-versions.outputs.mlops }} + dep_package: sagemaker-serve + dep_version: ${{ needs.read-versions.outputs.serve }} poll_interval: ${{ github.event.inputs.poll_interval_seconds }} max_attempts: ${{ github.event.inputs.timeout_attempts }} secrets: - token: ${{ secrets.GH_PAT }} + token: ${{ secrets.CONDA_FORGE_RELEASE }} + # sagemaker-python-sdk waits for sagemaker-mlops release-sagemaker-python-sdk: needs: [read-versions, release-sagemaker-mlops] uses: ./.github/workflows/_conda-forge-package-release.yml @@ -99,11 +97,15 @@ jobs: package: sagemaker-python-sdk feedstock: conda-forge/sagemaker-python-sdk-feedstock pr_search: "[bot-automerge] sagemaker-python-sdk v${{ needs.read-versions.outputs.pysdk }}" + version: ${{ needs.read-versions.outputs.pysdk }} + dep_package: sagemaker-mlops + dep_version: ${{ needs.read-versions.outputs.mlops }} poll_interval: ${{ github.event.inputs.poll_interval_seconds }} max_attempts: ${{ github.event.inputs.timeout_attempts }} secrets: - token: ${{ secrets.GH_PAT }} + token: ${{ secrets.CONDA_FORGE_RELEASE }} + # sagemaker (meta) waits for sagemaker-python-sdk release-sagemaker: needs: [read-versions, release-sagemaker-python-sdk] uses: ./.github/workflows/_conda-forge-package-release.yml @@ -111,7 +113,10 @@ jobs: package: sagemaker feedstock: conda-forge/sagemaker-feedstock pr_search: "[bot-automerge] sagemaker v${{ needs.read-versions.outputs.meta }}" + version: ${{ needs.read-versions.outputs.meta }} + dep_package: sagemaker-python-sdk + dep_version: ${{ needs.read-versions.outputs.pysdk }} poll_interval: ${{ github.event.inputs.poll_interval_seconds }} max_attempts: ${{ github.event.inputs.timeout_attempts }} secrets: - token: ${{ secrets.GH_PAT }} + token: ${{ secrets.CONDA_FORGE_RELEASE }} From 2cc908dbc9b20910ad2a2848cf0b6a337abdb3d7 Mon Sep 17 00:00:00 2001 From: Molly He Date: Thu, 26 Mar 2026 10:46:27 -0700 Subject: [PATCH 6/9] Update merge PR --- .github/workflows/_conda-forge-package-release.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/_conda-forge-package-release.yml b/.github/workflows/_conda-forge-package-release.yml index ed03f00af9..a8c9de50a4 100644 --- a/.github/workflows/_conda-forge-package-release.yml +++ b/.github/workflows/_conda-forge-package-release.yml @@ -80,7 +80,7 @@ jobs: [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ || echo "No failed runs." - - name: Wait for ${{ inputs.package }} feedstock PR to merge + - name: Merge and wait for ${{ inputs.package }} feedstock PR run: | REPO="${{ inputs.feedstock }}" SEARCH="${{ inputs.pr_search }}" @@ -89,6 +89,11 @@ jobs: --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') echo "Attempt $i: ${STATE}" [ "$STATE" = "MERGED" ] && exit 0 + PR=$(gh pr list --repo "$REPO" --state open \ + --search "$SEARCH" --json number -q '.[0].number') + if [ -n "$PR" ]; then + gh pr merge "$PR" --repo "$REPO" --merge --auto 2>/dev/null || true + fi sleep ${{ inputs.poll_interval }} done echo "Timed out waiting for ${{ inputs.package }} PR to merge." && exit 1 From 3a5e76280fc101463e6a648709b52bc27a713137 Mon Sep 17 00:00:00 2001 From: Molly He Date: Thu, 26 Mar 2026 13:47:36 -0700 Subject: [PATCH 7/9] Update wait for PR test run before merge --- .../_conda-forge-package-release.yml | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/.github/workflows/_conda-forge-package-release.yml b/.github/workflows/_conda-forge-package-release.yml index a8c9de50a4..dcddf69c5a 100644 --- a/.github/workflows/_conda-forge-package-release.yml +++ b/.github/workflows/_conda-forge-package-release.yml @@ -59,27 +59,6 @@ jobs: done echo "Timed out waiting for ${PACKAGE}==${VERSION}." && exit 1 - - name: Rerun failed checks on ${{ inputs.package }} feedstock PR - run: | - REPO="${{ inputs.feedstock }}" - SEARCH="${{ inputs.pr_search }}" - STATE=$(gh pr list --repo "$REPO" --state all \ - --search "$SEARCH" --json state -q '.[0].state // "NOT_FOUND"') - echo "PR state: ${STATE}" - if [ "$STATE" = "MERGED" ]; then - echo "Already merged, skipping rerun."; exit 0 - fi - PR=$(gh pr list --repo "$REPO" --state open \ - --search "$SEARCH" --json number -q '.[0].number') - [ -z "$PR" ] && echo "No open PR found." && exit 1 - echo "PR #${PR}" - BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) - RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ - --json databaseId,conclusion -q \ - '[.[] | select(.conclusion=="failure")][0].databaseId') - [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed \ - || echo "No failed runs." - - name: Merge and wait for ${{ inputs.package }} feedstock PR run: | REPO="${{ inputs.feedstock }}" @@ -92,7 +71,21 @@ jobs: PR=$(gh pr list --repo "$REPO" --state open \ --search "$SEARCH" --json number -q '.[0].number') if [ -n "$PR" ]; then - gh pr merge "$PR" --repo "$REPO" --merge --auto 2>/dev/null || true + CI_STATUS=$(gh pr view "$PR" --repo "$REPO" \ + --json statusCheckRollup -q \ + '[.statusCheckRollup[].conclusion] | if length == 0 then "pending" elif all(. == "SUCCESS") then "success" else "failure" end') + echo "CI status: ${CI_STATUS}" + if [ "$CI_STATUS" = "success" ]; then + echo "CI passed, merging PR #${PR}..." + gh pr merge "$PR" --repo "$REPO" --merge 2>/dev/null || true + elif [ "$CI_STATUS" = "failure" ]; then + echo "CI failed, retriggering..." + BRANCH=$(gh pr view "$PR" --repo "$REPO" --json headRefName -q .headRefName) + RUN_ID=$(gh run list --repo "$REPO" --branch "$BRANCH" \ + --json databaseId,conclusion -q \ + '[.[] | select(.conclusion=="failure")][0].databaseId') + [ -n "$RUN_ID" ] && gh run rerun "$RUN_ID" --repo "$REPO" --failed || true + fi fi sleep ${{ inputs.poll_interval }} done From 3bca0963f54436d4de032af7a7fcf6a2c40225bc Mon Sep 17 00:00:00 2001 From: Molly He Date: Thu, 26 Mar 2026 14:44:28 -0700 Subject: [PATCH 8/9] Update checking latest run result --- .github/workflows/_conda-forge-package-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_conda-forge-package-release.yml b/.github/workflows/_conda-forge-package-release.yml index dcddf69c5a..8d833f7d22 100644 --- a/.github/workflows/_conda-forge-package-release.yml +++ b/.github/workflows/_conda-forge-package-release.yml @@ -73,7 +73,7 @@ jobs: if [ -n "$PR" ]; then CI_STATUS=$(gh pr view "$PR" --repo "$REPO" \ --json statusCheckRollup -q \ - '[.statusCheckRollup[].conclusion] | if length == 0 then "pending" elif all(. == "SUCCESS") then "success" else "failure" end') + '[.statusCheckRollup | group_by(.name) | map(sort_by(.startedAt) | last | .conclusion) | if length == 0 then "pending" elif all(. == "SUCCESS") then "success" elif any(. == null or . == "") then "pending" else "failure" end][-1]') echo "CI status: ${CI_STATUS}" if [ "$CI_STATUS" = "success" ]; then echo "CI passed, merging PR #${PR}..." From 35b6c807c1b3a8afe1731bf93cf1437043c87026 Mon Sep 17 00:00:00 2001 From: Molly He Date: Thu, 26 Mar 2026 15:19:45 -0700 Subject: [PATCH 9/9] Update check run status: --- .github/workflows/_conda-forge-package-release.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/_conda-forge-package-release.yml b/.github/workflows/_conda-forge-package-release.yml index 8d833f7d22..347489124e 100644 --- a/.github/workflows/_conda-forge-package-release.yml +++ b/.github/workflows/_conda-forge-package-release.yml @@ -72,8 +72,15 @@ jobs: --search "$SEARCH" --json number -q '.[0].number') if [ -n "$PR" ]; then CI_STATUS=$(gh pr view "$PR" --repo "$REPO" \ - --json statusCheckRollup -q \ - '[.statusCheckRollup | group_by(.name) | map(sort_by(.startedAt) | last | .conclusion) | if length == 0 then "pending" elif all(. == "SUCCESS") then "success" elif any(. == null or . == "") then "pending" else "failure" end][-1]') + --json statusCheckRollup -q ' + .statusCheckRollup | map( + if .__typename == "CheckRun" then .conclusion + elif .__typename == "StatusContext" then .state + else null end + ) | if length == 0 then "pending" + elif any(. == null or . == "" or . == "IN_PROGRESS" or . == "QUEUED" or . == "WAITING" or . == "PENDING") then "pending" + elif all(. == "SUCCESS") then "success" + else "failure" end') echo "CI status: ${CI_STATUS}" if [ "$CI_STATUS" = "success" ]; then echo "CI passed, merging PR #${PR}..."