@rm-industries/create-forge 0.4.0-beta.0 → 0.4.0-beta.2

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.
Files changed (29) hide show
  1. package/dist/index.mjs +27 -1
  2. package/dist/index.mjs.map +1 -1
  3. package/dist/template/.github/actions/setup-project/action.yml +24 -0
  4. package/dist/template/.github/dependabot.yml +45 -0
  5. package/dist/template/.github/workflows/automation.yml +79 -0
  6. package/dist/template/.github/workflows/project.yml +262 -0
  7. package/dist/template/.github/workflows/security.yml +70 -0
  8. package/dist/template/README.md +56 -0
  9. package/dist/template/astro.config.ts +5 -1
  10. package/dist/template/cspell.config.ts +1 -0
  11. package/dist/template/docs/github-pages.md +56 -0
  12. package/dist/template/package-lock.json +429 -500
  13. package/dist/template/package.json +8 -7
  14. package/dist/template/src/components/navigation/Footer.astro +2 -1
  15. package/dist/template/src/components/navigation/Navbar.astro +9 -5
  16. package/dist/template/src/components/navigation/Pagination.astro +4 -2
  17. package/dist/template/src/components/seo/SeoHead.astro +7 -6
  18. package/dist/template/src/components/ui/Card.astro +5 -2
  19. package/dist/template/src/config/deployment.test.ts +16 -0
  20. package/dist/template/src/config/deployment.ts +14 -0
  21. package/dist/template/src/integrations/sveltia/config.ts +3 -2
  22. package/dist/template/src/lib/paths.test.ts +26 -0
  23. package/dist/template/src/lib/paths.ts +17 -0
  24. package/dist/template/src/pages/404.astro +2 -1
  25. package/dist/template/src/pages/about.astro +5 -1
  26. package/dist/template/src/pages/index.astro +4 -3
  27. package/dist/template/src/pages/rss.xml.ts +2 -1
  28. package/dist/template/src/pages/site.webmanifest.ts +3 -2
  29. package/package.json +3 -3
@@ -0,0 +1,262 @@
1
+ ---
2
+ name: Project Continuous Integration
3
+
4
+ on: # yamllint disable-line rule:truthy
5
+ pull_request:
6
+ branches:
7
+ - main
8
+ push:
9
+ branches:
10
+ - main
11
+
12
+ permissions: {}
13
+
14
+ concurrency:
15
+ group: ${{ github.workflow }}-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ defaults:
19
+ run:
20
+ shell: bash
21
+
22
+ jobs:
23
+ format:
24
+ name: Format
25
+ runs-on: ubuntu-latest
26
+
27
+ permissions:
28
+ contents: read
29
+
30
+ steps:
31
+ - name: Checkout repository
32
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
33
+ with:
34
+ persist-credentials: false
35
+
36
+ - name: Setup project
37
+ uses: ./.github/actions/setup-project
38
+ with:
39
+ node-version: '26.x'
40
+
41
+ - name: Check formatting
42
+ run: npm run format
43
+
44
+ spellcheck:
45
+ name: Spellcheck
46
+ runs-on: ubuntu-latest
47
+
48
+ permissions:
49
+ contents: read
50
+
51
+ steps:
52
+ - name: Checkout repository
53
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
54
+ with:
55
+ persist-credentials: false
56
+
57
+ - name: Setup project
58
+ uses: ./.github/actions/setup-project
59
+ with:
60
+ node-version: '26.x'
61
+
62
+ - name: Check spelling
63
+ run: npm run spellcheck
64
+
65
+ static-quality:
66
+ name: Static quality
67
+ runs-on: ubuntu-latest
68
+
69
+ permissions:
70
+ contents: read
71
+
72
+ steps:
73
+ - name: Checkout repository
74
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
75
+ with:
76
+ persist-credentials: false
77
+
78
+ - name: Setup project
79
+ uses: ./.github/actions/setup-project
80
+ with:
81
+ node-version: '26.x'
82
+
83
+ - name: Run remaining static quality checks
84
+ run: npm run quality:static:ci
85
+
86
+ unit-tests:
87
+ name: Unit tests and coverage
88
+ runs-on: ubuntu-latest
89
+
90
+ permissions:
91
+ contents: read
92
+
93
+ steps:
94
+ - name: Checkout repository
95
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
96
+ with:
97
+ persist-credentials: false
98
+
99
+ - name: Setup project
100
+ uses: ./.github/actions/setup-project
101
+ with:
102
+ node-version: '26.x'
103
+
104
+ - name: Run unit tests with coverage
105
+ run: npm run test:coverage
106
+
107
+ - name: Upload coverage report
108
+ if: always()
109
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
110
+ with:
111
+ name: unit-coverage
112
+ path: coverage
113
+ if-no-files-found: error
114
+ retention-days: 7
115
+
116
+ build:
117
+ name: Production build
118
+ needs:
119
+ - format
120
+ - spellcheck
121
+ - static-quality
122
+ runs-on: ubuntu-latest
123
+
124
+ permissions:
125
+ contents: read
126
+
127
+ steps:
128
+ - name: Checkout repository
129
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
130
+ with:
131
+ persist-credentials: false
132
+
133
+ - name: Setup project
134
+ uses: ./.github/actions/setup-project
135
+ with:
136
+ node-version: '26.x'
137
+
138
+ - name: Build project
139
+ run: npm run build
140
+
141
+ - name: Validate generated output
142
+ run: npm run validate:build
143
+
144
+ - name: Upload production build
145
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
146
+ with:
147
+ name: site-build
148
+ path: dist
149
+ if-no-files-found: error
150
+ retention-days: 7
151
+
152
+ - name: Upload GitHub Pages artifact
153
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
154
+ uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
155
+ with:
156
+ path: dist
157
+
158
+ browser-tests:
159
+ name: Browser and accessibility tests
160
+ runs-on: ubuntu-latest
161
+
162
+ permissions:
163
+ contents: read
164
+
165
+ steps:
166
+ - name: Checkout repository
167
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
168
+ with:
169
+ persist-credentials: false
170
+
171
+ - name: Setup project
172
+ uses: ./.github/actions/setup-project
173
+ with:
174
+ node-version: '26.x'
175
+
176
+ - name: Install Chromium
177
+ run: npx playwright install --with-deps chromium
178
+
179
+ - name: Run browser and accessibility tests
180
+ run: npm run test:e2e
181
+
182
+ - name: Upload browser failure evidence
183
+ if: failure()
184
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
185
+ with:
186
+ name: browser-test-failures
187
+ path: |
188
+ playwright-report
189
+ test-results
190
+ if-no-files-found: error
191
+ retention-days: 7
192
+
193
+ lighthouse:
194
+ name: Lighthouse budgets
195
+ runs-on: ubuntu-latest
196
+
197
+ permissions:
198
+ contents: read
199
+
200
+ steps:
201
+ - name: Checkout repository
202
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
203
+ with:
204
+ persist-credentials: false
205
+
206
+ - name: Setup project
207
+ uses: ./.github/actions/setup-project
208
+ with:
209
+ node-version: '26.x'
210
+
211
+ - name: Enforce Lighthouse budgets
212
+ run: npm run lighthouse:ci
213
+
214
+ - name: Upload Lighthouse reports
215
+ if: always()
216
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
217
+ with:
218
+ name: lighthouse-reports
219
+ path: .lighthouseci
220
+ include-hidden-files: true
221
+ if-no-files-found: error
222
+ retention-days: 7
223
+
224
+ project:
225
+ name: Project
226
+ needs:
227
+ - format
228
+ - spellcheck
229
+ - static-quality
230
+ - unit-tests
231
+ - build
232
+ - browser-tests
233
+ - lighthouse
234
+ runs-on: ubuntu-latest
235
+
236
+ permissions:
237
+ contents: read
238
+
239
+ steps:
240
+ - name: Confirm project checks
241
+ run: echo "All project checks passed."
242
+
243
+ deploy:
244
+ name: Deploy GitHub Pages
245
+ needs:
246
+ - build
247
+ - project
248
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
249
+ runs-on: ubuntu-latest
250
+
251
+ permissions:
252
+ pages: write
253
+ id-token: write
254
+
255
+ environment:
256
+ name: github-pages
257
+ url: ${{ steps.deployment.outputs.page_url }}
258
+
259
+ steps:
260
+ - name: Deploy GitHub Pages
261
+ id: deployment
262
+ uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: Security Analysis
3
+
4
+ on: # yamllint disable-line rule:truthy
5
+ pull_request:
6
+ branches:
7
+ - main
8
+ push:
9
+ branches:
10
+ - main
11
+ schedule:
12
+ - cron: '__RM_INDUSTRIES_FORGE_TEMPLATE_V1_SECURITY_SCHEDULE_MINUTE__ 5 * * 1'
13
+
14
+ permissions: {}
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ code-analysis:
22
+ name: Analyze (${{ matrix.language }})
23
+ runs-on: ubuntu-latest
24
+
25
+ permissions:
26
+ actions: read
27
+ contents: read
28
+ security-events: write
29
+
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ language:
34
+ - actions
35
+ - javascript-typescript
36
+
37
+ steps:
38
+ - name: Checkout repository
39
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
40
+ with:
41
+ persist-credentials: false
42
+
43
+ - name: Initialize CodeQL
44
+ uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
45
+ with:
46
+ build-mode: none
47
+ languages: ${{ matrix.language }}
48
+ queries: security-extended,security-and-quality
49
+
50
+ - name: Perform CodeQL analysis
51
+ uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
52
+
53
+ dependency-review:
54
+ name: Review dependencies
55
+ if: github.event_name == 'pull_request'
56
+ runs-on: ubuntu-latest
57
+
58
+ permissions:
59
+ contents: read
60
+
61
+ steps:
62
+ - name: Checkout repository
63
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
64
+ with:
65
+ persist-credentials: false
66
+
67
+ - name: Review dependency changes
68
+ uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
69
+ with:
70
+ fail-on-severity: high
@@ -55,6 +55,56 @@ the individual scripts when working offline. CI may execute independent stages
55
55
  in parallel, but a project generated by the packed Forge initializer must pass
56
56
  the documented `npm run quality` command as a single ordered pipeline.
57
57
 
58
+ ## Continuous integration
59
+
60
+ The generated `.github/workflows/project.yml` runs on pull requests targeting
61
+ `main` and on pushes to `main`. It separates static quality, coverage-enforced
62
+ unit tests, the validated production build, browser and accessibility tests,
63
+ and Lighthouse budgets so failures identify the affected gate directly. The
64
+ required `Project` result succeeds only after every release-blocking job passes.
65
+ On pushes to `main`, that result unlocks a separate GitHub Pages deployment;
66
+ pull requests never upload or deploy a Pages artifact. Deployment setup,
67
+ project-site URLs, custom domains, and environment protections are documented in
68
+ [`docs/github-pages.md`](docs/github-pages.md).
69
+
70
+ The workflow installs dependencies with `npm ci`, caches npm downloads using
71
+ the lockfile, cancels superseded runs on the same Git reference, and grants only
72
+ read access to repository contents. Pull requests receive no secrets or write
73
+ permissions. Coverage, production builds, Lighthouse reports, and browser
74
+ failure evidence are retained for seven days. All third-party actions use
75
+ immutable commit pins.
76
+
77
+ Security automation is included alongside project CI. CodeQL analyzes the
78
+ project's TypeScript and GitHub Actions on pull requests, pushes to `main`, and
79
+ a weekly schedule. Dependency review rejects pull requests that introduce
80
+ known high- or critical-severity vulnerabilities. A separate scheduled
81
+ automation workflow validates workflow syntax and scans GitHub Actions with
82
+ Zizmor. Zizmor uploads its findings to GitHub code scanning for review in the
83
+ Security tab without failing the workflow solely because it found an issue.
84
+ The job receives `security-events: write` only for that upload; all other access
85
+ remains read-only. Repositories can make selected code-scanning severities
86
+ merge-blocking later through their ruleset without changing the workflow.
87
+ The `Automation` aggregate runs when `.github/**` changes and succeeds only after
88
+ both workflow syntax and security validation pass. Because it is path-filtered,
89
+ do not configure it as a globally required status check; review it whenever an
90
+ automation change causes it to appear.
91
+
92
+ Dependabot checks npm and GitHub Actions weekly. Minor and patch npm updates are
93
+ grouped by production or development scope, while major updates remain separate
94
+ for deliberate review. Updates use cooldown periods to avoid adopting newly
95
+ released versions immediately. Because pre-1.0 Sveltia minor releases may be
96
+ breaking, `@sveltia/cms` updates are kept separate from generic production
97
+ dependency groups. Its pull requests must satisfy the compatibility line
98
+ declared by `@rm-industries/content-model`; moving to a later minor requires a
99
+ tested content-model release first. No version is ignored, security updates
100
+ remain enabled, and every update must pass the complete project and security
101
+ workflows before merging.
102
+
103
+ GitHub chooses the Dependabot run times, distributing update checks across its
104
+ available schedule. Forge derives distinct weekly CodeQL and workflow-validation
105
+ minutes from the generated package name. This keeps generation reproducible
106
+ while preventing every Forge project from starting scheduled work simultaneously.
107
+
58
108
  Playwright builds the site and runs Chromium against Astro's production preview,
59
109
  not the development server. Its browser coverage exercises desktop and mobile
60
110
  navigation, article listing/detail flows, article pagination, light and dark
@@ -99,6 +149,12 @@ configuration, shared layout, and reusable SEO head consume this single
99
149
  validated source. New pages should use `src/layouts/BaseLayout.astro` to inherit
100
150
  the document shell and canonical metadata.
101
151
 
152
+ The canonical URL may include a pathname for a GitHub Pages project site, such
153
+ as `https://owner.github.io/repository`. The Astro configuration derives its
154
+ deployment base from that pathname, and shared URL helpers apply it to local
155
+ navigation, metadata, supporting files, and assets. Root-hosted and custom-domain
156
+ sites use an origin-only URL and therefore have no deployment prefix.
157
+
102
158
  The standalone source template uses `https://example.com` as a valid,
103
159
  non-production site origin. Projects created by Forge receive the values
104
160
  selected through the generator input contract.
@@ -2,12 +2,16 @@ import sitemap from '@astrojs/sitemap';
2
2
  import tailwindcss from '@tailwindcss/vite';
3
3
  import { defineConfig } from 'astro/config';
4
4
 
5
+ import { getDeploymentConfig } from './src/config/deployment';
5
6
  import { site } from './src/config/site';
6
7
 
8
+ const deployment = getDeploymentConfig(site.url);
9
+
7
10
  export default defineConfig({
11
+ base: deployment.base,
8
12
  integrations: [sitemap()],
9
13
  output: 'static',
10
- site: site.url,
14
+ site: deployment.site,
11
15
  trailingSlash: 'always',
12
16
  vite: {
13
17
  plugins: [tailwindcss()],
@@ -18,5 +18,6 @@ export default defineConfig({
18
18
  'Sveltia',
19
19
  'unreviewed',
20
20
  'WCAG',
21
+ 'Zizmor',
21
22
  ],
22
23
  });
@@ -0,0 +1,56 @@
1
+ # GitHub Pages deployment
2
+
3
+ The project workflow publishes the validated production build to GitHub Pages
4
+ after every push to `main`. Pull requests build and test the site, but they do
5
+ not upload a Pages artifact or run a deployment.
6
+
7
+ ## Enable deployment
8
+
9
+ 1. Open the repository's **Settings → Pages** page.
10
+ 2. Under **Build and deployment**, select **GitHub Actions** as the source.
11
+ 3. Open **Settings → Environments → github-pages** after its first appearance.
12
+ 4. Restrict deployment branches to `main`. Add required reviewers when the site
13
+ needs a manual production approval.
14
+
15
+ The build job has read-only repository access. The separate deployment job is
16
+ the only job granted `pages: write` and `id-token: write`, and it cannot begin
17
+ until the complete `Project` quality gate succeeds.
18
+
19
+ ## Choose the public URL
20
+
21
+ Set `url` in `src/config/site.ts` to the complete public address. Forge derives
22
+ Astro's deployment base from this value, so canonical metadata, navigation,
23
+ assets, the RSS feed, the web manifest, and CMS branding use the same path.
24
+
25
+ For a project site, include the repository name:
26
+
27
+ ```ts
28
+ url: 'https://owner.github.io/repository',
29
+ ```
30
+
31
+ For an organization or user site, use the root address:
32
+
33
+ ```ts
34
+ url: 'https://owner.github.io',
35
+ ```
36
+
37
+ Run `npm run build && npm run validate:build` after changing the URL. Once the
38
+ workflow succeeds on `main`, its deployment summary links to the published site.
39
+
40
+ ## Use a custom domain
41
+
42
+ Set the site URL to the custom origin without a repository pathname:
43
+
44
+ ```ts
45
+ url: 'https://www.example.com',
46
+ ```
47
+
48
+ Add `public/CNAME` containing only the domain name, configure the same domain in
49
+ **Settings → Pages**, and create the DNS records GitHub documents for the chosen
50
+ domain. The template does not include a `CNAME` file because generated projects
51
+ do not share a domain. Enable **Enforce HTTPS** after GitHub verifies the DNS
52
+ configuration.
53
+
54
+ Do not configure both a repository pathname and a custom domain. A custom domain
55
+ is served from its root, while a project site uses the repository name as its
56
+ base path.