From 4269885e1f468c7d357212a8603f1a66a0fb3f97 Mon Sep 17 00:00:00 2001 From: "Ivan Gaiduk [SSW]" Date: Fri, 15 May 2026 08:23:46 +1000 Subject: [PATCH] Improve build starter templates action (#6855) Previously ran on a weekday cron with no version control over tina packages. Now triggers automatically after each publish, pins each tina package to its exact published version (packages carry different version numbers), and falls back to latest for packages not in the release. Lock files for non-tina dependencies are preserved. Manual dispatch supports both a flat version and a JSON package map for testing tagged/candidate builds. Note: pnpm is pinned to version 10 for now. Version 11 required explicitly specifying which packages are allowed to run scripts, which requires an update to all starter templates. After that's done - we can bump it. --- .github/workflows/build-starter-templates.yml | 105 +++++++++++++++++- .github/workflows/publish.yml | 27 ++++- 2 files changed, 123 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-starter-templates.yml b/.github/workflows/build-starter-templates.yml index 184120ab6c..2f5ac0a01e 100644 --- a/.github/workflows/build-starter-templates.yml +++ b/.github/workflows/build-starter-templates.yml @@ -2,8 +2,19 @@ name: Build TinaCMS Starter Templates on: workflow_dispatch: + inputs: + tina_version: + description: 'Version applied to any Tina package not listed in published_packages (semver, dist-tag, or snapshot tag, e.g. 2.5.0, latest, or my-branch). Defaults to latest.' + required: false + default: 'latest' + type: string + published_packages: + description: 'JSON array [{name, version}] of per-package versions to test. Use when packages carry different versions — e.g. a partial tagged release or a prod publish where only some packages changed. Packages omitted here fall back to tina_version.' + required: false + default: '' + type: string schedule: - - cron: '0 9 * * 1-5' + - cron: '0 9 * * 1' jobs: build-templates: @@ -26,14 +37,14 @@ jobs: steps: - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 name: Install pnpm with: - version: latest + version: '10' if: ${{ matrix.package-manager == 'pnpm' }} - name: Setup Hugo @@ -74,11 +85,91 @@ jobs: id: create-tina-app run: npx create-tina-app@latest template-repo --pkg-manager ${{ matrix.package-manager }} --template ${{ matrix.template }} --noTelemetry ${{ matrix.template == 'tina-docs' && '--theme default' || '' }} + - name: Install dependencies + id: install + run: | + cd template-repo + ${{ matrix.package-manager }} install + + - name: Update Tina packages to target version + id: update-tina + env: + PUBLISHED_PACKAGES: ${{ inputs.published_packages }} + TINA_VERSION: ${{ inputs.tina_version || 'latest' }} + run: | + cd template-repo + PKG_MANAGER="${{ matrix.package-manager }}" + + # Resolve versioned package specs for direct and dev dependencies separately + # so the add command preserves their original category in package.json. + # For each matching package: + # - Use the exact version from published_packages if it was part of this release. + # - Fall back to TINA_VERSION (default: "latest") for packages not in the release. + TINA_FILTER=' + def is_tina: . == "tinacms" or startswith("@tinacms/") or startswith("tinacms-") or startswith("next-tinacms-"); + def resolve($published; $fallback): + . as $pkg | (($published | map(select(.name == $pkg)) | first | .version) // $fallback); + ' + TINA_DEPS=$(jq -r --arg fallback "$TINA_VERSION" \ + --argjson published "${PUBLISHED_PACKAGES:-[]}" \ + "${TINA_FILTER}"' + (.dependencies // {}) | to_entries[] | + select(.key | is_tina) | + .key + "@" + (.key | resolve($published; $fallback)) + ' package.json | tr '\n' ' ') + TINA_DEV_DEPS=$(jq -r --arg fallback "$TINA_VERSION" \ + --argjson published "${PUBLISHED_PACKAGES:-[]}" \ + "${TINA_FILTER}"' + (.devDependencies // {}) | to_entries[] | + select(.key | is_tina) | + .key + "@" + (.key | resolve($published; $fallback)) + ' package.json | tr '\n' ' ') + + # Bypass the minimum release age gate for Tina packages only. + # The install step above ran with the gate fully active for all other dependencies. + # npm has no per-package exclusion (npm#8994); disable the gate for this project. + # .npmrc is ini-style so appending always wins (last value takes precedence). + echo "min-release-age=0" >> .npmrc + case "$PKG_MANAGER" in + pnpm) + # pnpm 11+ defaults to a 1440-minute gate. Whitelist Tina packages specifically + # rather than disabling the gate entirely. yq merges into any existing list + # and deduplicates, safe whether or not the file or key already exists. + touch pnpm-workspace.yaml + yq -i '.minimumReleaseAgeExclude += ["tinacms", "@tinacms/*"] | .minimumReleaseAgeExclude |= unique' pnpm-workspace.yaml + ;; + yarn) + # yarn berry 4.10+ supports npmPreapprovedPackages with glob patterns. + # yarn 1.x (bundled with Node) predates this feature — no-op if detected. + YARN_MAJOR=$(yarn --version 2>/dev/null | cut -d. -f1) + if [ "${YARN_MAJOR:-0}" -ge 4 ] 2>/dev/null; then + touch .yarnrc.yml + yq -i '.npmPreapprovedPackages += ["tinacms", "@tinacms/*"] | .npmPreapprovedPackages |= unique' .yarnrc.yml + fi + ;; + esac + + echo "Updating Tina packages — deps: $TINA_DEPS dev deps: $TINA_DEV_DEPS" + if [ -n "$TINA_DEPS" ]; then + case "$PKG_MANAGER" in + pnpm) pnpm add $TINA_DEPS ;; + yarn) yarn add $TINA_DEPS ;; + npm) npm install $TINA_DEPS ;; + esac + fi + if [ -n "$TINA_DEV_DEPS" ]; then + case "$PKG_MANAGER" in + pnpm) pnpm add -D $TINA_DEV_DEPS ;; + yarn) yarn add -D $TINA_DEV_DEPS ;; + npm) npm install --save-dev $TINA_DEV_DEPS ;; + esac + fi + - name: Run build id: build run: | cd template-repo - ${{ matrix.package-manager }} install && ${{ matrix.package-manager }} run build + ${{ matrix.package-manager }} run build - name: Report errors continue-on-error: false @@ -87,6 +178,10 @@ jobs: run: | if [[ "${{ steps.create-tina-app.outcome }}" == "failure" ]]; then ERROR_STEP="create-tina-app" + elif [[ "${{ steps.install.outcome }}" == "failure" ]]; then + ERROR_STEP="install" + elif [[ "${{ steps.update-tina.outcome }}" == "failure" ]]; then + ERROR_STEP="update-tina" else ERROR_STEP="build" fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3bc95590fa..0d6b974670 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,7 +41,7 @@ jobs: fetch-depth: 2 - name: Setup Node.js environment - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version-file: ".nvmrc" registry-url: "https://registry.npmjs.org" @@ -49,7 +49,7 @@ jobs: - name: Upgrade npm for OIDC support run: npm install -g npm@latest - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 name: Install pnpm id: pnpm-install with: @@ -229,7 +229,7 @@ jobs: fetch-depth: 0 - name: Setup Node.js environment - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version-file: ".nvmrc" registry-url: "https://registry.npmjs.org" @@ -237,7 +237,7 @@ jobs: - name: Upgrade npm for OIDC support run: npm install -g npm@latest - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 name: Install pnpm id: pnpm-install with: @@ -325,6 +325,25 @@ jobs: } token: ${{ steps.generate-token.outputs.token }} + - name: Trigger starter template builds + if: steps.changesets.outputs.published == 'true' + uses: actions/github-script@v7 + env: + PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} + with: + github-token: ${{ steps.generate-token.outputs.token }} + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'build-starter-templates.yml', + ref: 'main', + inputs: { + published_packages: process.env.PUBLISHED_PACKAGES || '[]' + } + }); + console.log('Triggered starter template builds with published packages'); + - name: Generate token for tinacloud if: steps.changesets.outputs.published == 'true' uses: actions/create-github-app-token@v1