Release 0.2.0#22
Conversation
Comment bodies in formatPRAsMarkdown were inserted verbatim, so headers like `## Idea` inside a `### [Comment #N]` block broke the heading hierarchy. Promote the section/comment chrome by one level (## → #, ### → ##) and pipe each comment body through a new shiftHeadersToMinLevel helper that ensures the shallowest header starts at level 3. Refs: #4
Fix the default GITHUB_REPOSITORY from the non-existent 'vig-os/actions' to the correct 'vig-os/sync-issues-action', which caused a Not Found error when running the local integration test. Also remove the broken fallback command that passed a file path where a directory is required, producing a misleading 'missing required argument' error. Refs: #4
Refs: #4
Refs: #4
fix: shift PR comment headers to respect document hierarchy Refs: #4
Add IssueRelationship interface. Update formatIssueAsMarkdown to accept optional relationship data and render parent/children fields. Update PR frontmatter to use parent/children instead of relationship. Refs: #8
Query parentIssue and subIssues for all synced issues in batches of 50 using aliased GraphQL fields. Gracefully degrades to empty map on error. Refs: #8
Collect all issue numbers first, fetch relationships in a single GraphQL batch, then pass relationship data to formatIssueAsMarkdown for each issue. Gracefully degrades when GraphQL is unavailable. Refs: #8
Sub-issue relationships are an issues-only concept; including them in PR frontmatter adds noise with no possible value. Refs: #8
## Description Sync GitHub sub-issue relationships (`parentIssue`/`subIssues`) into the markdown frontmatter of synced issue files. Previously the action wrote a hardcoded `relationship: none` for every issue. This PR replaces that with two dynamic fields (`parent`, `children`) populated via a bulk GraphQL query using the `sub_issues` preview API. ## Related Issue(s) Closes #8 ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update - [ ] Refactoring (no functional changes) - [ ] CI / Build change - [ ] Test updates ## Changes Made - **New `IssueRelationship` interface** — `{ parent: number | null; children: number[] }` - **New `fetchIssueRelationships()` function** — Constructs batched (50 per query) aliased GraphQL queries to fetch `parentIssue` and `subIssues` for all synced issues in a single round-trip. Requires the `GraphQL-Features: sub_issues` header. Gracefully degrades to empty map on error. - **Updated `syncIssuesToMarkdown()`** — Collects all issue numbers first, fetches relationships in bulk, then passes relationship data to each issue's formatting call. - **Updated `formatIssueAsMarkdown()`** — Accepts optional `IssueRelationship` parameter; renders `parent: <N|none>` and `children: <N, M|none>` instead of `relationship: none`. - **Updated PR frontmatter** — Replaced `relationship: none` with `parent: none` and `children: none`. - **Updated test mock** — Added `graphql: jest.fn()` to the mocked Octokit instance. - **8 new tests** — 4 formatting tests (parent-only, children-only, both, none), 3 fetch tests (happy path, empty list, error), 1 integration test (relationships in written files). ## Changelog Entry ### Added - **Sync sub-issue relationships into frontmatter** ([#8](#8)) - Fetch `parentIssue` and `subIssues` via GraphQL batch query for all synced issues - Replace hardcoded `relationship: none` with dynamic `parent` and `children` fields - Graceful degradation: falls back to `none` if GraphQL query fails ## Testing - [x] Tests pass locally (`npm test` — 87 passed, 0 failed) - [ ] Manual testing performed (describe below) ### Manual Testing Details Unit tests cover all paths: - `formatIssueAsMarkdown` with parent-only, children-only, both, and no relationships - `fetchIssueRelationships` happy path (returns correct map), empty input (no GraphQL call), error handling (warning + empty map) - Integration: `run()` with mocked GraphQL response verifies `parent: 2` and `children: 10, 11` appear in written file content ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly (edit `docs/templates/`, then run `just docs`) - [x] I have updated `CHANGELOG.md` in the `[Unreleased]` section (and pasted the entry above) - [x] My changes generate no new warnings or errors - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] Any dependent changes have been merged and published ## Additional Notes - The issue originally referenced `trackedIssues`/`trackedInIssues` GraphQL fields, but GitHub retired tasklists in April 2025. This PR uses the replacement `subIssues`/`parentIssue` API with the `GraphQL-Features: sub_issues` header. - The old `relationship` frontmatter field has been removed entirely — it was always `none` and is fully derivable from `parent`/`children`. - Sub-issues support up to 100 children per parent and 8 nesting levels. The batch query fetches up to 100 children per issue. Refs: #8
When force-update is true, syncIssuesToMarkdown and syncPRsToMarkdown skip the content-comparison check and always write files. This ensures all items are re-synced (with updated frontmatter timestamps) even when their body content has not changed on GitHub. Issue: #10
## Description When triggering a workflow with `force-update: true`, only PRs were re-synced while issues were silently skipped. The root cause is that `hasContentChanged` strips frontmatter (including the `synced:` timestamp) and compares body content only -- when nothing has changed on GitHub, the body is identical and the write is skipped, even during a force-update. The action had no mechanism to bypass this content-comparison gate. This PR adds a `force-update` boolean input to the action. When active, both `syncIssuesToMarkdown` and `syncPRsToMarkdown` skip the `hasContentChanged` check and always write files (updating the `synced:` frontmatter timestamp, which produces a real git diff). ## Related Issue(s) Closes #10 ## Type of Change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] Documentation update - [ ] Refactoring (no functional changes) - [ ] CI / Build change - [x] Test updates ## Changes Made - `action.yml` -- added `force-update` input (boolean string, default `'false'`) - `src/index.ts` -- read the new input, thread a `forceUpdate` boolean into `syncIssuesToMarkdown` and `syncPRsToMarkdown`, short-circuit with `forceUpdate || hasContentChanged(...)` - `.github/workflows/sync-issues.yml` -- pass `force-update: ${{ github.event.inputs.force-update }}` to the action - `src/__tests__/unit/index.test.ts` -- two new tests (issues + PRs) verifying force-update bypasses `hasContentChanged` - `CHANGELOG.md` -- added entry under Unreleased > Fixed - `README.md` -- added `force-update` row to the Options table ## Changelog Entry ### Fixed - **`--force-update` does not re-sync issues (only PRs)** ([#10](#10)) - Added `force-update` action input that bypasses the `hasContentChanged` content-comparison gate - When active, all fetched items are re-written (with updated `synced:` frontmatter) even if body content is unchanged - Updated `sync-issues.yml` workflow to pass the `force-update` dispatch input to the action ## Testing - [x] Tests pass locally (`npx jest` -- 89 passed, 0 failed) - [x] Manual testing performed (describe below) ### Manual Testing Details - Ran `npx jest -t "force-update input"` to verify both new tests pass (issue + PR force-update) - Ran `npx jest -t "should skip writing when only synced timestamp changes"` to confirm existing behaviour is preserved when `force-update` is not set ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have updated the documentation accordingly - [x] I have updated `CHANGELOG.md` in the `[Unreleased]` section (and pasted the entry above) - [x] My changes generate no new warnings or errors - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] Any dependent changes have been merged and published ## Additional Notes The fix follows TDD: failing tests were committed first, then the implementation, then the workflow and docs updates. The commit history proves compliance: 1. `test:` failing test for issues 2. `test:` failing test for PRs 3. `fix:` implementation (action.yml + src/index.ts) 4. `fix:` workflow update 5. `docs:` changelog 6. `docs:` README Refs: #10
- Pin hook revs to full SHAs for reproducibility - Add branch naming enforcement and action SHA-pinning hooks - Simplify ruff hooks, remove hadolint and checkmake - Tighten pymarkdown rules (line length 120, front matter, ATX headings) Refs: #13
Replace the three generic templates (bug_report, feature_request, task) with purpose-built templates for each issue type: bug, feature, refactor, chore, docs, discussion, and config contact link. Refs: #13
Add CODEOWNERS to enforce review by the maintainer on all files. Update the PR template to align with this project: - Add type-of-change checklist using conventional commit types - Add Changelog Entry section with an example referencing this repo - Replace `make test` with `npm test` - Remove stale `just docs` reference - Add Refs traceability footer Refs: #13
Enable weekly automated dependency updates for GitHub Actions (sha-pinned) and npm packages, targeting the dev branch with grouped minor/patch updates. Refs: #13
There was a problem hiding this comment.
Pull request overview
This PR prepares release 0.2.0, introducing sub-issue relationship syncing, force-update functionality, and a comprehensive CI/CD pipeline. The release addresses issues #8, #10, #13, and #15, adding GraphQL-based parent/child relationship tracking for issues and improving the testing and release infrastructure.
Changes:
- Added GraphQL batch querying to sync sub-issue relationships (
parent/childrenfrontmatter fields) - Implemented
force-updateandsync-sub-issuesaction inputs with graceful API degradation - Established full CI/CD pipeline with integration tests, release automation, and security scanning
- Fixed PR comment header hierarchy and removed source maps from build output
Reviewed changes
Copilot reviewed 46 out of 74 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/index.ts | Core implementation: GraphQL relationship fetching, force-update bypass, frontmatter changes |
| action.yml | New inputs: force-update, sync-sub-issues |
| tsconfig.json | Disabled source/declaration maps |
| package.json | Removed --source-map flag from package script |
| README.md | Updated feature list to include relationships |
| CHANGELOG.md | Prepared 0.2.0 release notes |
| .github/workflows/* | Added/updated CI, CodeQL, Scorecard, integration-test, prepare-release, post-release workflows |
| .github/actions/* | Added setup-env and build-dist composite actions |
| .pymarkdown | Enhanced markdown linting configuration |
| .pre-commit-config.yaml | Updated hooks with SHA pinning |
| .nvmrc | Added Node.js version pinning |
| docs/* | Synced issue and PR markdown files |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The function signature defaulted syncSubIssues to false while action.yml defaults sync-sub-issues to true. Although the caller always passes the value explicitly (no runtime impact), the mismatch could cause incorrect behavior if the function were ever called without the argument. Refs: #26
…lure (#25) Move try/catch inside the batch loop so that: - Schema errors ("doesn't exist on type") break immediately - Transient errors warn per-batch and continue to the next - Successfully fetched relationships are preserved instead of being discarded on a later batch failure Add tests for multi-batch partial-result and schema-error-break scenarios.
## Summary - Fixes the `syncSubIssues` parameter default in `syncIssuesToMarkdown` from `false` to `true`, matching the `action.yml` `sync-sub-issues` input default - Update README with full build pipeline ## Test plan - [x] No runtime impact (caller always passes the value explicitly) - [x] `npm run prepare` rebuilds cleanly - [x] Existing tests pass (`npm test`) Refs: #26
…ailure ## Summary - Moves `try/catch` inside the batch loop in `fetchIssueRelationships` so each batch is handled independently - Schema errors (`"doesn't exist on type"`) `break` immediately (API unavailable, no point continuing) - Transient errors `warn` per-batch and `continue` to the next, preserving already-fetched relationships - Exports `GRAPHQL_BATCH_SIZE` for testability - Adds two new tests: multi-batch partial results on transient error, and schema-error break with partial results ## Test plan - [x] All 95 existing unit tests pass - [x] New partial-result tests cover both transient-error and schema-error scenarios - [x] `npm run prepare` rebuilds cleanly - [x] CI passes Refs: #25
|
Id say the reason for it to exist is to allow dev to diverge while the release is being prepared. Once released i dont see the point in keeping it. So anything dev has, should be fine. A hotfix as in patch will bump the version X.Y.Z+1 so it should be a new rc anyway?! |
gerchowl
left a comment
There was a problem hiding this comment.
Testing Checklist
- All tests pass (
npm run test:coverage)- Manual testing complete
- No critical bugs found
- Ready for release
update checklist or remove if not applicable
Updated. |
## Summary - Clarifies the weekly CodeQL schedule comment in `.github/workflows/codeql.yml` - Makes explicit that the scheduled run re-scans with updated CodeQL rules/engines even when repository code has not changed - Removes ambiguity noted in PR #22 review discussion ## Test plan - [x] Confirm only workflow comments changed (no runtime workflow logic changes) - [x] Validate YAML remains syntactically valid - [x] Verify wording addresses reviewer question about schedule purpose Refs: #29
## Description Fix release workflow validation failure in dry-run mode by allowing the reusable integration test workflow to request required read scopes. ## Type of Change - [x] `fix` -- Bug fix - [ ] `ci` -- CI/CD pipeline changes ### Modifiers - [ ] Breaking change (`!`) -- This change breaks backward compatibility ## Changes Made - Added job-level permissions to `integration-test` in `.github/workflows/release.yml` - Granted only minimum required scopes: `contents: read`, `issues: read`, `pull-requests: read` ## Changelog Entry No changelog needed (workflow permission fix only). ## Testing - [x] Tests pass locally (`npm test`) - [x] Manual testing performed (describe below) ### Manual Testing Details - Verified workflow schema error cause against reusable workflow requested permissions. - Confirmed caller now explicitly allows required read scopes. ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly - [ ] I have updated `CHANGELOG.md` in the `[Unreleased]` section (and pasted the entry above) - [x] My changes generate no new warnings or errors - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published ## Additional Notes Scoped permissions are set only on the reusable workflow caller job to preserve least privilege. Refs: #31
gerchowl
left a comment
There was a problem hiding this comment.
Testing Checklist
- All tests pass (
npm run test:coverage)- Manual testing complete
- No critical bugs found
- Ready for release
update checklist or remove if not applicable
Updated.
@gerchowl could you run the local tests too?
----------|---------|----------|---------|---------|------------------------------------------------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|------------------------------------------------------------------------
All files | 93.31 | 76.43 | 94 | 94 |
index.ts | 93.31 | 76.43 | 94 | 94 | 10-11,16,21-23,242,401-402,446,464-475,501-502,597,608,626,633,672,690
----------|---------|----------|---------|---------|------------------------------------------------------------------------
Test Suites: 1 passed, 1 total
Tests: 95 passed, 95 total
Snapshots: 0 total
Time: 2.701 s, estimated 3 s
Ran all test suites.
Set release date to 2026-02-25 in CHANGELOG.md Bump package.json version to 0.2.0 Refs: #22
4fc363e to
c4cf762
Compare
|
Due to immutability of releases, the bug described in #34 means version 0.2.0 is no longer available. We switch to 0.2.1. |
Release 0.2.0
This PR prepares release 0.2.0 for merge to main.
Release Content
Added
shiftHeadersToMinLevelutility function for independent unit testingparentandsubIssuesvia GraphQL batch query for all synced issuessync-sub-issuesaction input to control sub-issue syncing (default:true)relationship: nonewith dynamicparentandchildrenfieldsnoneif the sub-issues API is unavailablesetup-envandbuild-distcomposite actions for consistent environment setupprepare_changelog.py) for automated release note preparationChanged
uses: ./so the workflow always tests the current branch's code.nvmrc(#13).nvmrcis the single source of truth;setup-envand devcontainer read from itFixed
formatPRAsMarkdown: promoted the Comments section header from##to#and individual comment entry headers from###to##--force-updatedoes not re-sync issues (only PRs) (#10)force-updateaction input that bypasses thehasContentChangedcontent-comparison gatesynced:frontmatter) even if body content is unchangedsync-issues.ymlworkflow to pass theforce-updatedispatch input to the actionshiftHeadersToMinLevelhelper to re-level headers inside comment bodies so the shallowest header maps to###, preventing collisions with outer document structureGITHUB_REPOSITORYintest-local.shfrom non-existentvig-os/actionstovig-os/sync-issues-actiontest-local.shthat passed a file path where a directory is requiredSecurity
Testing Checklist
npm run prepare && npm run test:all)integration-testworkflow)When Ready to Release
Run the Release workflow (
workflow_dispatch) with version0.2.0.This will:
Related
Refs: #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29, #30