release: v3.1.1 — dead RPC endpoints, mainnetFork typing, CI correctness #23
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: Scaffold Stark React Native Sync and Update | |
| on: | |
| pull_request: | |
| types: [closed] | |
| branches: [main] | |
| push: | |
| branches: [develop] | |
| paths: | |
| - '.tool-versions' | |
| - '**/package.json' | |
| - 'yarn.lock' | |
| - '**/Scarb.toml' | |
| - '**/Scarb.lock' | |
| - 'README.md' | |
| workflow_dispatch: | |
| inputs: | |
| source_ref: | |
| description: 'Source ref of scaffold-stark-2 to sync from (branch, tag, or SHA)' | |
| required: false | |
| default: 'main' | |
| type: string | |
| permissions: | |
| contents: read | |
| jobs: | |
| check_commit: | |
| if: github.event_name != 'pull_request' || github.event.pull_request.merged == true | |
| runs-on: ubuntu-latest | |
| outputs: | |
| SHOULD_RUN: ${{ steps.check_commit.outputs.SHOULD_RUN }} | |
| SOURCE_REF: ${{ steps.source.outputs.SOURCE_REF }} | |
| steps: | |
| - name: Checkout Files | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.ORG_GITHUB_TOKEN }} | |
| - name: check if skip ci | |
| id: check_commit | |
| run: | | |
| COMMIT_MESSAGE=$(git log -1 --pretty=%B) | |
| if [[ "$COMMIT_MESSAGE" == *"[skip ci]"* ]]; then | |
| echo "SHOULD_RUN=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "SHOULD_RUN=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Resolve source ref | |
| id: source | |
| run: | | |
| case "${{ github.event_name }}" in | |
| workflow_dispatch) | |
| REF="${{ inputs.source_ref }}" | |
| ;; | |
| push) | |
| REF="${{ github.ref_name }}" | |
| ;; | |
| *) | |
| REF="main" | |
| ;; | |
| esac | |
| echo "SOURCE_REF=$REF" >> "$GITHUB_OUTPUT" | |
| echo "Resolved source ref: $REF" | |
| sync-speedrun: | |
| needs: check_commit | |
| if: ${{ needs.check_commit.outputs.SHOULD_RUN != 'false' }} | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Checkout Source Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: Scaffold-Stark/scaffold-stark-2 | |
| ref: ${{ needs.check_commit.outputs.SOURCE_REF }} | |
| token: ${{ secrets.ORG_GITHUB_TOKEN }} | |
| path: source_repo | |
| - name: Checkout Destination Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: Scaffold-Stark/scaffold-stark-rn | |
| token: ${{ secrets.ORG_GITHUB_TOKEN }} | |
| path: destination_repo | |
| fetch-depth: 0 | |
| - name: Setup Git | |
| run: | | |
| git config --global user.name 'github-actions[bot]' | |
| git config --global user.email 'github-actions[bot]@users.noreply.github.com' | |
| - name: Sync to temp branch | |
| id: sync | |
| env: | |
| SOURCE_REF: ${{ needs.check_commit.outputs.SOURCE_REF }} | |
| run: | | |
| set -e | |
| cd destination_repo | |
| SHORT_SHA=$(cd ../source_repo && git rev-parse --short HEAD) | |
| SOURCE_SHA=$(cd ../source_repo && git rev-parse HEAD) | |
| # Sanitize ref for branch name (slashes are fine in git refs but keep readable) | |
| SAFE_REF=$(echo "$SOURCE_REF" | tr '/' '-') | |
| TEMP_BRANCH="sync/from-${SAFE_REF}-${SHORT_SHA}" | |
| git fetch origin develop | |
| git checkout -B "$TEMP_BRANCH" origin/develop | |
| cp -f ../source_repo/.tool-versions ./.tool-versions | |
| # --exclude='.claude/' is a no-op today: this rsync's source is packages/snfoundry/, | |
| # a subdirectory, while .claude/ lives at the repo root and is never inside that path. | |
| # Kept anyway as defense-in-depth so the guard is already in place if this source is | |
| # ever broadened to the full repo tree. | |
| rsync -av --exclude='.claude/' ../source_repo/packages/snfoundry/ ./packages/snfoundry/ | |
| # rn-fork rewrites: structural deltas between scaffold-stark-2 and scaffold-stark-rn. | |
| # Each rewrite is gated by a grep sanity check so upstream renames surface as a conflict PR | |
| # instead of silently no-op'ing. | |
| CONFLICT=false | |
| REASON="" | |
| PKG_JSON=./packages/snfoundry/package.json | |
| PARSE_DEPLOY=./packages/snfoundry/scripts-ts/helpers/parse-deployments.ts | |
| VERIFY_CONTRACTS=./packages/snfoundry/scripts-ts/verify-contracts.ts | |
| if [ ! -f "$PKG_JSON" ]; then | |
| CONFLICT=true | |
| REASON="$PKG_JSON not found after rsync — upstream layout changed." | |
| elif ! grep -q '@ss-2/snfoundry' "$PKG_JSON"; then | |
| CONFLICT=true | |
| REASON="grep '@ss-2/snfoundry' not found in $PKG_JSON — upstream may have renamed the package." | |
| fi | |
| if [ "$CONFLICT" != "true" ]; then | |
| if [ ! -f "$PARSE_DEPLOY" ]; then | |
| CONFLICT=true | |
| REASON="$PARSE_DEPLOY not found after rsync — upstream layout changed." | |
| elif ! grep -q 'nextjs/contracts' "$PARSE_DEPLOY"; then | |
| CONFLICT=true | |
| REASON="grep 'nextjs/contracts' not found in $PARSE_DEPLOY — upstream may have moved the contracts target dir." | |
| fi | |
| fi | |
| if [ "$CONFLICT" != "true" ]; then | |
| if [ ! -f "$VERIFY_CONTRACTS" ]; then | |
| CONFLICT=true | |
| REASON="$VERIFY_CONTRACTS not found after rsync — upstream layout changed." | |
| elif ! grep -q 'nextjs/contracts' "$VERIFY_CONTRACTS"; then | |
| CONFLICT=true | |
| REASON="grep 'nextjs/contracts' not found in $VERIFY_CONTRACTS — upstream may have moved the contracts target dir." | |
| fi | |
| fi | |
| if [ "$CONFLICT" != "true" ]; then | |
| sed -i 's|@ss-2/snfoundry|@ss-rn/snfoundry|g' "$PKG_JSON" | |
| sed -i 's|nextjs/contracts|rn/contracts|g' "$PARSE_DEPLOY" | |
| sed -i 's|nextjs/contracts|rn/contracts|g' "$VERIFY_CONTRACTS" | |
| # Post-rewrite verification: ensure the old strings are gone. | |
| if grep -q '@ss-2/snfoundry' "$PKG_JSON" || grep -q 'nextjs/contracts' "$PARSE_DEPLOY" || grep -q 'nextjs/contracts' "$VERIFY_CONTRACTS"; then | |
| CONFLICT=true | |
| REASON="sed rewrites left residual @ss-2/snfoundry or nextjs/contracts references — manual review required." | |
| fi | |
| fi | |
| if [ "$CONFLICT" = "true" ]; then | |
| echo "::warning::rn-fork sed rewrites failed sanity check; staging partial sync for manual review." | |
| echo "$REASON" | |
| fi | |
| if [ -n "$(git status --porcelain)" ]; then | |
| git add -A | |
| git commit -m "chore: sync files from scaffold-stark-2 (${SOURCE_REF} @ ${SHORT_SHA})" | |
| git push --force-with-lease origin "$TEMP_BRANCH" | |
| NOOP=false | |
| else | |
| echo "No changes to sync; destination already at parity." | |
| NOOP=true | |
| fi | |
| { | |
| echo "TEMP_BRANCH=$TEMP_BRANCH" | |
| echo "SOURCE_SHA=$SOURCE_SHA" | |
| echo "SHORT_SHA=$SHORT_SHA" | |
| echo "CONFLICT=$CONFLICT" | |
| echo "NOOP=$NOOP" | |
| echo 'REASON<<REASON_EOF' | |
| echo "${REASON:-Sed rewrites applied cleanly.}" | |
| echo 'REASON_EOF' | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Finalize sync (fast-forward or open PR) | |
| id: finalize | |
| if: steps.sync.outputs.NOOP != 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }} | |
| DEST_REPO: Scaffold-Stark/scaffold-stark-rn | |
| PROD_BRANCH: develop | |
| TEMP_BRANCH: ${{ steps.sync.outputs.TEMP_BRANCH }} | |
| SOURCE_SHA: ${{ steps.sync.outputs.SOURCE_SHA }} | |
| SHORT_SHA: ${{ steps.sync.outputs.SHORT_SHA }} | |
| SOURCE_REF: ${{ needs.check_commit.outputs.SOURCE_REF }} | |
| REASON: ${{ steps.sync.outputs.REASON }} | |
| CONFLICT: ${{ steps.sync.outputs.CONFLICT }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| set -e | |
| cd destination_repo | |
| if [ "$CONFLICT" = "true" ]; then | |
| gh label create sync-conflict --color b60205 \ | |
| --description "Sync from scaffold-stark-2 hit a conflict needing manual resolution" \ | |
| --force --repo "$DEST_REPO" | |
| gh label create needs-review --color fbca04 \ | |
| --description "Awaiting human review" \ | |
| --force --repo "$DEST_REPO" | |
| BODY_FILE=$(mktemp) | |
| { | |
| echo "## Automated sync conflict from scaffold-stark-2" | |
| echo | |
| echo "The sync workflow's rn-fork sed rewrites failed a sanity check against the rsync'd tree from \`scaffold-stark-2\`. Partial changes (rsync of \`packages/snfoundry/\` and \`.tool-versions\`) have been committed to this branch so the failure can be inspected against the latest tree." | |
| echo | |
| echo "| Field | Value |" | |
| echo "| --- | --- |" | |
| echo "| Source ref | \`$SOURCE_REF\` |" | |
| echo "| Source SHA | \`$SOURCE_SHA\` |" | |
| echo "| Trigger | \`$EVENT_NAME\` |" | |
| echo "| Failing step | sed-based rn-fork rewrites (sanity check). Reason: $REASON |" | |
| echo | |
| echo "### Sanity-check reason" | |
| echo | |
| echo '```' | |
| echo "$REASON" | |
| echo '```' | |
| echo | |
| echo "### Manual resolution" | |
| echo | |
| echo "1. \`git fetch origin && git checkout $TEMP_BRANCH\`" | |
| echo "2. Inspect the sed targets in \`.github/workflows/sync-rn-repo.yaml\` (the \"Sync to temp branch\" step) and the upstream files in \`scaffold-stark-2\`. If upstream renamed \`@ss-2/snfoundry\` or moved \`nextjs/contracts\`, update the sed patterns and grep sanity checks in the workflow. Otherwise resolve manually on this branch." | |
| echo "3. Resolve conflicts, amend the sync commit, force-push." | |
| echo "4. When CI is green, merge this PR into \`$PROD_BRANCH\`." | |
| } > "$BODY_FILE" | |
| EXISTING=$(gh pr list --repo "$DEST_REPO" --head "$TEMP_BRANCH" --base "$PROD_BRANCH" --state open --json number --jq '.[0].number // empty') | |
| if [ -n "$EXISTING" ]; then | |
| gh pr edit "$EXISTING" --repo "$DEST_REPO" --body-file "$BODY_FILE" | |
| echo "Updated existing conflict PR #$EXISTING" | |
| else | |
| gh pr create --repo "$DEST_REPO" \ | |
| --base "$PROD_BRANCH" \ | |
| --head "$TEMP_BRANCH" \ | |
| --title "Sync conflict from ${SOURCE_REF}@${SHORT_SHA}" \ | |
| --label sync-conflict \ | |
| --label needs-review \ | |
| --body-file "$BODY_FILE" | |
| fi | |
| rm -f "$BODY_FILE" | |
| echo "OUTCOME=pr_opened" >> "$GITHUB_OUTPUT" | |
| else | |
| git fetch origin "$PROD_BRANCH" "$TEMP_BRANCH" | |
| git checkout "$PROD_BRANCH" | |
| git merge --ff-only "origin/$TEMP_BRANCH" | |
| git push origin "$PROD_BRANCH" | |
| git push origin --delete "$TEMP_BRANCH" | |
| echo "OUTCOME=fast_forwarded" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Notify Slack on fast-forward sync | |
| if: success() && steps.finalize.outputs.OUTCOME == 'fast_forwarded' | |
| uses: slackapi/slack-github-action@v1.26.0 | |
| with: | |
| channel-id: ${{ secrets.SLACK_CHANNEL_ID }} | |
| slack-message: "Successfully synced scaffold-stark-2 (${{ needs.check_commit.outputs.SOURCE_REF }}@${{ steps.sync.outputs.SHORT_SHA }}) to scaffold-stark-rn develop." | |
| env: | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} | |
| - name: Notify Slack on conflict PR opened | |
| if: success() && steps.finalize.outputs.OUTCOME == 'pr_opened' | |
| uses: slackapi/slack-github-action@v1.26.0 | |
| with: | |
| channel-id: ${{ secrets.SLACK_CHANNEL_ID }} | |
| slack-message: "scaffold-stark-rn sync from ${{ needs.check_commit.outputs.SOURCE_REF }}@${{ steps.sync.outputs.SHORT_SHA }} hit a sync conflict (sed sanity check failed). Opened PR for manual review on branch ${{ steps.sync.outputs.TEMP_BRANCH }}." | |
| env: | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} | |
| - name: Notify Slack on no-op sync | |
| if: success() && steps.sync.outputs.NOOP == 'true' | |
| uses: slackapi/slack-github-action@v1.26.0 | |
| with: | |
| channel-id: ${{ secrets.SLACK_CHANNEL_ID }} | |
| slack-message: "scaffold-stark-rn sync from ${{ needs.check_commit.outputs.SOURCE_REF }}@${{ steps.sync.outputs.SHORT_SHA }}: no changes to apply." | |
| env: | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} | |
| - name: Notify Slack on Failure | |
| if: failure() | |
| uses: slackapi/slack-github-action@v1.26.0 | |
| with: | |
| channel-id: ${{ secrets.SLACK_CHANNEL_ID }} | |
| slack-message: "Failed to sync scaffold-stark-2 changes to scaffold-stark-rn repository (workflow error, not a sync conflict)." | |
| env: | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} |