Conversation
There was a problem hiding this comment.
Pull request overview
Adds a “project notes” pipeline that validates PR bodies for required note sections and generates a project page markdown file (intended to sync into benhalverson-blog) via GitHub Actions.
Changes:
- Introduces
tools/project-notes/*scripts to validate PR notes and generate a project markdown page from merged PR history +project-notes.config.json. - Adds Node-based tests for the project-notes generator/formatting and wires them into CI.
- Adds GitHub workflows to validate PR note sections and to publish generated notes into the blog repo via an automated PR.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/project-notes/validate-pr-notes.ts | CLI to validate PR body sections from GITHUB_EVENT_PATH payload. |
| tools/project-notes/shared.ts | Core parsing/validation, GitHub API fetching, and markdown rendering utilities. |
| tools/project-notes/generate-project-notes.ts | CLI to generate markdown from config + merged PRs (or a fixture pulls file). |
| test/project-notes/shared.spec.ts | Unit tests for parsing, validation, and deterministic markdown output. |
| test/project-notes/generate.spec.ts | Integration-style test invoking the generator CLI. |
| project-notes.config.json | Defines stable project metadata/roadmap used in generated markdown. |
| package.json | Adds scripts for generating/validating notes and running project-notes tests. |
| README.md | Documents the project notes pipeline, commands, and required secrets. |
| .github/workflows/project-notes-publish.yml | Workflow to generate markdown on main and open/update a PR in the blog repo. |
| .github/workflows/project-notes-pr-validation.yml | Workflow to validate PR bodies contain required “project notes” sections. |
| .github/workflows/nodejs.yaml | Updates CI to use frozen lockfile installs and run the new project-notes test suite. |
| .github/pull_request_template.md | Adds the standardized “project notes” sections to PR template. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const files = await githubRequest(`/repos/${owner}/${repo}/pulls/${pullRequest.number}/files?per_page=100`, token); | ||
|
|
||
| return normalizePullRequestNotes({ | ||
| ...pullRequest, | ||
| files: Array.isArray(files) ? files : [], |
There was a problem hiding this comment.
The PR files list fetch only requests the first page of pulls/{pull_number}/files (per_page=100 without pagination). PRs with >100 changed files will silently drop the remainder, which can produce incomplete paths context in the generated markdown. Consider paginating this endpoint (loop over page until fewer than per_page results, or follow the Link header) and concatenating all file entries.
| const files = await githubRequest(`/repos/${owner}/${repo}/pulls/${pullRequest.number}/files?per_page=100`, token); | |
| return normalizePullRequestNotes({ | |
| ...pullRequest, | |
| files: Array.isArray(files) ? files : [], | |
| const perPageFiles = 100; | |
| const allFiles: any[] = []; | |
| for (let page = 1; ; page += 1) { | |
| const pageFiles = await githubRequest( | |
| `/repos/${owner}/${repo}/pulls/${pullRequest.number}/files?per_page=${perPageFiles}&page=${page}`, | |
| token, | |
| ); | |
| if (!Array.isArray(pageFiles) || pageFiles.length === 0) { | |
| break; | |
| } | |
| allFiles.push(...pageFiles); | |
| if (pageFiles.length < perPageFiles) { | |
| break; | |
| } | |
| } | |
| return normalizePullRequestNotes({ | |
| ...pullRequest, | |
| files: allFiles, |
| { | ||
| cwd: '/home/ben/projects/3dprinter-web-api', | ||
| env: { | ||
| ...process.env, | ||
| GENERATED_AT: '2026-03-27T00:00:00.000Z', | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| const contents = await readFile(outputPath, 'utf8'); | ||
| const config = await loadProjectConfig('/home/ben/projects/3dprinter-web-api/project-notes.config.json'); | ||
|
|
There was a problem hiding this comment.
This test hard-codes a developer-specific absolute path for cwd (/home/ben/projects/3dprinter-web-api) and for loading project-notes.config.json. This will fail in CI and for other contributors. Use process.cwd() (repo root during tests) or resolve relative to the test file, and avoid absolute paths by copying/creating the config in the temp directory you already create (and set cwd to that temp directory if needed).
| const key = token.slice(2); | ||
| const nextValue = values[index + 1]; | ||
|
|
||
| if (!nextValue || nextValue.startsWith('--')) { | ||
| parsed[key] = 'true'; | ||
| continue; |
There was a problem hiding this comment.
parseArgs assigns the string 'true' when a flag is provided without a value. For options that require a value (e.g. --pullsFile, --config, --output, --repository, --branch, --token), this can lead to confusing runtime failures like trying to read a file literally named true. Consider validating required-value flags and throwing a clear error when their value is missing, instead of defaulting to 'true'.
No description provided.