@rtorcato/repo-tooling 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -142,11 +142,34 @@ export async function checkBrand(dir) {
142
142
  if (problems.length > 0) {
143
143
  return { check, status: 'drift', detail: problems.join('; '), hint: BRAND_HINT };
144
144
  }
145
+ // Name the pieces still missing (#679). Severity is unchanged: brand is optional.
146
+ const missing = [];
147
+ if (!(await has('brand/favicon.svg')))
148
+ missing.push('favicon (brand/favicon.svg)');
149
+ const unrendered = [];
150
+ for (const n of ['banner', 'banner-mobile', 'social-card', 'favicon-512']) {
151
+ if (!(await has(`brand/${n}.png`)))
152
+ unrendered.push(`${n}.png`);
153
+ }
154
+ if (unrendered.length > 0)
155
+ missing.push(`rendered PNGs (brand/${unrendered.join(', ')})`);
156
+ const readmeFile = path.join(dir, 'README.md');
157
+ const readmeText = (await fs.pathExists(readmeFile)) ? await fs.readFile(readmeFile, 'utf-8') : '';
158
+ if (!/brand\/banner(?:-mobile)?\.png/.test(readmeText))
159
+ missing.push('README banner');
145
160
  if (!brandDir) {
146
161
  return {
147
162
  check,
148
163
  status: 'optional-missing',
149
- detail: 'no brand/ folder — the repo ships no regenerable brand sources',
164
+ detail: `no brand/ folder — missing: ${missing.join('; ')}`,
165
+ hint: BRAND_HINT,
166
+ };
167
+ }
168
+ if (missing.length > 0) {
169
+ return {
170
+ check,
171
+ status: 'ok',
172
+ detail: `brand/ holds the SVG sources and render.sh; missing: ${missing.join('; ')}`,
150
173
  hint: BRAND_HINT,
151
174
  };
152
175
  }
package/dist/base/ci.js CHANGED
@@ -13,7 +13,9 @@
13
13
  /** Every job is gated on the skip-CI check; extra conditions are ANDed on. */
14
14
  const SKIP_GUARD = "needs.check-skip.outputs.should-skip != 'true'";
15
15
  /** Header through `jobs:` — triggers and concurrency are language-independent. */
16
- const WORKFLOW_HEADER = `name: 🚀 CI/CD Pipeline
16
+ /** The generated CI workflow's `name:` — the docs workflow's `workflow_run` must match it. */
17
+ export const CI_WORKFLOW_NAME = '🚀 CI/CD Pipeline';
18
+ const WORKFLOW_HEADER = `name: ${CI_WORKFLOW_NAME}
17
19
 
18
20
  on:
19
21
  push:
@@ -24,7 +26,9 @@ on:
24
26
 
25
27
  concurrency:
26
28
  group: \${{ github.workflow }}-\${{ github.ref }}
27
- cancel-in-progress: true
29
+ # Never cancel on main: a newer push would kill a release that is waiting on
30
+ # approval or halfway through publishing.
31
+ cancel-in-progress: \${{ github.event_name == 'pull_request' }}
28
32
 
29
33
  jobs:
30
34
  `;
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'fs-extra';
3
3
  import selfPackageJson from '../../../package.json' with { type: 'json' };
4
+ import { CI_WORKFLOW_NAME } from '../../base/ci.js';
4
5
  import { coverageUploadWorkflow } from '../../base/checks.js';
5
6
  import { jsBadgeAudience } from '../../languages/js/checks.js';
6
7
  import { copyPreset, PRESETS } from '../utils/copy-preset.js';
@@ -344,15 +345,18 @@ on:
344
345
  paths:
345
346
  - 'apps/docs/**'
346
347
  - '.github/workflows/docs.yml'
347
- # The changelog page is built from GitHub Releases, and no release commit
348
- # lands on main any more (see #417) — so a push trigger alone would never
349
- # rebuild the site after a release.
350
- release:
351
- types: [published]
348
+ # The changelog page is built from GitHub Releases. A release created with
349
+ # GITHUB_TOKEN never fires \`release: published\`, so rebuild once CI (which
350
+ # runs semantic-release) succeeds on main instead — no PAT needed (#691).
351
+ workflow_run:
352
+ workflows: ['${CI_WORKFLOW_NAME}']
353
+ types: [completed]
354
+ branches: [main]
352
355
  workflow_dispatch:
353
356
 
354
357
  jobs:
355
358
  docs:
359
+ if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
356
360
  permissions:
357
361
  contents: read
358
362
  pages: write
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Conventional-commit types that cut a release, mirroring the `releaseRules` in
3
+ * tooling/semantic-release (a test keeps the two in step). `feat!:` and `fix!:`
4
+ * start with these too, so breaking changes are covered.
5
+ */
6
+ export const RELEASE_TYPES = ['feat', 'fix', 'perf', 'refactor', 'revert', 'update'];
7
+ // Match only the START of the squash subject: the message carries the whole PR
8
+ // body, so searching it matched PRs that merely mentioned `BREAKING CHANGE`.
9
+ const RELEASE_IF = `github.ref == 'refs/heads/main' && (github.event_name == 'workflow_dispatch' || github.event_name == 'push' && (${RELEASE_TYPES.map((t) => `startsWith(github.event.head_commit.message, '${t}')`).join(' || ')}))`;
1
10
  /** Coverage is uploaded when Vitest is the test runner (it emits an lcov report). */
2
11
  export function usesCoverage(config) {
3
12
  return config.testing.framework === 'vitest';
@@ -175,7 +184,7 @@ ${attw}${publint}
175
184
  id: 'release',
176
185
  // Gate the publish on everything that ran before it.
177
186
  needs: jobs.map((job) => job.id),
178
- if: "github.ref == 'refs/heads/main'",
187
+ if: RELEASE_IF,
179
188
  extra: ` permissions:
180
189
  contents: write
181
190
  issues: write
@@ -224,7 +233,14 @@ ${attw}${publint}
224
233
  # for the package on npmjs.com (Settings → Trusted Publisher).
225
234
  env:
226
235
  GITHUB_TOKEN: \${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
227
- run: npx semantic-release`,
236
+ run: |
237
+ set -o pipefail
238
+ npx semantic-release 2>&1 | tee release.log
239
+ # semantic-release exits 0 when main moved on since this run started,
240
+ # publishing nothing (#690). Say so instead of going quietly green.
241
+ if grep -q "is behind the remote one" release.log; then
242
+ echo "::warning::main moved on; nothing was published. Re-run via workflow_dispatch."
243
+ fi`,
228
244
  });
229
245
  }
230
246
  return jobs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "One CLI to scaffold, audit and fix your repo's whole toolchain — linting, tests, commits, releases & CI.",
5
5
  "type": "module",
6
6
  "keywords": [