fix: clear the terminal before the install intro animation (#10) #53
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: Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| concurrency: ${{ github.workflow }}-${{ github.ref }} | |
| jobs: | |
| # Publishing to npm is irreversible — never let a commit that fails CI or | |
| # Nix Build ship. Those workflows run in parallel on the same push, so this | |
| # job blocks the release until both conclude successfully for this SHA. | |
| wait-for-checks: | |
| name: Wait for CI and Nix Build | |
| runs-on: ubuntu-latest | |
| if: github.repository_owner == 'Pythoughts-labs' | |
| timeout-minutes: 45 | |
| permissions: | |
| actions: read | |
| contents: read | |
| steps: | |
| - name: Wait for required workflows on this commit | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| SHA: ${{ github.sha }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| for workflow in "CI" "Nix Build"; do | |
| echo "Waiting for workflow: $workflow" | |
| while true; do | |
| # Transient API failures must not kill the gate (step shell is -e). | |
| pair=$(gh api "repos/$REPO/actions/runs?head_sha=$SHA&per_page=50" \ | |
| --jq "[.workflow_runs[] | select(.name==\"$workflow\")][0] | \"\(.status)/\(.conclusion)\"" \ | |
| 2>/dev/null) || pair="api-error/null" | |
| case "$pair" in | |
| completed/success) | |
| echo "$workflow: success"; break ;; | |
| completed/*) | |
| echo "::error::$workflow concluded '${pair#completed/}' for $SHA — refusing to release." | |
| exit 1 ;; | |
| *) | |
| echo "$workflow: $pair — waiting..."; sleep 30 ;; | |
| esac | |
| done | |
| done | |
| release: | |
| name: Release | |
| needs: wait-for-checks | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| if: github.repository_owner == 'Pythoughts-labs' | |
| outputs: | |
| packages_published: ${{ steps.changesets.outputs.published }} | |
| pythinker_native_release: ${{ steps.pythinker-release.outputs.should_publish }} | |
| pythinker_release_tag: ${{ steps.pythinker-release.outputs.tag }} | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| id-token: write # Required for NPM Trusted Publishing (OIDC) | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: "pnpm" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Upgrade npm for Trusted Publishing | |
| run: npm install -g npm@latest | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Generate Pythinker Code built-in catalog | |
| shell: bash | |
| run: | | |
| CATALOG_FILE="$RUNNER_TEMP/pythinker-code-built-in-catalog.json" | |
| node apps/pythinker-code/scripts/update-catalog.mjs --out "$CATALOG_FILE" | |
| echo "PYTHINKER_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV" | |
| - name: Build packages | |
| run: pnpm build | |
| - name: Mint release-bot token | |
| id: release-bot | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.RELEASE_BOT_APP_ID }} | |
| private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }} | |
| - name: Create Release Pull Request or Publish to npm | |
| id: changesets | |
| uses: changesets/action@v1 | |
| with: | |
| publish: node scripts/release/changeset-publish-idempotent.mjs | |
| version: pnpm run version:release | |
| commit: "ci: release packages" | |
| title: "ci: release packages" | |
| env: | |
| # App token (not GITHUB_TOKEN) so the version PR triggers pull_request | |
| # workflows and required status checks / CodeRabbit run on it. | |
| GITHUB_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| # No NPM_TOKEN on purpose: changesets prefers it over OIDC when set, so | |
| # defining it would silently downgrade publishing to a long-lived token. | |
| - name: Request CodeRabbit review on version PR | |
| if: steps.changesets.outputs.published != 'true' | |
| env: | |
| GH_TOKEN: ${{ steps.release-bot.outputs.token }} | |
| run: | | |
| pr=$(gh pr list --head changeset-release/main --state open --json number --jq '.[0].number' || true) | |
| if [ -n "$pr" ] && [ "$pr" != "null" ]; then | |
| gh pr comment "$pr" --body '@coderabbitai review' | |
| fi | |
| - name: Resolve Pythinker Code native release | |
| if: steps.changesets.outputs.published == 'true' | |
| id: pythinker-release | |
| run: node apps/pythinker-code/scripts/native/resolve-release.mjs | |
| env: | |
| CHANGESETS_PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} | |
| # code.pythinker.com redeploys via Dokploy autodeploy on push to main | |
| # (app Pythinker/code builds apps/site/Dockerfile from the repo, no npm | |
| # registry dependency), so no deploy webhook is fired here — this job only | |
| # verifies the published release is internally consistent. | |
| verify-cdn-release: | |
| timeout-minutes: 15 | |
| name: Verify release consistency | |
| needs: release | |
| if: needs.release.outputs.packages_published == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Verify release consistency | |
| run: node scripts/release/verify-release-consistency.mjs | |
| update-brew-tap: | |
| timeout-minutes: 15 | |
| name: Update Homebrew tap | |
| needs: release | |
| if: needs.release.outputs.packages_published == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Bump formula | |
| env: | |
| TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} | |
| run: | | |
| if [ -z "$TAP_GITHUB_TOKEN" ]; then | |
| echo "TAP_GITHUB_TOKEN secret not set — skipping tap update" >&2 | |
| exit 0 | |
| fi | |
| node scripts/release/update-brew-formula.mjs | |
| deploy-docs: | |
| name: Deploy docs | |
| needs: release | |
| if: needs.release.outputs.packages_published == 'true' | |
| uses: ./.github/workflows/docs-deploy.yml | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| native-artifacts: | |
| name: Native release artifact | |
| needs: release | |
| if: needs.release.outputs.pythinker_native_release == 'true' | |
| uses: ./.github/workflows/_native-build.yml | |
| with: | |
| upload-artifact-prefix: pythinker-code-native | |
| retention-days: 7 | |
| sign-macos: true | |
| secrets: | |
| APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_NOTARIZATION_KEY_P8: ${{ secrets.APPLE_NOTARIZATION_KEY_P8 }} | |
| APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }} | |
| APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }} | |
| publish-native-assets: | |
| timeout-minutes: 15 | |
| name: Publish native release assets | |
| needs: | |
| - release | |
| - native-artifacts | |
| if: needs.release.outputs.pythinker_native_release == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Download native artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: pythinker-code-native-* | |
| path: dist-native-release | |
| merge-multiple: true | |
| - name: Assert all native targets are present | |
| run: | | |
| missing=0 | |
| for target in darwin-arm64 darwin-x64 linux-arm64 linux-x64 win32-arm64 win32-x64; do | |
| if ! ls dist-native-release/pythinker-code-"$target".zip >/dev/null 2>&1; then | |
| echo "::error::Missing native bundle for $target — refusing to publish a partial release." | |
| missing=1 | |
| fi | |
| done | |
| exit $missing | |
| - name: Produce manifest.json | |
| env: | |
| RELEASE_TAG: ${{ needs.release.outputs.pythinker_release_tag }} | |
| run: node apps/pythinker-code/scripts/native/produce-manifest.mjs dist-native-release "$RELEASE_TAG" | |
| - name: Upload assets to GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ needs.release.outputs.pythinker_release_tag }} | |
| run: gh release upload "$RELEASE_TAG" dist-native-release/* --clobber |