diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36ae683b..9a8373c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,8 @@ on: - tsconfig.json - .node-version - .github/workflows/ci.yml + - .github/workflows/repoctl-docs.yml + - .github/workflows/repoctl-docs-deploy.yml push: branches: [main] paths: @@ -31,12 +33,17 @@ on: - tsconfig.json - .node-version - .github/workflows/ci.yml + - .github/workflows/repoctl-docs.yml + - .github/workflows/repoctl-docs-deploy.yml workflow_dispatch: concurrency: group: web-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} +env: + LEFTHOOK: '0' + permissions: contents: read @@ -45,8 +52,12 @@ jobs: name: Verify commercial application runs-on: ubuntu-24.04 timeout-minutes: 25 + env: + REPO_DOCS_CHANNEL: ${{ github.event_name == 'pull_request' && 'preview' || 'stable' }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: @@ -63,6 +74,12 @@ jobs: run: pnpm --filter @weapp-io/web lint && pnpm --filter @weapp-io/web lint:styles && pnpm --filter @weapp-io/web check && pnpm --filter @weapp-io/web test - name: Build and validate run: pnpm --filter @weapp-io/web build + - name: Bind the preview artifact to this pull request + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository + env: + PR_NUMBER: ${{ github.event.number }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: node scripts/docs-build.mjs web --identity-only - name: Install browser run: pnpm --filter @weapp-io/web exec playwright install --with-deps chromium - name: Test deployment artifact @@ -83,114 +100,62 @@ jobs: path: apps/web/test-results retention-days: 7 - deploy-production: - needs: verify - if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') - runs-on: ubuntu-24.04 - timeout-minutes: 10 - environment: production - concurrency: - group: deploy-production - cancel-in-progress: false - permissions: - contents: read - deployments: write - env: - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - - steps: - - name: Check out the repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Set up pnpm - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - - - name: Set up Node.js - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 - with: - node-version-file: .node-version - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Download the static site - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - name: web-dist - path: apps/web/dist - - - name: Deploy to Cloudflare Workers - working-directory: apps/web - run: | - set -o pipefail - pnpm exec wrangler deploy --message "${GITHUB_SHA}" 2>&1 | tee "$GITHUB_STEP_SUMMARY" - deploy-preview: needs: verify if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-24.04 - timeout-minutes: 10 + timeout-minutes: 15 concurrency: - group: deploy-preview-${{ github.event.number }} + group: pr-preview-web-${{ github.event.number }} cancel-in-progress: true permissions: contents: read pull-requests: write env: - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID || vars.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - + PR_NUMBER: ${{ github.event.number }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} steps: - - name: Check out the repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Set up pnpm - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - - - name: Set up Node.js - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - node-version-file: .node-version + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Download the static site - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + - run: pnpm install --frozen-lockfile + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: web-dist path: apps/web/dist - - - name: Upload a Worker version preview + - name: Deploy the tested PR artifact id: preview - working-directory: apps/web - run: | - set -o pipefail - pnpm exec wrangler versions upload \ - --preview-alias "pr-${{ github.event.number }}" \ - --message "${GITHUB_SHA}" \ - 2>&1 | tee "$GITHUB_STEP_SUMMARY" wrangler-preview.log - url="$(grep -Eo 'https://[a-zA-Z0-9._/-]+\.workers\.dev' wrangler-preview.log | head -n 1 || true)" - echo "url=${url}" >> "$GITHUB_OUTPUT" - - - name: Comment the preview URL + run: node scripts/docs-deployment/cli.mjs pr web + - name: Update the preview comment if: steps.preview.outputs.url != '' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: - GH_TOKEN: ${{ github.token }} PREVIEW_URL: ${{ steps.preview.outputs.url }} - PR_NUMBER: ${{ github.event.number }} - run: | - marker='' - # Keep Markdown backticks literal in the preview comment. - # shellcheck disable=SC2016 - body="$(printf '%s\n\nPreview for this pull request: %s\n\nThis Worker Version is not production traffic. `weapp.dev` stays on the current production deployment.\n' "${marker}" "${PREVIEW_URL}")" - existing="$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \ - --jq ".[] | select(.body | contains(\"${marker}\")) | .id" | head -n 1)" - if [ -n "${existing}" ]; then - gh api -X PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${existing}" -f body="${body}" - else - gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" -f body="${body}" - fi + with: + github-token: ${{ github.token }} + script: | + const marker = '' + const body = `${marker}\n\nweb preview: ${process.env.PREVIEW_URL}\n\nCommit: ${process.env.PR_HEAD_SHA}` + const issue_number = Number(process.env.PR_NUMBER) + const comments = await github.paginate(github.rest.issues.listComments, { ...context.repo, issue_number }) + const existing = comments.find(comment => comment.user?.type === 'Bot' && comment.body?.includes(marker)) + if (existing) { + await github.rest.issues.updateComment({ ...context.repo, comment_id: existing.id, body }) + } else { + await github.rest.issues.createComment({ ...context.repo, issue_number, body }) + } + - name: Retain preview deployment evidence + if: always() + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: pr-web-deployment-${{ github.event.number }} + path: .cache/docs-deployment + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/open-source.yml b/.github/workflows/open-source.yml index f0fec51a..6a65c8e8 100644 --- a/.github/workflows/open-source.yml +++ b/.github/workflows/open-source.yml @@ -16,6 +16,8 @@ on: - tsconfig.json - .node-version - .github/workflows/open-source.yml + - .github/workflows/repoctl-docs.yml + - .github/workflows/repoctl-docs-deploy.yml push: branches: [main] paths: @@ -31,12 +33,17 @@ on: - tsconfig.json - .node-version - .github/workflows/open-source.yml + - .github/workflows/repoctl-docs.yml + - .github/workflows/repoctl-docs-deploy.yml workflow_dispatch: concurrency: group: open-source-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} +env: + LEFTHOOK: '0' + permissions: contents: read @@ -45,8 +52,12 @@ jobs: name: Verify open-source application runs-on: ubuntu-24.04 timeout-minutes: 25 + env: + REPO_DOCS_CHANNEL: ${{ github.event_name == 'pull_request' && 'preview' || 'stable' }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: @@ -63,6 +74,12 @@ jobs: run: pnpm --filter @weapp-io/open-source lint && pnpm --filter @weapp-io/open-source lint:styles && pnpm --filter @weapp-io/open-source check && pnpm --filter @weapp-io/open-source test - name: Build and validate run: pnpm --filter @weapp-io/open-source build + - name: Bind the preview artifact to this pull request + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository + env: + PR_NUMBER: ${{ github.event.number }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: node scripts/docs-build.mjs open-source --identity-only - name: Install browser run: pnpm --filter @weapp-io/open-source exec playwright install --with-deps chromium - name: Test deployment artifact @@ -83,35 +100,62 @@ jobs: path: apps/open-source/test-results retention-days: 7 - deploy-pages: + deploy-preview: needs: verify - if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-24.04 - timeout-minutes: 10 - environment: - name: github-pages - url: ${{ steps.pages.outputs.page_url }} + timeout-minutes: 15 concurrency: - group: deploy-pages - cancel-in-progress: false + group: pr-preview-open-source-${{ github.event.number }} + cancel-in-progress: true permissions: contents: read - pages: write - id-token: write - + pull-requests: write + env: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID || vars.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + PR_NUMBER: ${{ github.event.number }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} steps: - - name: Download the GitHub Pages site - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + - run: pnpm install --frozen-lockfile + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: open-source-dist - path: dist - - - name: Upload the GitHub Pages artifact - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + path: apps/open-source/dist + - name: Deploy the tested PR artifact + id: preview + run: node scripts/docs-deployment/cli.mjs pr open-source + - name: Update the preview comment + if: steps.preview.outputs.url != '' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + PREVIEW_URL: ${{ steps.preview.outputs.url }} with: - path: dist - include-hidden-files: false - - - name: Deploy to GitHub Pages - id: pages - uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 + github-token: ${{ github.token }} + script: | + const marker = '' + const body = `${marker}\n\nopen-source preview: ${process.env.PREVIEW_URL}\n\nCommit: ${process.env.PR_HEAD_SHA}` + const issue_number = Number(process.env.PR_NUMBER) + const comments = await github.paginate(github.rest.issues.listComments, { ...context.repo, issue_number }) + const existing = comments.find(comment => comment.user?.type === 'Bot' && comment.body?.includes(marker)) + if (existing) { + await github.rest.issues.updateComment({ ...context.repo, comment_id: existing.id, body }) + } else { + await github.rest.issues.createComment({ ...context.repo, issue_number, body }) + } + - name: Retain preview deployment evidence + if: always() + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: pr-open-source-deployment-${{ github.event.number }} + path: .cache/docs-deployment + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/publish-weapp.yml b/.github/workflows/publish-weapp.yml deleted file mode 100644 index 97c42928..00000000 --- a/.github/workflows/publish-weapp.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: Publish weapp package - -on: - release: - types: [published] - workflow_dispatch: - inputs: - mode: - description: 'Validate only, or explicitly publish a release tag' - required: true - default: preflight - type: choice - options: [preflight, publish] - tag: - description: Git ref for preflight; publish requires weapp@ (legacy weapp-v accepted) - required: true - default: main - type: string - -permissions: - contents: read - -concurrency: - group: publish-weapp - cancel-in-progress: false - -jobs: - publish: - if: github.repository == 'weappjs/weapp.dev' && (github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'weapp@') || startsWith(github.event.release.tag_name, 'weapp-v')) - name: Validate weapp and optionally publish - runs-on: ubuntu-24.04 - timeout-minutes: 15 - permissions: - contents: read - id-token: write - env: - WEAPP_PREFLIGHT_MODE: ${{ github.event_name == 'release' && 'publish' || inputs.mode }} - WEAPP_RELEASE_TAG: ${{ inputs.tag || github.event.release.tag_name }} - - steps: - - name: Check out the release ref - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ inputs.tag || github.event.release.tag_name }} - fetch-depth: 0 - - - name: Set up pnpm - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - - - name: Set up Node.js - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 - with: - node-version-file: .node-version - cache: pnpm - registry-url: https://registry.npmjs.org - - - name: Install npm with trusted publishing support - run: npm install --global npm@12.2.1 - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Verify release tag - if: github.event_name == 'release' || inputs.mode == 'publish' - run: pnpm --filter weapp exec tsx scripts/check-release.ts - - - name: Verify generated catalog - run: pnpm --filter weapp exec tsx scripts/build.ts --check-readme - - - name: Test the package - run: pnpm check:boundaries && pnpm --filter weapp check && pnpm --filter weapp lint && pnpm --filter weapp lint:styles && pnpm --filter weapp test - - - name: Verify the package contents - working-directory: packages/weapp - run: npm pack --ignore-scripts --json - - - name: Preflight identity, unpublished version, exact artifact, and OIDC exchange - id: preflight - working-directory: packages/weapp - run: pnpm exec tsx scripts/preflight.ts --artifact - - - name: Preserve the validated artifact - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - with: - name: weapp-publication-${{ github.run_id }} - path: packages/weapp/${{ steps.preflight.outputs.artifact }} - if-no-files-found: error - retention-days: 14 - - - name: Publish with npm provenance - if: github.event_name == 'release' || inputs.mode == 'publish' - working-directory: packages/weapp - env: - WEAPP_VALIDATED_ARTIFACT: ${{ steps.preflight.outputs.artifact }} - run: npm publish "./$WEAPP_VALIDATED_ARTIFACT" --ignore-scripts --access public --provenance diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3005da56 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,331 @@ +# repoctl-managed: release/v2 +name: Release + +on: + push: + branches: + - main + workflow_dispatch: + inputs: + mode: + description: Release operation + required: true + default: auto + type: choice + options: + - auto + - prepare + - publish + - publish-unpublished + - reconcile + - oidc-audit + - nightly + package: + description: Package used for unpublished-version recovery + required: false + type: string + version: + description: Version used for unpublished-version recovery + required: false + type: string + dry-run: + description: Preview reconciliation or nightly publication without changes + required: false + default: false + type: boolean + source-sha: + description: Original commit on the selected release line (publish modes only) + required: false + type: string + schedule: + # 02:00 Asia/Shanghai every day; an already-published source is skipped. + - cron: '0 18 * * *' + +env: + LEFTHOOK: '0' + NPM_CONFIG_PROVENANCE: true + npm_config_registry: https://registry.npmjs.org + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + release: + if: ${{ github.repository == 'weappjs/weapp.dev' && github.event_name != 'schedule' && inputs.mode != 'nightly' && inputs.mode != 'oidc-audit' }} + name: Release + runs-on: ubuntu-24.04 + timeout-minutes: 60 + permissions: + contents: write + pull-requests: write + actions: write + id-token: write + outputs: + release-record: ${{ steps.release-finalize.outputs.release-record }} + docs-sites: ${{ steps.release-finalize.outputs.docs-sites }} + steps: + - name: Validate GitHub App configuration + env: + APP_CLIENT_ID: ${{ vars.REPOCTL_APP_CLIENT_ID }} + APP_PRIVATE_KEY_CONFIGURED: ${{ secrets.REPOCTL_APP_PRIVATE_KEY != '' }} + run: | + if { [ -n "$APP_CLIENT_ID" ] && [ "$APP_PRIVATE_KEY_CONFIGURED" != 'true' ]; } || + { [ -z "$APP_CLIENT_ID" ] && [ "$APP_PRIVATE_KEY_CONFIGURED" = 'true' ]; }; then + echo 'Configure both REPOCTL_APP_CLIENT_ID and REPOCTL_APP_PRIVATE_KEY.' >&2 + exit 1 + fi + + - name: Create GitHub App token + if: ${{ vars.REPOCTL_APP_CLIENT_ID != '' }} + id: app-token + uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 + with: + client-id: ${{ vars.REPOCTL_APP_CLIENT_ID }} + private-key: ${{ secrets.REPOCTL_APP_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + permission-actions: write + + - name: Checkout Repo + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + + - name: Setup Node.js environment + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + + - name: Install npm with trusted publishing support + run: npm install --global npm@11.16.0 --registry=https://registry.npmjs.org + + - name: Install Dependencies + run: pnpm install --frozen-lockfile + + - name: Release plan + id: release-plan + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }} + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --stage plan + + - name: Release verify + id: release-verify + if: ${{ steps.release-plan.outputs.run == 'true' }} + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }} + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --stage verify + + - name: Release prepare + id: release-prepare + if: ${{ steps.release-plan.outputs.run == 'true' }} + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }} + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --stage prepare + + - name: Validate the version pull request + if: ${{ steps.release-plan.outputs.run == 'true' && steps.release-prepare.outputs.publish != 'true' }} + env: + GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + GH_REPO: ${{ github.repository }} + run: | + # Workflow-token PRs do not emit another workflow-triggering event. + pr_url=$(gh pr list --head release/pnpm-version --base main --state open --json url --jq '.[0].url // empty') + if [ -n "$pr_url" ]; then + printf 'Version PR: %s\n' "$pr_url" >> "$GITHUB_STEP_SUMMARY" + gh workflow run weapp-cli.yml --ref release/pnpm-version + fi + + - name: Release upload + id: release-upload + if: ${{ steps.release-prepare.outputs.publish == 'true' }} + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }} + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --stage upload + + - name: Release confirm + id: release-confirm + if: ${{ steps.release-prepare.outputs.publish == 'true' }} + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }} + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --stage confirm + + - name: Release finalize + id: release-finalize + if: ${{ steps.release-prepare.outputs.publish == 'true' }} + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.REPOCTL_RELEASE_TOKEN || secrets.CHANGESETS_RELEASE_TOKEN || github.token }} + REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }} + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --stage finalize + + - name: Preserve npm publish progress + if: ${{ always() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: npm-publish-progress-${{ github.run_id }}-${{ github.run_attempt }} + path: | + pnpm-publish-summary.json + repoctl-publish-progress.json + repoctl-release-progress.json + repoctl-ci-progress.json + if-no-files-found: ignore + retention-days: 14 + + docs: + needs: release + if: ${{ !cancelled() && github.ref == 'refs/heads/main' && needs.release.outputs.release-record != '' && needs.release.outputs.docs-sites != '' && needs.release.outputs.docs-sites != '[]' }} + strategy: + fail-fast: false + matrix: + site: ${{ fromJSON(needs.release.outputs.docs-sites) }} + permissions: + contents: write + pages: write + id-token: write + uses: ./.github/workflows/repoctl-docs-deploy.yml + with: + site: ${{ matrix.site }} + channel: stable + release: ${{ needs.release.outputs.release-record }} + secrets: inherit + + nightly: + name: Publish nightly + if: ${{ github.repository == 'weappjs/weapp.dev' && ((github.event_name == 'schedule' && github.event.schedule == '0 18 * * *') || (github.event_name == 'workflow_dispatch' && inputs.mode == 'nightly')) }} + runs-on: ubuntu-24.04 + timeout-minutes: 90 + env: + REPOCTL_NIGHTLY_PROVIDER: npm + REPOCTL_NIGHTLY_SCHEDULE: '0 18 * * *' + permissions: + contents: read + id-token: write + steps: + - name: Validate nightly source + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + run: | + if [ -z "$DEFAULT_BRANCH" ] || [ "$GITHUB_REF" != "refs/heads/$DEFAULT_BRANCH" ]; then + echo '::error::Nightly publication requires the repository default branch.' + exit 1 + fi + + - name: Checkout nightly source + id: nightly-checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + + - name: Setup Node.js environment + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + + - name: Install npm with trusted publishing support + id: nightly-npm + run: npm install --global npm@11.16.0 --registry=https://registry.npmjs.org + + - name: Install Dependencies without lifecycle scripts + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Publish nightly packages + id: nightly-publish + env: + REPOCTL_SNAPSHOT_PUBLISH: '1' + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: | + args=(--publish --output "$RUNNER_TEMP/repoctl-nightly" --json) + if [ "$REPO_RELEASE_DRY_RUN" = 'true' ]; then + args+=(--dry-run) + fi + pnpm exec repo release nightly "${args[@]}" + + - name: Preserve nightly diagnostics + if: ${{ always() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: nightly-${{ github.run_id }}-${{ github.run_attempt }} + path: | + ${{ runner.temp }}/repoctl-nightly/*.json + ${{ runner.temp }}/repoctl-nightly/**/nightly-report.json + ${{ runner.temp }}/repoctl-nightly/**/consumer-report.json + ${{ runner.temp }}/repoctl-nightly/**/snapshot-report.json + ${{ runner.temp }}/repoctl-nightly/**/tarballs/**/*.tgz + if-no-files-found: ignore + retention-days: 14 + + oidc-audit: + name: Audit npm OIDC + if: ${{ github.repository == 'weappjs/weapp.dev' && github.event_name == 'workflow_dispatch' && inputs.mode == 'oidc-audit' }} + runs-on: ubuntu-24.04 + permissions: + contents: read + id-token: write + steps: + - name: Checkout Repo + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + + - name: Setup Node.js environment + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + + - name: Install Dependencies without lifecycle scripts + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Audit every publishable package + env: + REPO_RELEASE_PACKAGE: ${{ inputs.package }} + REPO_RELEASE_VERSION: ${{ inputs.version }} + REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }} + REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }} + run: pnpm exec repo release ci --mode oidc-audit diff --git a/.github/workflows/repoctl-docs-deploy.yml b/.github/workflows/repoctl-docs-deploy.yml new file mode 100644 index 00000000..ca61a85a --- /dev/null +++ b/.github/workflows/repoctl-docs-deploy.yml @@ -0,0 +1,166 @@ +# repoctl-managed: docs-deploy/v1 +name: Deploy documentation + +on: + workflow_call: + inputs: + site: + required: true + type: string + channel: + required: true + type: string + source-sha: + required: false + default: '' + type: string + release: + required: false + default: '' + type: string + commits: + required: false + default: '' + type: string + +env: + LEFTHOOK: '0' + +permissions: + contents: read + +concurrency: + group: docs-${{ inputs.site }}-${{ inputs.channel }} + cancel-in-progress: false + +jobs: + cloudflare: + if: ${{ github.repository == 'weappjs/weapp.dev' && github.ref == 'refs/heads/main' && github.event.repository.default_branch == 'main' && (inputs.site == 'web' || inputs.channel == 'preview') }} + runs-on: ubuntu-24.04 + timeout-minutes: 60 + environment: docs-${{ inputs.site }}-${{ inputs.channel }} + permissions: + contents: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + ref: main + persist-credentials: false + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + - run: pnpm install --frozen-lockfile + - name: Install the validation browser + run: pnpm --filter @weapp-io/web exec playwright install --with-deps chromium + - name: Plan and deploy the selected documentation source + env: + GITHUB_TOKEN: ${{ github.token }} + REPO_DOCS_SITE: ${{ inputs.site }} + REPO_DOCS_CHANNEL: ${{ inputs.channel }} + REPO_DOCS_SOURCE_SHA: ${{ inputs.source-sha }} + REPO_DOCS_RELEASE: ${{ inputs.release }} + REPO_DOCS_COMMITS: ${{ inputs.commits }} + REPO_DOCS_CONCURRENCY_GROUP: docs-${{ inputs.site }}-${{ inputs.channel }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID || vars.CLOUDFLARE_ACCOUNT_ID }} + run: | + args=("$REPO_DOCS_SITE" --channel "$REPO_DOCS_CHANNEL") + if [ -n "$REPO_DOCS_SOURCE_SHA" ]; then args+=(--source-sha "$REPO_DOCS_SOURCE_SHA"); fi + if [ -n "$REPO_DOCS_RELEASE" ]; then args+=(--release "$REPO_DOCS_RELEASE"); fi + if [ -n "$REPO_DOCS_COMMITS" ]; then + read -r -a commits <<< "$REPO_DOCS_COMMITS" + args+=(--commits "${commits[@]}") + fi + pnpm exec repo docs plan "${args[@]}" --json + pnpm exec repo docs deploy "${args[@]}" --json + - name: Retain the tested deployment artifact + if: ${{ always() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: docs-${{ inputs.site }}-${{ inputs.channel }}-${{ github.run_id }}-${{ github.run_attempt }} + path: .cache/docs-artifacts/${{ inputs.site }}/${{ inputs.channel }}/dist + if-no-files-found: ignore + retention-days: 30 + - name: Retain deployment and test evidence + if: ${{ always() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: docs-evidence-${{ inputs.site }}-${{ inputs.channel }}-${{ github.run_id }}-${{ github.run_attempt }} + path: | + .cache/docs-artifacts/${{ inputs.site }}/${{ inputs.channel }}/test-results + .cache/docs-deployment + if-no-files-found: ignore + retention-days: 7 + + pages: + if: ${{ github.repository == 'weappjs/weapp.dev' && github.ref == 'refs/heads/main' && github.event.repository.default_branch == 'main' && inputs.site == 'open-source' && inputs.channel == 'stable' }} + runs-on: ubuntu-24.04 + timeout-minutes: 60 + environment: docs-${{ inputs.site }}-${{ inputs.channel }} + permissions: + contents: write + pages: write + id-token: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + ref: main + persist-credentials: false + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + - run: pnpm install --frozen-lockfile + - name: Install the validation browser + run: pnpm --filter @weapp-io/web exec playwright install --with-deps chromium + # A JavaScript action exposes the runner artifact service credentials to its child. + - name: Plan and deploy the validated Pages artifact + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GITHUB_TOKEN: ${{ github.token }} + REPO_DOCS_SITE: ${{ inputs.site }} + REPO_DOCS_CHANNEL: ${{ inputs.channel }} + REPO_DOCS_SOURCE_SHA: ${{ inputs.source-sha }} + REPO_DOCS_RELEASE: ${{ inputs.release }} + REPO_DOCS_COMMITS: ${{ inputs.commits }} + REPO_DOCS_CONCURRENCY_GROUP: docs-${{ inputs.site }}-${{ inputs.channel }} + with: + github-token: ${{ github.token }} + script: | + const { spawnSync } = require('node:child_process') + const args = [process.env.REPO_DOCS_SITE, '--channel', process.env.REPO_DOCS_CHANNEL] + if (process.env.REPO_DOCS_SOURCE_SHA) args.push('--source-sha', process.env.REPO_DOCS_SOURCE_SHA) + if (process.env.REPO_DOCS_RELEASE) args.push('--release', process.env.REPO_DOCS_RELEASE) + if (process.env.REPO_DOCS_COMMITS) args.push('--commits', ...process.env.REPO_DOCS_COMMITS.trim().split(/\s+/)) + for (const command of ['plan', 'deploy']) { + const result = spawnSync('pnpm', ['exec', 'repo', 'docs', command, ...args, '--json'], { + stdio: 'inherit', + env: process.env, + }) + if (result.error || result.status !== 0) { + throw new Error(`repo docs ${command} failed with status ${result.status}`) + } + } + - name: Retain the tested deployment artifact + if: ${{ always() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: docs-${{ inputs.site }}-${{ inputs.channel }}-${{ github.run_id }}-${{ github.run_attempt }} + path: .cache/docs-artifacts/${{ inputs.site }}/${{ inputs.channel }}/dist + if-no-files-found: ignore + retention-days: 30 + - name: Retain deployment and test evidence + if: ${{ always() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: docs-evidence-${{ inputs.site }}-${{ inputs.channel }}-${{ github.run_id }}-${{ github.run_attempt }} + path: | + .cache/docs-artifacts/${{ inputs.site }}/${{ inputs.channel }}/test-results + .cache/docs-deployment + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/repoctl-docs.yml b/.github/workflows/repoctl-docs.yml new file mode 100644 index 00000000..d3fae659 --- /dev/null +++ b/.github/workflows/repoctl-docs.yml @@ -0,0 +1,88 @@ +# repoctl-managed: docs/v1 +name: Documentation + +on: + push: + branches: [main] + workflow_dispatch: + inputs: + site: + description: Configured documentation site + required: true + type: string + channel: + description: Deployment channel + required: true + default: stable + type: choice + options: [stable, preview] + source-sha: + description: Exact main commit for preview + required: false + type: string + release: + description: Completed stable release ID, for deployment or retry + required: false + type: string + commits: + description: Space-separated single-parent main commits containing documentation corrections + required: false + type: string + +env: + LEFTHOOK: '0' + +permissions: + contents: read + +jobs: + sites: + if: ${{ github.repository == 'weappjs/weapp.dev' && github.ref == 'refs/heads/main' && github.event.repository.default_branch == 'main' }} + runs-on: ubuntu-24.04 + permissions: + contents: read + outputs: + sites: ${{ steps.sites.outputs.sites }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version: 24.22.1 + cache: pnpm + - run: pnpm install --frozen-lockfile + - id: sites + env: + REQUESTED_SITE: ${{ inputs.site }} + run: | + node --input-type=module <<'NODE' + import { appendFile } from 'node:fs/promises' + import { loadMonorepoConfig } from 'repoctl' + const config = await loadMonorepoConfig(process.cwd()) + const sites = Object.keys(config.commands?.docs?.sites ?? {}).sort() + const requested = process.env.REQUESTED_SITE + if (requested && !sites.includes(requested)) throw new Error('Unknown documentation site') + await appendFile(process.env.GITHUB_OUTPUT, `sites=${JSON.stringify(requested ? [requested] : sites)}\n`) + NODE + + deploy: + needs: sites + if: ${{ needs.sites.outputs.sites != '[]' && needs.sites.outputs.sites != '' }} + strategy: + fail-fast: false + matrix: + site: ${{ fromJSON(needs.sites.outputs.sites) }} + permissions: + contents: write + pages: write + id-token: write + uses: ./.github/workflows/repoctl-docs-deploy.yml + with: + site: ${{ matrix.site }} + channel: ${{ github.event_name == 'push' && 'preview' || inputs.channel }} + source-sha: ${{ github.event_name == 'push' && github.sha || inputs.source-sha }} + release: ${{ inputs.release }} + commits: ${{ inputs.commits }} + secrets: inherit diff --git a/.github/workflows/sync-project-metrics.yml b/.github/workflows/sync-project-metrics.yml index 66052288..978a139d 100644 --- a/.github/workflows/sync-project-metrics.yml +++ b/.github/workflows/sync-project-metrics.yml @@ -5,6 +5,9 @@ on: - cron: '0 1 * * 1' # Monday 09:00 Asia/Shanghai (UTC+8) workflow_dispatch: +env: + LEFTHOOK: '0' + concurrency: group: sync-project-metrics cancel-in-progress: false diff --git a/.github/workflows/version-packages.yml b/.github/workflows/version-packages.yml deleted file mode 100644 index 4e990c1e..00000000 --- a/.github/workflows/version-packages.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Version Packages - -on: - push: - branches: [main] - workflow_dispatch: - -permissions: - contents: read - -env: - HUSKY: 0 # repoctl runs release:verify; package checks also run on the generated PR. - -concurrency: - group: version-packages - cancel-in-progress: false - -jobs: - prepare: - if: github.repository == 'weappjs/weapp.dev' && github.ref == 'refs/heads/main' - runs-on: ubuntu-24.04 - timeout-minutes: 15 - permissions: - contents: write - pull-requests: write - actions: write - steps: - - name: Check out the release line - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: main - fetch-depth: 0 - - - name: Set up pnpm - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - - - name: Set up Node.js - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 - with: - node-version-file: .node-version - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Validate the versioning configuration - run: pnpm exec repo config validate && pnpm change check - - - name: Prepare the version pull request with repoctl - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: pnpm release:prepare - - - name: Validate the version pull request - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - run: | - # Dispatch checks explicitly for PRs created with the workflow token. - pr_url=$(gh pr list --head release/pnpm-version --base main --state open --json url --jq '.[0].url // empty') - if [ -n "$pr_url" ]; then - printf 'Version PR: %s\n' "$pr_url" >> "$GITHUB_STEP_SUMMARY" - gh workflow run weapp-cli.yml --ref release/pnpm-version - gh workflow run publish-weapp.yml --ref release/pnpm-version -f mode=preflight -f tag=release/pnpm-version - fi diff --git a/.github/workflows/weapp-cli.yml b/.github/workflows/weapp-cli.yml index 93dc44bb..79cc1dca 100644 --- a/.github/workflows/weapp-cli.yml +++ b/.github/workflows/weapp-cli.yml @@ -17,8 +17,7 @@ on: - pnpm-workspace.yaml - eslint.config.js - .github/workflows/weapp-cli.yml - - .github/workflows/publish-weapp.yml - - .github/workflows/version-packages.yml + - .github/workflows/release.yml push: branches: [main] paths: @@ -35,10 +34,12 @@ on: - pnpm-workspace.yaml - eslint.config.js - .github/workflows/weapp-cli.yml - - .github/workflows/publish-weapp.yml - - .github/workflows/version-packages.yml + - .github/workflows/release.yml workflow_dispatch: +env: + LEFTHOOK: '0' + permissions: contents: read diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 5fc57f24..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1 +0,0 @@ -pnpm exec repo verify pre-commit diff --git a/.node-version b/.node-version index b8b23ca9..ce62013c 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -22.23.4 +24.22.1 diff --git a/.repoctl/baselines/root/0da85e683125db2a66123e080152c15de988e502daa6d2375b7199d2cb9ed9ea.json b/.repoctl/baselines/root/0da85e683125db2a66123e080152c15de988e502daa6d2375b7199d2cb9ed9ea.json new file mode 100644 index 00000000..e7a2a32a --- /dev/null +++ b/.repoctl/baselines/root/0da85e683125db2a66123e080152c15de988e502daa6d2375b7199d2cb9ed9ea.json @@ -0,0 +1,14 @@ +{ + "schemaVersion": 1, + "path": ".github/workflows/repoctl-docs.yml", + "source": { + "package": "@icebreakers/monorepo-templates", + "version": "3.0.1", + "assetPath": ".github/workflows/repoctl-docs.yml", + "hash": "a5dc95668e55c83c14a79fb4a2d1f02c0538cf8be25cb3667169f9b6203c7b83" + }, + "upstream": { + "hash": "a5dc95668e55c83c14a79fb4a2d1f02c0538cf8be25cb3667169f9b6203c7b83", + "content": "IyByZXBvY3RsLW1hbmFnZWQ6IGRvY3MvdjEKbmFtZTogRG9jdW1lbnRhdGlvbgoKb246CiAgcHVzaDoKICAgIGJyYW5jaGVzOiBbbWFpbl0KICB3b3JrZmxvd19kaXNwYXRjaDoKICAgIGlucHV0czoKICAgICAgc2l0ZToKICAgICAgICBkZXNjcmlwdGlvbjogQ29uZmlndXJlZCBkb2N1bWVudGF0aW9uIHNpdGUKICAgICAgICByZXF1aXJlZDogdHJ1ZQogICAgICAgIHR5cGU6IHN0cmluZwogICAgICBjaGFubmVsOgogICAgICAgIGRlc2NyaXB0aW9uOiBEZXBsb3ltZW50IGNoYW5uZWwKICAgICAgICByZXF1aXJlZDogdHJ1ZQogICAgICAgIGRlZmF1bHQ6IHN0YWJsZQogICAgICAgIHR5cGU6IGNob2ljZQogICAgICAgIG9wdGlvbnM6IFtzdGFibGUsIHByZXZpZXddCiAgICAgIHNvdXJjZS1zaGE6CiAgICAgICAgZGVzY3JpcHRpb246IEV4YWN0IG1haW4gY29tbWl0IGZvciBwcmV2aWV3CiAgICAgICAgcmVxdWlyZWQ6IGZhbHNlCiAgICAgICAgdHlwZTogc3RyaW5nCiAgICAgIHJlbGVhc2U6CiAgICAgICAgZGVzY3JpcHRpb246IENvbXBsZXRlZCBzdGFibGUgcmVsZWFzZSBJRCwgZm9yIGRlcGxveW1lbnQgb3IgcmV0cnkKICAgICAgICByZXF1aXJlZDogZmFsc2UKICAgICAgICB0eXBlOiBzdHJpbmcKICAgICAgY29tbWl0czoKICAgICAgICBkZXNjcmlwdGlvbjogU3BhY2Utc2VwYXJhdGVkIHNpbmdsZS1wYXJlbnQgbWFpbiBjb21taXRzIGNvbnRhaW5pbmcgZG9jdW1lbnRhdGlvbiBjb3JyZWN0aW9ucwogICAgICAgIHJlcXVpcmVkOiBmYWxzZQogICAgICAgIHR5cGU6IHN0cmluZwoKcGVybWlzc2lvbnM6CiAgY29udGVudHM6IHdyaXRlCgpqb2JzOgogIHNpdGVzOgogICAgaWY6ICR7eyBnaXRodWIucmVmID09ICdyZWZzL2hlYWRzL21haW4nICYmIGdpdGh1Yi5ldmVudC5yZXBvc2l0b3J5LmRlZmF1bHRfYnJhbmNoID09ICdtYWluJyB9fQogICAgcnVucy1vbjogdWJ1bnR1LWxhdGVzdAogICAgcGVybWlzc2lvbnM6CiAgICAgIGNvbnRlbnRzOiByZWFkCiAgICBvdXRwdXRzOgogICAgICBzaXRlczogJHt7IHN0ZXBzLnNpdGVzLm91dHB1dHMuc2l0ZXMgfX0KICAgIHN0ZXBzOgogICAgICAtIHVzZXM6IGFjdGlvbnMvY2hlY2tvdXRAM2QzYzQyZTVhYWM1YmE4MDU4MjVkYTc2NDEwYzE4MTI3M2JhOTBiMSAjIHY3LjAuMQogICAgICAgIHdpdGg6CiAgICAgICAgICBwZXJzaXN0LWNyZWRlbnRpYWxzOiBmYWxzZQogICAgICAtIHVzZXM6IHBucG0vYWN0aW9uLXNldHVwQGVhMTdjNjhkZjg5MTJlZjU0MzM1MjcyM2MxNDlhODRmNTZlM2Q0MTMgIyB2Ni4xLjAKICAgICAgLSB1c2VzOiBhY3Rpb25zL3NldHVwLW5vZGVAOTQ5ZmViMjQxM2Q2NDU4Nzk0ZGNkMjQ5MWM0YmFiYmJjZTBjMTVjMSAjIHY3LjEuMAogICAgICAgIHdpdGg6CiAgICAgICAgICBub2RlLXZlcnNpb246IDI0LjIyLjEKICAgICAgICAgIGNhY2hlOiBwbnBtCiAgICAgIC0gcnVuOiBwbnBtIGluc3RhbGwgLS1mcm96ZW4tbG9ja2ZpbGUKICAgICAgLSBpZDogc2l0ZXMKICAgICAgICBlbnY6CiAgICAgICAgICBSRVFVRVNURURfU0lURTogJHt7IGlucHV0cy5zaXRlIH19CiAgICAgICAgcnVuOiB8CiAgICAgICAgICBub2RlIC0taW5wdXQtdHlwZT1tb2R1bGUgPDwnTk9ERScKICAgICAgICAgIGltcG9ydCB7IGFwcGVuZEZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJwogICAgICAgICAgaW1wb3J0IHsgbG9hZE1vbm9yZXBvQ29uZmlnIH0gZnJvbSAncmVwb2N0bCcKICAgICAgICAgIGNvbnN0IGNvbmZpZyA9IGF3YWl0IGxvYWRNb25vcmVwb0NvbmZpZyhwcm9jZXNzLmN3ZCgpKQogICAgICAgICAgY29uc3Qgc2l0ZXMgPSBPYmplY3Qua2V5cyhjb25maWcuY29tbWFuZHM/LmRvY3M/LnNpdGVzID8/IHt9KS5zb3J0KCkKICAgICAgICAgIGNvbnN0IHJlcXVlc3RlZCA9IHByb2Nlc3MuZW52LlJFUVVFU1RFRF9TSVRFCiAgICAgICAgICBpZiAocmVxdWVzdGVkICYmICFzaXRlcy5pbmNsdWRlcyhyZXF1ZXN0ZWQpKSB0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gZG9jdW1lbnRhdGlvbiBzaXRlJykKICAgICAgICAgIGF3YWl0IGFwcGVuZEZpbGUocHJvY2Vzcy5lbnYuR0lUSFVCX09VVFBVVCwgYHNpdGVzPSR7SlNPTi5zdHJpbmdpZnkocmVxdWVzdGVkID8gW3JlcXVlc3RlZF0gOiBzaXRlcyl9XG5gKQogICAgICAgICAgTk9ERQoKICBkZXBsb3k6CiAgICBuZWVkczogc2l0ZXMKICAgIGlmOiAke3sgbmVlZHMuc2l0ZXMub3V0cHV0cy5zaXRlcyAhPSAnW10nICYmIG5lZWRzLnNpdGVzLm91dHB1dHMuc2l0ZXMgIT0gJycgfX0KICAgIHN0cmF0ZWd5OgogICAgICBmYWlsLWZhc3Q6IGZhbHNlCiAgICAgIG1hdHJpeDoKICAgICAgICBzaXRlOiAke3sgZnJvbUpTT04obmVlZHMuc2l0ZXMub3V0cHV0cy5zaXRlcykgfX0KICAgIHVzZXM6IC4vLmdpdGh1Yi93b3JrZmxvd3MvcmVwb2N0bC1kb2NzLWRlcGxveS55bWwKICAgIHdpdGg6CiAgICAgIHNpdGU6ICR7eyBtYXRyaXguc2l0ZSB9fQogICAgICBjaGFubmVsOiAke3sgZ2l0aHViLmV2ZW50X25hbWUgPT0gJ3B1c2gnICYmICdwcmV2aWV3JyB8fCBpbnB1dHMuY2hhbm5lbCB9fQogICAgICBzb3VyY2Utc2hhOiAke3sgZ2l0aHViLmV2ZW50X25hbWUgPT0gJ3B1c2gnICYmIGdpdGh1Yi5zaGEgfHwgaW5wdXRzLnNvdXJjZS1zaGEgfX0KICAgICAgcmVsZWFzZTogJHt7IGlucHV0cy5yZWxlYXNlIH19CiAgICAgIGNvbW1pdHM6ICR7eyBpbnB1dHMuY29tbWl0cyB9fQogICAgc2VjcmV0czogaW5oZXJpdAo=" + } +} diff --git a/.repoctl/baselines/root/87db21a973eed4fef5f32b267aa60fcee5cbdf03c67fafdc2a9b553bb0b15f34.json b/.repoctl/baselines/root/87db21a973eed4fef5f32b267aa60fcee5cbdf03c67fafdc2a9b553bb0b15f34.json new file mode 100644 index 00000000..4a9d64c8 --- /dev/null +++ b/.repoctl/baselines/root/87db21a973eed4fef5f32b267aa60fcee5cbdf03c67fafdc2a9b553bb0b15f34.json @@ -0,0 +1,14 @@ +{ + "schemaVersion": 1, + "path": ".github/workflows/release.yml", + "source": { + "package": "@icebreakers/monorepo-templates", + "version": "3.0.1", + "assetPath": ".github/workflows/release.yml", + "hash": "5cbbc636eff5094b0974048e377c9d0924f0f35b2155dbf9b5e6fe8d0bb96020" + }, + "upstream": { + "hash": "a74821ca181c1cfc940096b02ac25210caefb63a4ca8e2e5a0ef05a7768c2882", + "content": "IyByZXBvY3RsLW1hbmFnZWQ6IHJlbGVhc2UvdjIKbmFtZTogUmVsZWFzZQoKb246CiAgIyBTb3VyY2UgcmVwb3NpdG9yeSBvbmx5OiAwMzoxNyBBc2lhL1NoYW5naGFpLgogIHB1c2g6CiAgICBicmFuY2hlczoKICAgICAgLSBtYWluCiAgd29ya2Zsb3dfZGlzcGF0Y2g6CiAgICBpbnB1dHM6CiAgICAgIG1vZGU6CiAgICAgICAgZGVzY3JpcHRpb246IFJlbGVhc2Ugb3BlcmF0aW9uCiAgICAgICAgcmVxdWlyZWQ6IHRydWUKICAgICAgICBkZWZhdWx0OiBhdXRvCiAgICAgICAgdHlwZTogY2hvaWNlCiAgICAgICAgb3B0aW9uczoKICAgICAgICAgIC0gYXV0bwogICAgICAgICAgLSBwcmVwYXJlCiAgICAgICAgICAtIHB1Ymxpc2gKICAgICAgICAgIC0gcHVibGlzaC11bnB1Ymxpc2hlZAogICAgICAgICAgLSByZWNvbmNpbGUKICAgICAgICAgIC0gb2lkYy1hdWRpdAogICAgICAgICAgLSBuaWdodGx5CiAgICAgIHBhY2thZ2U6CiAgICAgICAgZGVzY3JpcHRpb246IFBhY2thZ2UgdXNlZCBmb3IgdW5wdWJsaXNoZWQtdmVyc2lvbiByZWNvdmVyeQogICAgICAgIHJlcXVpcmVkOiBmYWxzZQogICAgICAgIHR5cGU6IHN0cmluZwogICAgICB2ZXJzaW9uOgogICAgICAgIGRlc2NyaXB0aW9uOiBWZXJzaW9uIHVzZWQgZm9yIHVucHVibGlzaGVkLXZlcnNpb24gcmVjb3ZlcnkKICAgICAgICByZXF1aXJlZDogZmFsc2UKICAgICAgICB0eXBlOiBzdHJpbmcKICAgICAgZHJ5LXJ1bjoKICAgICAgICBkZXNjcmlwdGlvbjogUHJldmlldyByZWNvbmNpbGlhdGlvbiBvciBuaWdodGx5IHB1YmxpY2F0aW9uIHdpdGhvdXQgY2hhbmdlcwogICAgICAgIHJlcXVpcmVkOiBmYWxzZQogICAgICAgIGRlZmF1bHQ6IGZhbHNlCiAgICAgICAgdHlwZTogYm9vbGVhbgogICAgICBzb3VyY2Utc2hhOgogICAgICAgIGRlc2NyaXB0aW9uOiBPcmlnaW5hbCBjb21taXQgb24gdGhlIHNlbGVjdGVkIHJlbGVhc2UgbGluZSAocHVibGlzaCBtb2RlcyBvbmx5KQogICAgICAgIHJlcXVpcmVkOiBmYWxzZQogICAgICAgIHR5cGU6IHN0cmluZwogIHNjaGVkdWxlOgogICAgLSBjcm9uOiAwIDE4ICogKiAqCgplbnY6CiAgTEVGVEhPT0s6IDAKICBOUE1fQ09ORklHX1BST1ZFTkFOQ0U6IHRydWUKICBucG1fY29uZmlnX3JlZ2lzdHJ5OiBodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZwoKcGVybWlzc2lvbnM6CiAgY29udGVudHM6IHdyaXRlCiAgcHVsbC1yZXF1ZXN0czogd3JpdGUKICBpZC10b2tlbjogd3JpdGUKCmNvbmN1cnJlbmN5OgogIGdyb3VwOiAke3sgZ2l0aHViLndvcmtmbG93IH19LSR7eyBnaXRodWIucmVmIH19CiAgY2FuY2VsLWluLXByb2dyZXNzOiBmYWxzZQoKam9iczoKICByZWxlYXNlOgogICAgaWY6ICR7eyBnaXRodWIuZXZlbnRfbmFtZSAhPSAnc2NoZWR1bGUnICYmIGlucHV0cy5tb2RlICE9ICduaWdodGx5JyAmJiBpbnB1dHMubW9kZSAhPSAnb2lkYy1hdWRpdCcgfX0KICAgIG5hbWU6IFJlbGVhc2UKICAgIHJ1bnMtb246IHVidW50dS1sYXRlc3QKICAgIG91dHB1dHM6CiAgICAgIHJlbGVhc2UtcmVjb3JkOiAke3sgc3RlcHMucmVsZWFzZS1maW5hbGl6ZS5vdXRwdXRzLnJlbGVhc2UtcmVjb3JkIH19CiAgICAgIGRvY3Mtc2l0ZXM6ICR7eyBzdGVwcy5yZWxlYXNlLWZpbmFsaXplLm91dHB1dHMuZG9jcy1zaXRlcyB9fQogICAgc3RlcHM6CiAgICAgIC0gbmFtZTogVmFsaWRhdGUgR2l0SHViIEFwcCBjb25maWd1cmF0aW9uCiAgICAgICAgZW52OgogICAgICAgICAgQVBQX0NMSUVOVF9JRDogJHt7IHZhcnMuUkVQT0NUTF9BUFBfQ0xJRU5UX0lEIH19CiAgICAgICAgICBBUFBfUFJJVkFURV9LRVlfQ09ORklHVVJFRDogJHt7IHNlY3JldHMuUkVQT0NUTF9BUFBfUFJJVkFURV9LRVkgIT0gJycgfX0KICAgICAgICBydW46IHwKICAgICAgICAgIGlmIHsgWyAtbiAiJEFQUF9DTElFTlRfSUQiIF0gJiYgWyAiJEFQUF9QUklWQVRFX0tFWV9DT05GSUdVUkVEIiAhPSAndHJ1ZScgXTsgfSB8fAogICAgICAgICAgICAgeyBbIC16ICIkQVBQX0NMSUVOVF9JRCIgXSAmJiBbICIkQVBQX1BSSVZBVEVfS0VZX0NPTkZJR1VSRUQiID0gJ3RydWUnIF07IH07IHRoZW4KICAgICAgICAgICAgZWNobyAnQ29uZmlndXJlIGJvdGggUkVQT0NUTF9BUFBfQ0xJRU5UX0lEIGFuZCBSRVBPQ1RMX0FQUF9QUklWQVRFX0tFWS4nID4mMgogICAgICAgICAgICBleGl0IDEKICAgICAgICAgIGZpCgogICAgICAtIG5hbWU6IENyZWF0ZSBHaXRIdWIgQXBwIHRva2VuCiAgICAgICAgaWY6ICR7eyB2YXJzLlJFUE9DVExfQVBQX0NMSUVOVF9JRCAhPSAnJyB9fQogICAgICAgIGlkOiBhcHAtdG9rZW4KICAgICAgICB1c2VzOiBhY3Rpb25zL2NyZWF0ZS1naXRodWItYXBwLXRva2VuQDY0YWI3MjlhNjI5NDAwMGY1YWE0YTRiYzBiNzNkMWYzMmJjNDU1MTAgIyB2My4zLjAKICAgICAgICB3aXRoOgogICAgICAgICAgY2xpZW50LWlkOiAke3sgdmFycy5SRVBPQ1RMX0FQUF9DTElFTlRfSUQgfX0KICAgICAgICAgIHByaXZhdGUta2V5OiAke3sgc2VjcmV0cy5SRVBPQ1RMX0FQUF9QUklWQVRFX0tFWSB9fQogICAgICAgICAgcGVybWlzc2lvbi1jb250ZW50czogd3JpdGUKICAgICAgICAgIHBlcm1pc3Npb24tcHVsbC1yZXF1ZXN0czogd3JpdGUKCiAgICAgIC0gbmFtZTogQ2hlY2tvdXQgUmVwbwogICAgICAgIHVzZXM6IGFjdGlvbnMvY2hlY2tvdXRAM2QzYzQyZTVhYWM1YmE4MDU4MjVkYTc2NDEwYzE4MTI3M2JhOTBiMSAjIHY3LjAuMQogICAgICAgIHdpdGg6CiAgICAgICAgICBmZXRjaC1kZXB0aDogMAogICAgICAgICAgdG9rZW46ICR7eyBzdGVwcy5hcHAtdG9rZW4ub3V0cHV0cy50b2tlbiB8fCBzZWNyZXRzLlJFUE9DVExfUkVMRUFTRV9UT0tFTiB8fCBzZWNyZXRzLkNIQU5HRVNFVFNfUkVMRUFTRV9UT0tFTiB8fCBnaXRodWIudG9rZW4gfX0KCiAgICAgIC0gdXNlczogcG5wbS9hY3Rpb24tc2V0dXBAZWExN2M2OGRmODkxMmVmNTQzMzUyNzIzYzE0OWE4NGY1NmUzZDQxMyAjIHY2LjEuMAoKICAgICAgLSBuYW1lOiBTZXR1cCBOb2RlLmpzIGVudmlyb25tZW50CiAgICAgICAgdXNlczogYWN0aW9ucy9zZXR1cC1ub2RlQDk0OWZlYjI0MTNkNjQ1ODc5NGRjZDI0OTFjNGJhYmJiY2UwYzE1YzEgIyB2Ny4xLjAKICAgICAgICB3aXRoOgogICAgICAgICAgbm9kZS12ZXJzaW9uOiAyNC4yMi4xCiAgICAgICAgICBjYWNoZTogcG5wbQoKICAgICAgLSBuYW1lOiBJbnN0YWxsIG5wbSB3aXRoIHRydXN0ZWQgcHVibGlzaGluZyBzdXBwb3J0CiAgICAgICAgcnVuOiBucG0gaW5zdGFsbCAtLWdsb2JhbCBucG1AMTEuMTYuMCAtLXJlZ2lzdHJ5PWh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnCgogICAgICAtIG5hbWU6IEluc3RhbGwgRGVwZW5kZW5jaWVzCiAgICAgICAgcnVuOiBwbnBtIGluc3RhbGwgLS1mcm96ZW4tbG9ja2ZpbGUKCiAgICAgIC0gbmFtZTogUmVsZWFzZSBwbGFuCiAgICAgICAgaWQ6IHJlbGVhc2UtcGxhbgogICAgICAgIGVudjoKICAgICAgICAgIEdJVEhVQl9UT0tFTjogJHt7IHN0ZXBzLmFwcC10b2tlbi5vdXRwdXRzLnRva2VuIHx8IHNlY3JldHMuUkVQT0NUTF9SRUxFQVNFX1RPS0VOIHx8IHNlY3JldHMuQ0hBTkdFU0VUU19SRUxFQVNFX1RPS0VOIHx8IGdpdGh1Yi50b2tlbiB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX01PREU6ICR7eyBpbnB1dHMubW9kZSB8fCAnYXV0bycgfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9QQUNLQUdFOiAke3sgaW5wdXRzLnBhY2thZ2UgfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9WRVJTSU9OOiAke3sgaW5wdXRzLnZlcnNpb24gfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9EUllfUlVOOiAke3sgaW5wdXRzLmRyeS1ydW4gfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9SRUNPVkVSWV9TT1VSQ0VfU0hBOiAke3sgaW5wdXRzLnNvdXJjZS1zaGEgfX0KICAgICAgICBydW46IHBucG0gZXhlYyByZXBvIHJlbGVhc2UgY2kgLS1zdGFnZSBwbGFuCgogICAgICAtIG5hbWU6IFJlbGVhc2UgdmVyaWZ5CiAgICAgICAgaWQ6IHJlbGVhc2UtdmVyaWZ5CiAgICAgICAgaWY6ICR7eyBzdGVwcy5yZWxlYXNlLXBsYW4ub3V0cHV0cy5ydW4gPT0gJ3RydWUnIH19CiAgICAgICAgZW52OgogICAgICAgICAgR0lUSFVCX1RPS0VOOiAke3sgc3RlcHMuYXBwLXRva2VuLm91dHB1dHMudG9rZW4gfHwgc2VjcmV0cy5SRVBPQ1RMX1JFTEVBU0VfVE9LRU4gfHwgc2VjcmV0cy5DSEFOR0VTRVRTX1JFTEVBU0VfVE9LRU4gfHwgZ2l0aHViLnRva2VuIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfTU9ERTogJHt7IGlucHV0cy5tb2RlIHx8ICdhdXRvJyB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1BBQ0tBR0U6ICR7eyBpbnB1dHMucGFja2FnZSB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1ZFUlNJT046ICR7eyBpbnB1dHMudmVyc2lvbiB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX0RSWV9SVU46ICR7eyBpbnB1dHMuZHJ5LXJ1biB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1JFQ09WRVJZX1NPVVJDRV9TSEE6ICR7eyBpbnB1dHMuc291cmNlLXNoYSB9fQogICAgICAgIHJ1bjogcG5wbSBleGVjIHJlcG8gcmVsZWFzZSBjaSAtLXN0YWdlIHZlcmlmeQoKICAgICAgLSBuYW1lOiBSZWxlYXNlIHByZXBhcmUKICAgICAgICBpZDogcmVsZWFzZS1wcmVwYXJlCiAgICAgICAgaWY6ICR7eyBzdGVwcy5yZWxlYXNlLXBsYW4ub3V0cHV0cy5ydW4gPT0gJ3RydWUnIH19CiAgICAgICAgZW52OgogICAgICAgICAgR0lUSFVCX1RPS0VOOiAke3sgc3RlcHMuYXBwLXRva2VuLm91dHB1dHMudG9rZW4gfHwgc2VjcmV0cy5SRVBPQ1RMX1JFTEVBU0VfVE9LRU4gfHwgc2VjcmV0cy5DSEFOR0VTRVRTX1JFTEVBU0VfVE9LRU4gfHwgZ2l0aHViLnRva2VuIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfTU9ERTogJHt7IGlucHV0cy5tb2RlIHx8ICdhdXRvJyB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1BBQ0tBR0U6ICR7eyBpbnB1dHMucGFja2FnZSB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1ZFUlNJT046ICR7eyBpbnB1dHMudmVyc2lvbiB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX0RSWV9SVU46ICR7eyBpbnB1dHMuZHJ5LXJ1biB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1JFQ09WRVJZX1NPVVJDRV9TSEE6ICR7eyBpbnB1dHMuc291cmNlLXNoYSB9fQogICAgICAgIHJ1bjogcG5wbSBleGVjIHJlcG8gcmVsZWFzZSBjaSAtLXN0YWdlIHByZXBhcmUKCiAgICAgIC0gbmFtZTogUmVsZWFzZSB1cGxvYWQKICAgICAgICBpZDogcmVsZWFzZS11cGxvYWQKICAgICAgICBpZjogJHt7IHN0ZXBzLnJlbGVhc2UtcHJlcGFyZS5vdXRwdXRzLnB1Ymxpc2ggPT0gJ3RydWUnIH19CiAgICAgICAgZW52OgogICAgICAgICAgR0lUSFVCX1RPS0VOOiAke3sgc3RlcHMuYXBwLXRva2VuLm91dHB1dHMudG9rZW4gfHwgc2VjcmV0cy5SRVBPQ1RMX1JFTEVBU0VfVE9LRU4gfHwgc2VjcmV0cy5DSEFOR0VTRVRTX1JFTEVBU0VfVE9LRU4gfHwgZ2l0aHViLnRva2VuIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfTU9ERTogJHt7IGlucHV0cy5tb2RlIHx8ICdhdXRvJyB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1BBQ0tBR0U6ICR7eyBpbnB1dHMucGFja2FnZSB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1ZFUlNJT046ICR7eyBpbnB1dHMudmVyc2lvbiB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX0RSWV9SVU46ICR7eyBpbnB1dHMuZHJ5LXJ1biB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1JFQ09WRVJZX1NPVVJDRV9TSEE6ICR7eyBpbnB1dHMuc291cmNlLXNoYSB9fQogICAgICAgIHJ1bjogcG5wbSBleGVjIHJlcG8gcmVsZWFzZSBjaSAtLXN0YWdlIHVwbG9hZAoKICAgICAgLSBuYW1lOiBSZWxlYXNlIGNvbmZpcm0KICAgICAgICBpZDogcmVsZWFzZS1jb25maXJtCiAgICAgICAgaWY6ICR7eyBzdGVwcy5yZWxlYXNlLXByZXBhcmUub3V0cHV0cy5wdWJsaXNoID09ICd0cnVlJyB9fQogICAgICAgIGVudjoKICAgICAgICAgIEdJVEhVQl9UT0tFTjogJHt7IHN0ZXBzLmFwcC10b2tlbi5vdXRwdXRzLnRva2VuIHx8IHNlY3JldHMuUkVQT0NUTF9SRUxFQVNFX1RPS0VOIHx8IHNlY3JldHMuQ0hBTkdFU0VUU19SRUxFQVNFX1RPS0VOIHx8IGdpdGh1Yi50b2tlbiB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX01PREU6ICR7eyBpbnB1dHMubW9kZSB8fCAnYXV0bycgfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9QQUNLQUdFOiAke3sgaW5wdXRzLnBhY2thZ2UgfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9WRVJTSU9OOiAke3sgaW5wdXRzLnZlcnNpb24gfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9EUllfUlVOOiAke3sgaW5wdXRzLmRyeS1ydW4gfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9SRUNPVkVSWV9TT1VSQ0VfU0hBOiAke3sgaW5wdXRzLnNvdXJjZS1zaGEgfX0KICAgICAgICBydW46IHBucG0gZXhlYyByZXBvIHJlbGVhc2UgY2kgLS1zdGFnZSBjb25maXJtCgogICAgICAtIG5hbWU6IFJlbGVhc2UgZmluYWxpemUKICAgICAgICBpZDogcmVsZWFzZS1maW5hbGl6ZQogICAgICAgIGlmOiAke3sgc3RlcHMucmVsZWFzZS1wcmVwYXJlLm91dHB1dHMucHVibGlzaCA9PSAndHJ1ZScgfX0KICAgICAgICBlbnY6CiAgICAgICAgICBHSVRIVUJfVE9LRU46ICR7eyBzdGVwcy5hcHAtdG9rZW4ub3V0cHV0cy50b2tlbiB8fCBzZWNyZXRzLlJFUE9DVExfUkVMRUFTRV9UT0tFTiB8fCBzZWNyZXRzLkNIQU5HRVNFVFNfUkVMRUFTRV9UT0tFTiB8fCBnaXRodWIudG9rZW4gfX0KICAgICAgICAgIFJFUE9fUkVMRUFTRV9NT0RFOiAke3sgaW5wdXRzLm1vZGUgfHwgJ2F1dG8nIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfUEFDS0FHRTogJHt7IGlucHV0cy5wYWNrYWdlIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfVkVSU0lPTjogJHt7IGlucHV0cy52ZXJzaW9uIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfRFJZX1JVTjogJHt7IGlucHV0cy5kcnktcnVuIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfUkVDT1ZFUllfU09VUkNFX1NIQTogJHt7IGlucHV0cy5zb3VyY2Utc2hhIH19CiAgICAgICAgcnVuOiBwbnBtIGV4ZWMgcmVwbyByZWxlYXNlIGNpIC0tc3RhZ2UgZmluYWxpemUKCiAgICAgIC0gbmFtZTogUHJlc2VydmUgbnBtIHB1Ymxpc2ggcHJvZ3Jlc3MKICAgICAgICBpZjogJHt7IGFsd2F5cygpIH19CiAgICAgICAgdXNlczogYWN0aW9ucy91cGxvYWQtYXJ0aWZhY3RAY2Y0MzBlMDMwZGRiYjViMGFiZjkzZDIyOTYyZjQ3NTJmMzY0NmNkOSAjIHY3LjAuMgogICAgICAgIHdpdGg6CiAgICAgICAgICBuYW1lOiBucG0tcHVibGlzaC1wcm9ncmVzcy0ke3sgZ2l0aHViLnJ1bl9pZCB9fS0ke3sgZ2l0aHViLnJ1bl9hdHRlbXB0IH19CiAgICAgICAgICBwYXRoOiB8CiAgICAgICAgICAgIHBucG0tcHVibGlzaC1zdW1tYXJ5Lmpzb24KICAgICAgICAgICAgcmVwb2N0bC1wdWJsaXNoLXByb2dyZXNzLmpzb24KICAgICAgICAgICAgcmVwb2N0bC1yZWxlYXNlLXByb2dyZXNzLmpzb24KICAgICAgICAgICAgcmVwb2N0bC1jaS1wcm9ncmVzcy5qc29uCiAgICAgICAgICBpZi1uby1maWxlcy1mb3VuZDogaWdub3JlCiAgICAgICAgICByZXRlbnRpb24tZGF5czogMTQKCiAgZG9jczoKICAgIG5lZWRzOiByZWxlYXNlCiAgICBpZjogJHt7ICFjYW5jZWxsZWQoKSAmJiBnaXRodWIucmVmID09ICdyZWZzL2hlYWRzL21haW4nICYmIG5lZWRzLnJlbGVhc2Uub3V0cHV0cy5yZWxlYXNlLXJlY29yZCAhPSAnJyAmJiBuZWVkcy5yZWxlYXNlLm91dHB1dHMuZG9jcy1zaXRlcyAhPSAnJyAmJiBuZWVkcy5yZWxlYXNlLm91dHB1dHMuZG9jcy1zaXRlcyAhPSAnW10nIH19CiAgICBzdHJhdGVneToKICAgICAgZmFpbC1mYXN0OiBmYWxzZQogICAgICBtYXRyaXg6CiAgICAgICAgc2l0ZTogJHt7IGZyb21KU09OKG5lZWRzLnJlbGVhc2Uub3V0cHV0cy5kb2NzLXNpdGVzKSB9fQogICAgdXNlczogLi8uZ2l0aHViL3dvcmtmbG93cy9yZXBvY3RsLWRvY3MtZGVwbG95LnltbAogICAgd2l0aDoKICAgICAgc2l0ZTogJHt7IG1hdHJpeC5zaXRlIH19CiAgICAgIGNoYW5uZWw6IHN0YWJsZQogICAgICByZWxlYXNlOiAke3sgbmVlZHMucmVsZWFzZS5vdXRwdXRzLnJlbGVhc2UtcmVjb3JkIH19CiAgICBzZWNyZXRzOiBpbmhlcml0CgogIG5pZ2h0bHk6CiAgICBuYW1lOiBQdWJsaXNoIG5pZ2h0bHkKICAgIGlmOiAke3sgKGdpdGh1Yi5ldmVudF9uYW1lID09ICdzY2hlZHVsZScgJiYgZ2l0aHViLmV2ZW50LnNjaGVkdWxlID09ICcwIDE4ICogKiAqJykgfHwgKGdpdGh1Yi5ldmVudF9uYW1lID09ICd3b3JrZmxvd19kaXNwYXRjaCcgJiYgaW5wdXRzLm1vZGUgPT0gJ25pZ2h0bHknKSB9fQogICAgcnVucy1vbjogdWJ1bnR1LWxhdGVzdAogICAgdGltZW91dC1taW51dGVzOiA5MAogICAgZW52OgogICAgICBSRVBPQ1RMX05JR0hUTFlfUFJPVklERVI6IG5wbQogICAgICBSRVBPQ1RMX05JR0hUTFlfU0NIRURVTEU6ICcwIDE4ICogKiAqJwogICAgcGVybWlzc2lvbnM6CiAgICAgIGNvbnRlbnRzOiByZWFkCiAgICAgIGlkLXRva2VuOiB3cml0ZQogICAgc3RlcHM6CiAgICAgIC0gbmFtZTogVmFsaWRhdGUgbmlnaHRseSBzb3VyY2UKICAgICAgICBlbnY6CiAgICAgICAgICBERUZBVUxUX0JSQU5DSDogJHt7IGdpdGh1Yi5ldmVudC5yZXBvc2l0b3J5LmRlZmF1bHRfYnJhbmNoIH19CiAgICAgICAgcnVuOiB8CiAgICAgICAgICBpZiBbIC16ICIkREVGQVVMVF9CUkFOQ0giIF0gfHwgWyAiJEdJVEhVQl9SRUYiICE9ICJyZWZzL2hlYWRzLyRERUZBVUxUX0JSQU5DSCIgXTsgdGhlbgogICAgICAgICAgICBlY2hvICc6OmVycm9yOjpOaWdodGx5IHB1YmxpY2F0aW9uIHJlcXVpcmVzIHRoZSByZXBvc2l0b3J5IGRlZmF1bHQgYnJhbmNoLicKICAgICAgICAgICAgZXhpdCAxCiAgICAgICAgICBmaQoKICAgICAgLSBuYW1lOiBDaGVja291dCBuaWdodGx5IHNvdXJjZQogICAgICAgIGlkOiBuaWdodGx5LWNoZWNrb3V0CiAgICAgICAgdXNlczogYWN0aW9ucy9jaGVja291dEAzZDNjNDJlNWFhYzViYTgwNTgyNWRhNzY0MTBjMTgxMjczYmE5MGIxICMgdjcuMC4xCiAgICAgICAgd2l0aDoKICAgICAgICAgIHJlZjogJHt7IGdpdGh1Yi5zaGEgfX0KICAgICAgICAgIGZldGNoLWRlcHRoOiAwCiAgICAgICAgICBwZXJzaXN0LWNyZWRlbnRpYWxzOiBmYWxzZQoKICAgICAgLSB1c2VzOiBwbnBtL2FjdGlvbi1zZXR1cEBlYTE3YzY4ZGY4OTEyZWY1NDMzNTI3MjNjMTQ5YTg0ZjU2ZTNkNDEzICMgdjYuMS4wCgogICAgICAtIG5hbWU6IFNldHVwIE5vZGUuanMgZW52aXJvbm1lbnQKICAgICAgICB1c2VzOiBhY3Rpb25zL3NldHVwLW5vZGVAOTQ5ZmViMjQxM2Q2NDU4Nzk0ZGNkMjQ5MWM0YmFiYmJjZTBjMTVjMSAjIHY3LjEuMAogICAgICAgIHdpdGg6CiAgICAgICAgICBub2RlLXZlcnNpb246IDI0LjIyLjEKICAgICAgICAgIGNhY2hlOiBwbnBtCgogICAgICAtIG5hbWU6IEluc3RhbGwgbnBtIHdpdGggdHJ1c3RlZCBwdWJsaXNoaW5nIHN1cHBvcnQKICAgICAgICBpZDogbmlnaHRseS1ucG0KICAgICAgICBydW46IG5wbSBpbnN0YWxsIC0tZ2xvYmFsIG5wbUAxMS4xNi4wIC0tcmVnaXN0cnk9aHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcKCiAgICAgIC0gbmFtZTogSW5zdGFsbCBEZXBlbmRlbmNpZXMgd2l0aG91dCBsaWZlY3ljbGUgc2NyaXB0cwogICAgICAgIHJ1bjogcG5wbSBpbnN0YWxsIC0tZnJvemVuLWxvY2tmaWxlIC0taWdub3JlLXNjcmlwdHMKCiAgICAgIC0gbmFtZTogUHVibGlzaCBuaWdodGx5IHBhY2thZ2VzCiAgICAgICAgaWQ6IG5pZ2h0bHktcHVibGlzaAogICAgICAgIGVudjoKICAgICAgICAgIFJFUE9DVExfU05BUFNIT1RfUFVCTElTSDogJzEnCiAgICAgICAgICBSRVBPX1JFTEVBU0VfUEFDS0FHRTogJHt7IGlucHV0cy5wYWNrYWdlIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfVkVSU0lPTjogJHt7IGlucHV0cy52ZXJzaW9uIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfRFJZX1JVTjogJHt7IGlucHV0cy5kcnktcnVuIH19CiAgICAgICAgICBSRVBPX1JFTEVBU0VfUkVDT1ZFUllfU09VUkNFX1NIQTogJHt7IGlucHV0cy5zb3VyY2Utc2hhIH19CiAgICAgICAgcnVuOiB8CiAgICAgICAgICBhcmdzPSgtLXB1Ymxpc2ggLS1vdXRwdXQgIiRSVU5ORVJfVEVNUC9yZXBvY3RsLW5pZ2h0bHkiIC0tanNvbikKICAgICAgICAgIGlmIFsgIiRSRVBPX1JFTEVBU0VfRFJZX1JVTiIgPSAndHJ1ZScgXTsgdGhlbgogICAgICAgICAgICBhcmdzKz0oLS1kcnktcnVuKQogICAgICAgICAgZmkKICAgICAgICAgIHBucG0gZXhlYyByZXBvIHJlbGVhc2UgbmlnaHRseSAiJHthcmdzW0BdfSIKCiAgICAgIC0gbmFtZTogUHJlc2VydmUgbmlnaHRseSBkaWFnbm9zdGljcwogICAgICAgIGlmOiAke3sgYWx3YXlzKCkgfX0KICAgICAgICB1c2VzOiBhY3Rpb25zL3VwbG9hZC1hcnRpZmFjdEBjZjQzMGUwMzBkZGJiNWIwYWJmOTNkMjI5NjJmNDc1MmYzNjQ2Y2Q5ICMgdjcuMC4yCiAgICAgICAgd2l0aDoKICAgICAgICAgIG5hbWU6IG5pZ2h0bHktJHt7IGdpdGh1Yi5ydW5faWQgfX0tJHt7IGdpdGh1Yi5ydW5fYXR0ZW1wdCB9fQogICAgICAgICAgcGF0aDogfAogICAgICAgICAgICAke3sgcnVubmVyLnRlbXAgfX0vcmVwb2N0bC1uaWdodGx5LyouanNvbgogICAgICAgICAgICAke3sgcnVubmVyLnRlbXAgfX0vcmVwb2N0bC1uaWdodGx5LyoqL25pZ2h0bHktcmVwb3J0Lmpzb24KICAgICAgICAgICAgJHt7IHJ1bm5lci50ZW1wIH19L3JlcG9jdGwtbmlnaHRseS8qKi9jb25zdW1lci1yZXBvcnQuanNvbgogICAgICAgICAgICAke3sgcnVubmVyLnRlbXAgfX0vcmVwb2N0bC1uaWdodGx5LyoqL3NuYXBzaG90LXJlcG9ydC5qc29uCiAgICAgICAgICAgICR7eyBydW5uZXIudGVtcCB9fS9yZXBvY3RsLW5pZ2h0bHkvKiovdGFyYmFsbHMvKiovKi50Z3oKICAgICAgICAgIGlmLW5vLWZpbGVzLWZvdW5kOiBpZ25vcmUKICAgICAgICAgIHJldGVudGlvbi1kYXlzOiAxNAoKICBvaWRjLWF1ZGl0OgogICAgbmFtZTogQXVkaXQgbnBtIE9JREMKICAgIGlmOiAke3sgZ2l0aHViLmV2ZW50X25hbWUgPT0gJ3dvcmtmbG93X2Rpc3BhdGNoJyAmJiBpbnB1dHMubW9kZSA9PSAnb2lkYy1hdWRpdCcgfX0KICAgIHJ1bnMtb246IHVidW50dS1sYXRlc3QKICAgIHBlcm1pc3Npb25zOgogICAgICBjb250ZW50czogcmVhZAogICAgICBpZC10b2tlbjogd3JpdGUKICAgIHN0ZXBzOgogICAgICAtIG5hbWU6IENoZWNrb3V0IFJlcG8KICAgICAgICB1c2VzOiBhY3Rpb25zL2NoZWNrb3V0QDNkM2M0MmU1YWFjNWJhODA1ODI1ZGE3NjQxMGMxODEyNzNiYTkwYjEgIyB2Ny4wLjEKICAgICAgICB3aXRoOgogICAgICAgICAgcGVyc2lzdC1jcmVkZW50aWFsczogZmFsc2UKCiAgICAgIC0gdXNlczogcG5wbS9hY3Rpb24tc2V0dXBAZWExN2M2OGRmODkxMmVmNTQzMzUyNzIzYzE0OWE4NGY1NmUzZDQxMyAjIHY2LjEuMAoKICAgICAgLSBuYW1lOiBTZXR1cCBOb2RlLmpzIGVudmlyb25tZW50CiAgICAgICAgdXNlczogYWN0aW9ucy9zZXR1cC1ub2RlQDk0OWZlYjI0MTNkNjQ1ODc5NGRjZDI0OTFjNGJhYmJiY2UwYzE1YzEgIyB2Ny4xLjAKICAgICAgICB3aXRoOgogICAgICAgICAgbm9kZS12ZXJzaW9uOiAyNC4yMi4xCiAgICAgICAgICBjYWNoZTogcG5wbQoKICAgICAgLSBuYW1lOiBJbnN0YWxsIERlcGVuZGVuY2llcyB3aXRob3V0IGxpZmVjeWNsZSBzY3JpcHRzCiAgICAgICAgcnVuOiBwbnBtIGluc3RhbGwgLS1mcm96ZW4tbG9ja2ZpbGUgLS1pZ25vcmUtc2NyaXB0cwoKICAgICAgLSBuYW1lOiBBdWRpdCBldmVyeSBwdWJsaXNoYWJsZSBwYWNrYWdlCiAgICAgICAgZW52OgogICAgICAgICAgUkVQT19SRUxFQVNFX1BBQ0tBR0U6ICR7eyBpbnB1dHMucGFja2FnZSB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1ZFUlNJT046ICR7eyBpbnB1dHMudmVyc2lvbiB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX0RSWV9SVU46ICR7eyBpbnB1dHMuZHJ5LXJ1biB9fQogICAgICAgICAgUkVQT19SRUxFQVNFX1JFQ09WRVJZX1NPVVJDRV9TSEE6ICR7eyBpbnB1dHMuc291cmNlLXNoYSB9fQogICAgICAgIHJ1bjogcG5wbSBleGVjIHJlcG8gcmVsZWFzZSBjaSAtLW1vZGUgb2lkYy1hdWRpdAo=" + } +} diff --git a/.repoctl/baselines/root/ad6a01e589b8b1b214ca310dbb8d2e4314f6c612b921050c73c97455de43884d.json b/.repoctl/baselines/root/ad6a01e589b8b1b214ca310dbb8d2e4314f6c612b921050c73c97455de43884d.json new file mode 100644 index 00000000..ab58a9a9 --- /dev/null +++ b/.repoctl/baselines/root/ad6a01e589b8b1b214ca310dbb8d2e4314f6c612b921050c73c97455de43884d.json @@ -0,0 +1,14 @@ +{ + "schemaVersion": 1, + "path": "lefthook.yml", + "source": { + "package": "@icebreakers/monorepo-templates", + "version": "3.0.1", + "assetPath": "lefthook.yml", + "hash": "99918e855a9eea4e01284944d6a75ff87ef66e99715cdaa98f0598b61443e638" + }, + "upstream": { + "hash": "99918e855a9eea4e01284944d6a75ff87ef66e99715cdaa98f0598b61443e638", + "content": "IyByZXBvY3RsLW1hbmFnZWQ6IGhvb2tzL3YxCmdsb2JfbWF0Y2hlcjogZG91Ymxlc3RhcgoKcHJlLWNvbW1pdDoKICBwaXBlZDogdHJ1ZQogIGpvYnM6CiAgICAtIG5hbWU6IGVzbGludAogICAgICBnbG9iOiAnKiovKi57anMsanN4LG1qcyx0cyx0c3gsbXRzLGN0cyx2dWUsYXN0cm8sanNvbixtZCxtZHgsaHRtbCx5bWwseWFtbH0nCiAgICAgICMgQXZvaWQgTGVmdGhvb2sgMi4yLjIncyBXaW5kb3dzIHNoZWxsIHF1b3RpbmcgZm9yIGFwb3N0cm9waGVzIGluIHBhdGhzLgogICAgICAjIEtlZXAgdGhlc2UgR2l0IHBhdGhzcGVjcyBhbGlnbmVkIHdpdGggZ2xvYiBhYm92ZS4KICAgICAgcnVuOiA+LQogICAgICAgIGdpdCBkaWZmIC0tY2FjaGVkIC0tbmFtZS1vbmx5IC0tZGlmZi1maWx0ZXI9QUNNUiAteiAtLQogICAgICAgICcqLmpzJyAnKi5qc3gnICcqLm1qcycgJyoudHMnICcqLnRzeCcgJyoubXRzJyAnKi5jdHMnICcqLnZ1ZScgJyouYXN0cm8nCiAgICAgICAgJyouanNvbicgJyoubWQnICcqLm1keCcgJyouaHRtbCcgJyoueW1sJyAnKi55YW1sJwogICAgICAgIHwgeGFyZ3MgLTAgLXIgcG5wbSBleGVjIGVzbGludCAtLWZpeCAtLQogICAgICBzdGFnZV9maXhlZDogdHJ1ZQogICAgLSBuYW1lOiBzdHlsZWxpbnQKICAgICAgZ2xvYjogJyoqLyoue3Z1ZSxjc3Msc2NzcyxzYXNzLGxlc3N9JwogICAgICBydW46ID4tCiAgICAgICAgZ2l0IGRpZmYgLS1jYWNoZWQgLS1uYW1lLW9ubHkgLS1kaWZmLWZpbHRlcj1BQ01SIC16IC0tCiAgICAgICAgJyoudnVlJyAnKi5jc3MnICcqLnNjc3MnICcqLnNhc3MnICcqLmxlc3MnCiAgICAgICAgfCB4YXJncyAtMCAtciBwbnBtIGV4ZWMgc3R5bGVsaW50IC0tZml4IC0tYWxsb3ctZW1wdHktaW5wdXQgLS0KICAgICAgc3RhZ2VfZml4ZWQ6IHRydWUKICAgIC0gbmFtZTogdHlwZWNoZWNrCiAgICAgIHJ1bjogcG5wbSBleGVjIHJlcG8gdmVyaWZ5IHN0YWdlZC10eXBlY2hlY2sKCmNvbW1pdC1tc2c6CiAgam9iczoKICAgIC0gbmFtZTogY29tbWl0bGludAogICAgICBydW46IHBucG0gZXhlYyByZXBvIHZlcmlmeSBjb21taXQtbXNnICJ7MX0iCgpwcmUtcHVzaDoKICBwaXBlZDogdHJ1ZQogIGpvYnM6CiAgICAtIG5hbWU6IGxpbnQKICAgICAgcnVuOiBwbnBtIGxpbnQKICAgIC0gbmFtZTogdHlwZWNoZWNrCiAgICAgIHJ1bjogcG5wbSB0eXBlY2hlY2sK" + } +} diff --git a/.repoctl/baselines/root/d4ed323cdf9bc51e993369581f3bc29a355bec3f90416ab0057bb82604468391.json b/.repoctl/baselines/root/d4ed323cdf9bc51e993369581f3bc29a355bec3f90416ab0057bb82604468391.json new file mode 100644 index 00000000..dc06835e --- /dev/null +++ b/.repoctl/baselines/root/d4ed323cdf9bc51e993369581f3bc29a355bec3f90416ab0057bb82604468391.json @@ -0,0 +1,14 @@ +{ + "schemaVersion": 1, + "path": ".github/workflows/repoctl-docs-deploy.yml", + "source": { + "package": "@icebreakers/monorepo-templates", + "version": "3.0.1", + "assetPath": ".github/workflows/repoctl-docs-deploy.yml", + "hash": "4c108756f1af591febb679f9de070b81273a80a89751821cc853e33c7f62fafe" + }, + "upstream": { + "hash": "4c108756f1af591febb679f9de070b81273a80a89751821cc853e33c7f62fafe", + "content": "IyByZXBvY3RsLW1hbmFnZWQ6IGRvY3MtZGVwbG95L3YxCm5hbWU6IERlcGxveSBkb2N1bWVudGF0aW9uCgpvbjoKICB3b3JrZmxvd19jYWxsOgogICAgaW5wdXRzOgogICAgICBzaXRlOgogICAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAgICAgdHlwZTogc3RyaW5nCiAgICAgIGNoYW5uZWw6CiAgICAgICAgcmVxdWlyZWQ6IHRydWUKICAgICAgICB0eXBlOiBzdHJpbmcKICAgICAgc291cmNlLXNoYToKICAgICAgICByZXF1aXJlZDogZmFsc2UKICAgICAgICBkZWZhdWx0OiAnJwogICAgICAgIHR5cGU6IHN0cmluZwogICAgICByZWxlYXNlOgogICAgICAgIHJlcXVpcmVkOiBmYWxzZQogICAgICAgIGRlZmF1bHQ6ICcnCiAgICAgICAgdHlwZTogc3RyaW5nCiAgICAgIGNvbW1pdHM6CiAgICAgICAgcmVxdWlyZWQ6IGZhbHNlCiAgICAgICAgZGVmYXVsdDogJycKICAgICAgICB0eXBlOiBzdHJpbmcKCnBlcm1pc3Npb25zOgogIGNvbnRlbnRzOiB3cml0ZQoKY29uY3VycmVuY3k6CiAgZ3JvdXA6IGRvY3MtJHt7IGlucHV0cy5zaXRlIH19LSR7eyBpbnB1dHMuY2hhbm5lbCB9fQogIGNhbmNlbC1pbi1wcm9ncmVzczogZmFsc2UKCmpvYnM6CiAgZGVwbG95OgogICAgaWY6ICR7eyBnaXRodWIucmVmID09ICdyZWZzL2hlYWRzL21haW4nICYmIGdpdGh1Yi5ldmVudC5yZXBvc2l0b3J5LmRlZmF1bHRfYnJhbmNoID09ICdtYWluJyB9fQogICAgcnVucy1vbjogdWJ1bnR1LWxhdGVzdAogICAgZW52aXJvbm1lbnQ6IGRvY3MtJHt7IGlucHV0cy5zaXRlIH19LSR7eyBpbnB1dHMuY2hhbm5lbCB9fQogICAgc3RlcHM6CiAgICAgIC0gdXNlczogYWN0aW9ucy9jaGVja291dEAzZDNjNDJlNWFhYzViYTgwNTgyNWRhNzY0MTBjMTgxMjczYmE5MGIxICMgdjcuMC4xCiAgICAgICAgd2l0aDoKICAgICAgICAgIGZldGNoLWRlcHRoOiAwCiAgICAgICAgICByZWY6IG1haW4KICAgICAgICAgIHBlcnNpc3QtY3JlZGVudGlhbHM6IGZhbHNlCgogICAgICAtIHVzZXM6IHBucG0vYWN0aW9uLXNldHVwQGVhMTdjNjhkZjg5MTJlZjU0MzM1MjcyM2MxNDlhODRmNTZlM2Q0MTMgIyB2Ni4xLjAKCiAgICAgIC0gdXNlczogYWN0aW9ucy9zZXR1cC1ub2RlQDk0OWZlYjI0MTNkNjQ1ODc5NGRjZDI0OTFjNGJhYmJiY2UwYzE1YzEgIyB2Ny4xLjAKICAgICAgICB3aXRoOgogICAgICAgICAgbm9kZS12ZXJzaW9uOiAyNC4yMi4xCiAgICAgICAgICBjYWNoZTogcG5wbQoKICAgICAgLSBydW46IHBucG0gaW5zdGFsbCAtLWZyb3plbi1sb2NrZmlsZQoKICAgICAgLSBuYW1lOiBQbGFuIGFuZCBkZXBsb3kgdGhlIHNlbGVjdGVkIGRvY3VtZW50YXRpb24gc291cmNlCiAgICAgICAgZW52OgogICAgICAgICAgR0lUSFVCX1RPS0VOOiAke3sgZ2l0aHViLnRva2VuIH19CiAgICAgICAgICBSRVBPX0RPQ1NfU0lURTogJHt7IGlucHV0cy5zaXRlIH19CiAgICAgICAgICBSRVBPX0RPQ1NfQ0hBTk5FTDogJHt7IGlucHV0cy5jaGFubmVsIH19CiAgICAgICAgICBSRVBPX0RPQ1NfU09VUkNFX1NIQTogJHt7IGlucHV0cy5zb3VyY2Utc2hhIH19CiAgICAgICAgICBSRVBPX0RPQ1NfUkVMRUFTRTogJHt7IGlucHV0cy5yZWxlYXNlIH19CiAgICAgICAgICBSRVBPX0RPQ1NfQ09NTUlUUzogJHt7IGlucHV0cy5jb21taXRzIH19CiAgICAgICAgICBSRVBPX0RPQ1NfQ09OQ1VSUkVOQ1lfR1JPVVA6IGRvY3MtJHt7IGlucHV0cy5zaXRlIH19LSR7eyBpbnB1dHMuY2hhbm5lbCB9fQogICAgICAgICAgQ0xPVURGTEFSRV9BUElfVE9LRU46ICR7eyBzZWNyZXRzLkNMT1VERkxBUkVfQVBJX1RPS0VOIH19CiAgICAgICAgICBDTE9VREZMQVJFX0FDQ09VTlRfSUQ6ICR7eyBzZWNyZXRzLkNMT1VERkxBUkVfQUNDT1VOVF9JRCB8fCB2YXJzLkNMT1VERkxBUkVfQUNDT1VOVF9JRCB9fQogICAgICAgIHJ1bjogfAogICAgICAgICAgYXJncz0oIiRSRVBPX0RPQ1NfU0lURSIgLS1jaGFubmVsICIkUkVQT19ET0NTX0NIQU5ORUwiKQogICAgICAgICAgaWYgWyAtbiAiJFJFUE9fRE9DU19TT1VSQ0VfU0hBIiBdOyB0aGVuIGFyZ3MrPSgtLXNvdXJjZS1zaGEgIiRSRVBPX0RPQ1NfU09VUkNFX1NIQSIpOyBmaQogICAgICAgICAgaWYgWyAtbiAiJFJFUE9fRE9DU19SRUxFQVNFIiBdOyB0aGVuIGFyZ3MrPSgtLXJlbGVhc2UgIiRSRVBPX0RPQ1NfUkVMRUFTRSIpOyBmaQogICAgICAgICAgaWYgWyAtbiAiJFJFUE9fRE9DU19DT01NSVRTIiBdOyB0aGVuCiAgICAgICAgICAgIHJlYWQgLXIgLWEgY29tbWl0cyA8PDwgIiRSRVBPX0RPQ1NfQ09NTUlUUyIKICAgICAgICAgICAgYXJncys9KC0tY29tbWl0cyAiJHtjb21taXRzW0BdfSIpCiAgICAgICAgICBmaQogICAgICAgICAgcG5wbSBleGVjIHJlcG8gZG9jcyBwbGFuICIke2FyZ3NbQF19IiAtLWpzb24KICAgICAgICAgIHBucG0gZXhlYyByZXBvIGRvY3MgZGVwbG95ICIke2FyZ3NbQF19IiAtLWpzb24K" + } +} diff --git a/apps/open-source/playwright.config.ts b/apps/open-source/playwright.config.ts index 731dbf60..88e78331 100644 --- a/apps/open-source/playwright.config.ts +++ b/apps/open-source/playwright.config.ts @@ -6,6 +6,8 @@ const browserChannel = process.env.PLAYWRIGHT_CHANNEL export default defineConfig({ testDir: './tests/e2e', fullyParallel: true, + // Particle and canvas assertions need a bounded rendering workload on CI. + workers: 2, webServer: { // Serve the exact deployment artifact, including the Pages relative paths. command: 'node scripts/serve-test-site.mjs', @@ -13,6 +15,7 @@ export default defineConfig({ reuseExistingServer: false, }, use: { + headless: true, baseURL: 'http://127.0.0.1:45322', locale: 'zh-CN', ...(browserChannel ? { channel: browserChannel } : {}), diff --git a/apps/open-source/scripts/prepare-pages-content.ts b/apps/open-source/scripts/prepare-pages-content.ts index f3d55da9..a090ccaa 100644 --- a/apps/open-source/scripts/prepare-pages-content.ts +++ b/apps/open-source/scripts/prepare-pages-content.ts @@ -3,10 +3,12 @@ import { basename, join, resolve } from 'node:path' import process from 'node:process' import { projectsDirectory } from '@weapp-io/project-catalog/paths' import { projectDefinitionSchema } from '../src/content/schemas' +import { getBuildChannel } from '../src/lib/build-channel' import { getSiteProfile } from '../src/lib/deployment' import { createSiteResources } from '../src/lib/site-resources' const site = getSiteProfile() +const channel = getBuildChannel() const root = resolve(process.argv[2] || join(import.meta.dirname, '..', site.outputDir)) const projectDirectory = projectsDirectory const projects = await Promise.all((await readdir(projectDirectory)).filter(file => file.endsWith('.json')).map(async file => ({ @@ -15,9 +17,16 @@ const projects = await Promise.all((await readdir(projectDirectory)).filter(file }))) projects.sort((left, right) => left.data.order - right.data.order) -for (const [name, content] of Object.entries(createSiteResources(site, projects))) { +// A repeated stable preparation must remove preview-only response headers. +await rm(join(root, '_headers'), { force: true }) +for (const [name, content] of Object.entries(createSiteResources(site, projects, channel))) { await writeFile(join(root, name), content, 'utf8') } -await writeFile(join(root, 'CNAME'), `${new URL(site.origin).hostname}\n`, 'utf8') +if (channel === 'stable') { + await writeFile(join(root, 'CNAME'), `${new URL(site.origin).hostname}\n`, 'utf8') +} +else { + await rm(join(root, 'CNAME'), { force: true }) +} await rm(join(root, '.nojekyll'), { force: true }) diff --git a/apps/open-source/scripts/validate-build.ts b/apps/open-source/scripts/validate-build.ts index 5d869b07..7d380f8a 100644 --- a/apps/open-source/scripts/validate-build.ts +++ b/apps/open-source/scripts/validate-build.ts @@ -3,10 +3,13 @@ import { join, relative, resolve } from 'node:path' import process from 'node:process' import { projectsDirectory } from '@weapp-io/project-catalog/paths' import { parse } from 'node-html-parser' +import { getBuildChannel } from '../src/lib/build-channel' import { getSiteProfile, isRetiredOpenSourcePath } from '../src/lib/deployment' const root = resolve(import.meta.dirname, '..') const site = getSiteProfile() +const channel = getBuildChannel() +const preview = channel === 'preview' const dist = resolve(root, site.outputDir) const projectIds = (await readdir(projectsDirectory)).filter(file => file.endsWith('.json')).map(file => file.slice(0, -5)) const expectedFiles = [ @@ -24,7 +27,9 @@ const expectedFiles = [ 'og.png', 'og.svg', 'bimi/logo.svg', - ...(['CNAME', '404/index.html']), + ...(preview ? ['_headers'] : []), + '404/index.html', + ...(preview ? [] : ['CNAME']), ] const retiredDocsHosts = ['tw.icebreaker.top', 'vite.icebreaker.top'] const errors: string[] = [] @@ -79,7 +84,7 @@ for (const file of expectedFiles) { } } -for (const name of ['.nojekyll', '.well-known/bimi']) { +for (const name of ['.nojekyll', '.well-known/bimi', ...(preview ? ['CNAME'] : ['_headers'])]) { try { await access(resolve(dist, name)) errors.push(`Forbidden build output: ${name}`) @@ -89,14 +94,23 @@ for (const name of ['.nojekyll', '.well-known/bimi']) { } } -try { - const cname = (await readFile(resolve(dist, 'CNAME'), 'utf8')).trim() - if (cname !== new URL(site.origin).hostname) { - errors.push(`CNAME: expected ${new URL(site.origin).hostname}, received ${cname || '(empty)'}`) +if (!preview) { + try { + const cname = (await readFile(resolve(dist, 'CNAME'), 'utf8')).trim() + if (cname !== new URL(site.origin).hostname) { + errors.push(`CNAME: expected ${new URL(site.origin).hostname}, received ${cname || '(empty)'}`) + } + } + catch { + errors.push('CNAME: unable to read Pages hostname') } } -catch { - errors.push('CNAME: unable to read Pages hostname') + +if (preview) { + const headers = await readFile(resolve(dist, '_headers'), 'utf8').catch(() => '') + if (!/^\/\*\n\s+X-Robots-Tag: noindex, nofollow\n$/i.test(headers)) { + errors.push('_headers: preview responses must disallow indexing for every path') + } } const cssFiles = (await readdir(dist, { recursive: true })).filter(file => file.endsWith('.css')) @@ -131,6 +145,21 @@ for (const file of htmlFiles) { const robots = document.querySelector('meta[name="robots"]')?.getAttribute('content') const schemas = document.querySelectorAll('script[type="application/ld+json"]') + if (document.querySelector('html')?.getAttribute('data-site-channel') !== channel) { + errors.push(`${label}: build channel must be ${channel}`) + } + const notice = document.querySelector('[data-preview-notice]') + const expectsNotice = preview && !retiredRedirect + if (expectsNotice) { + const message = pagePath.startsWith('/en/') ? 'Preview version. Content may change.' : '预览版本,内容可能更新。' + if (!notice?.text.includes(message) || notice.querySelector('a')?.getAttribute('href') !== expectedCanonical) { + errors.push(`${label}: missing localized preview notice and production link`) + } + } + else if (notice) { + errors.push(`${label}: unexpected preview notice`) + } + if (canonical !== expectedCanonical) { errors.push(`${label}: expected canonical ${expectedCanonical}, received ${canonical ?? '(missing)'}`) } @@ -145,8 +174,11 @@ for (const file of htmlFiles) { if (descriptions.length !== 1 || !descriptions[0].getAttribute('content')?.trim()) { errors.push(`${label}: missing unique description`) } - if (!robots) { - errors.push(`${label}: missing robots directive`) + if (preview && robots !== 'noindex, follow') { + errors.push(`${label}: preview pages must be noindex`) + } + else if (!preview && !retiredRedirect && !['404.html', '404/index.html', 'en/404/index.html'].includes(label) && robots !== 'index, follow') { + errors.push(`${label}: stable content pages must remain indexable`) } if ((retiredRedirect || label === '404.html' || label === '404/index.html' || label === 'en/404/index.html') && !robots?.includes('noindex')) { errors.push(`${label}: compatibility redirects and 404 pages must be noindex`) @@ -260,8 +292,13 @@ for (const file of [...sitemapFiles, 'robots.txt', 'llms.txt', 'llms-full.txt', } } } - if (file === 'robots.txt' && !contents.includes(`Sitemap: ${site.origin}/sitemap-index.xml`)) { - errors.push(`${file}: sitemap must use this site's origin`) + if (file === 'robots.txt') { + const expectedRobots = preview + ? 'User-agent: *\nDisallow: /\n' + : `User-agent: *\nAllow: /\n\nSitemap: ${site.origin}/sitemap-index.xml\n` + if (contents !== expectedRobots) { + errors.push(`${file}: incorrect crawler policy for ${channel}`) + } } if (file === 'releases.xml' && !contents.includes(`${site.origin}/`)) { errors.push(`${file}: release channel must use this site's origin`) diff --git a/apps/open-source/src/components/PreviewNotice.astro b/apps/open-source/src/components/PreviewNotice.astro new file mode 100644 index 00000000..d318d996 --- /dev/null +++ b/apps/open-source/src/components/PreviewNotice.astro @@ -0,0 +1,71 @@ +--- +import type { Locale } from '../types/project' + +interface Props { + locale: Locale + productionUrl: string +} + +const { locale, productionUrl } = Astro.props +const label = locale === 'zh-CN' ? '预览版本,内容可能更新。' : 'Preview version. Content may change.' +const linkLabel = locale === 'zh-CN' ? '访问正式网站' : 'Visit the live website' +--- + + + + + + diff --git a/apps/open-source/src/components/ProjectRedirect.astro b/apps/open-source/src/components/ProjectRedirect.astro index 4ea0d58c..3ee751f3 100644 --- a/apps/open-source/src/components/ProjectRedirect.astro +++ b/apps/open-source/src/components/ProjectRedirect.astro @@ -2,6 +2,7 @@ import type { Locale } from '../types/project' import { localizePath } from '../i18n/ui' import { getSiteProfile } from '../lib/deployment' +import { getBuildChannel } from '../lib/build-channel' import { relativeSiteUrl } from '../lib/github-pages-paths' interface Props { locale: Locale } @@ -12,7 +13,7 @@ const relativeDestination = relativeSiteUrl(Astro.url.pathname.replace(/^\/+|\/+ const title = locale === 'zh-CN' ? '浏览开源项目' : 'Explore open-source projects' --- - + diff --git a/apps/open-source/src/layouts/BaseLayout.astro b/apps/open-source/src/layouts/BaseLayout.astro index fe2d15b3..f76c899b 100644 --- a/apps/open-source/src/layouts/BaseLayout.astro +++ b/apps/open-source/src/layouts/BaseLayout.astro @@ -3,11 +3,13 @@ import '@fontsource-variable/geist/index.css' import '@fontsource-variable/geist-mono/index.css' import '../styles/global.css' import { getSiteProfile } from '../lib/deployment' +import { getBuildChannel } from '../lib/build-channel' import type { Locale } from '../types/project' import { alternatePath } from '../i18n/ui' import { localeRedirectScript } from '../lib/locale-redirect' import { canonicalUrl, serializeJsonLd, webPageSchema } from '../lib/seo' import AnalyticsPreferences from '../components/AnalyticsPreferences.astro' +import PreviewNotice from '../components/PreviewNotice.astro' interface Props { locale: Locale @@ -24,6 +26,7 @@ interface Props { } const profile = getSiteProfile() +const channel = getBuildChannel() const { locale, title, @@ -47,7 +50,7 @@ const skipLabel = locale === 'zh-CN' ? '跳到主要内容' : 'Skip to main cont --- - + {localeSwitch && } @@ -57,7 +60,7 @@ const skipLabel = locale === 'zh-CN' ? '跳到主要内容' : 'Skip to main cont - + @@ -100,6 +103,7 @@ const skipLabel = locale === 'zh-CN' ? '跳到主要内容' : 'Skip to main cont {skipLabel} + {channel === 'preview' && } + + diff --git a/apps/web/src/layouts/BaseLayout.astro b/apps/web/src/layouts/BaseLayout.astro index fe2d15b3..f76c899b 100644 --- a/apps/web/src/layouts/BaseLayout.astro +++ b/apps/web/src/layouts/BaseLayout.astro @@ -3,11 +3,13 @@ import '@fontsource-variable/geist/index.css' import '@fontsource-variable/geist-mono/index.css' import '../styles/global.css' import { getSiteProfile } from '../lib/deployment' +import { getBuildChannel } from '../lib/build-channel' import type { Locale } from '../types/project' import { alternatePath } from '../i18n/ui' import { localeRedirectScript } from '../lib/locale-redirect' import { canonicalUrl, serializeJsonLd, webPageSchema } from '../lib/seo' import AnalyticsPreferences from '../components/AnalyticsPreferences.astro' +import PreviewNotice from '../components/PreviewNotice.astro' interface Props { locale: Locale @@ -24,6 +26,7 @@ interface Props { } const profile = getSiteProfile() +const channel = getBuildChannel() const { locale, title, @@ -47,7 +50,7 @@ const skipLabel = locale === 'zh-CN' ? '跳到主要内容' : 'Skip to main cont --- - + {localeSwitch && } @@ -57,7 +60,7 @@ const skipLabel = locale === 'zh-CN' ? '跳到主要内容' : 'Skip to main cont - + @@ -100,6 +103,7 @@ const skipLabel = locale === 'zh-CN' ? '跳到主要内容' : 'Skip to main cont {skipLabel} + {channel === 'preview' && }