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
## Summary - Switch `prepare-release.yml`, `release.yml`, and `post-release.yml` from `APP_SYNC_ISSUES_*` secrets to `RELEASE_APP_*` secrets, pointing to a dedicated GitHub App with the required permissions (`contents:write`, `pull-requests:write`, `issues:write`). - The previous fix (#20, commit ffe9e9b) misdiagnosed the root cause: it switched the PR creation step to `github.token`, but that token also cannot create PRs when the repo setting "Allow GitHub Actions to create and approve pull requests" is disabled. The correct fix is to use an App token from an App that has `pull-requests:write` permission. ## Test plan - [x] Verify `RELEASE_APP_ID` and `RELEASE_APP_PRIVATE_KEY` secrets are configured - [ ] Re-run the Prepare Release workflow and confirm the draft PR is created successfully Refs: #18
Prepare CHANGELOG.md structure for version 0.2.0. Release date TBD (set during finalization).
## Description Sync main into release 0.2.0 ## Type of Change - [ ] 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 - [x] Refactoring (no functional changes) - [ ] Test updates ## Changes Made - Sync documentation (CHANGELOG, README, issues and PRs) - Sync CI placeholders ## Testing - [x] Tests pass locally (`npm run test:all`) ## Checklist - [ ] My code follows the project's style guidelines - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have updated the documentation accordingly (README.md, CONTRIBUTE.md, etc.) - [x] I have updated the CHANGELOG.md in the `[Unreleased]` section - [x] My changes generate no new warnings or errors - [ ] 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 Refs: #22
# Conflicts: # .github/actions/setup-env/action.yml # .github/workflows/ci.yml # .github/workflows/codeql.yml # .github/workflows/post-release.yml # .github/workflows/prepare-release.yml # .github/workflows/release.yml # .github/workflows/scorecard.yml # CHANGELOG.md # docs/issues/issue-10.md # docs/pull-requests/pr-16.md # docs/pull-requests/pr-20.md
## Description Sync main into release 0.2.0 ## Type of Change - [ ] 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 - [x] Refactoring (no functional changes) - [ ] Test updates ## Changes Made - Sync documentation (CHANGELOG, README, issues and PRs) - Sync CI placeholders ## Testing - [x] Tests pass locally (`npm run test:all`) ## Checklist - [ ] My code follows the project's style guidelines - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have updated the documentation accordingly (README.md, CONTRIBUTE.md, etc.) - [x] I have updated the CHANGELOG.md in the `[Unreleased]` section - [x] My changes generate no new warnings or errors - [ ] 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 Refs: #22
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
## 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
## Summary - Merge `release/0.2.0` back into `dev` to realign branches after fixing issue #34 (immutable release errors). - Retrigger the `prepare release` workflow from a clean state after the permissions/workflow fix. - Preserve release workflow continuity without introducing new feature changes. ## Test plan - [ ] Confirm PR merges cleanly into `dev`. - [ ] Verify `prepare release` workflow triggers after merge. - [ ] Verify workflow run completes without immutable release errors (issue #34). Refs: #34
Attach checksums during `gh release create` instead of uploading after release creation to work with immutable releases. Harden floating-tag SHA lookup/rollback by validating resolved SHAs before restore/delete operations. Refs: #34
## Description Fixes release publishing failures caused by immutable release state when uploading artifacts after release creation. The workflow now prepares checksum artifacts before release creation and hardens floating tag SHA resolution/rollback handling. ## Type of Change - [ ] `feat` -- New feature - [x] `fix` -- Bug fix - [ ] `docs` -- Documentation only - [ ] `chore` -- Maintenance task (deps, config, etc.) - [ ] `refactor` -- Code restructuring (no behavior change) - [ ] `test` -- Adding or updating tests - [x] `ci` -- CI/CD pipeline changes - [ ] `build` -- Build system or dependency changes - [ ] `revert` -- Reverts a previous commit - [ ] `style` -- Code style (formatting, whitespace) ### Modifiers - [ ] Breaking change (`!`) -- This change breaks backward compatibility ## Changes Made - Generate `checksums-sha256.txt` before creating the GitHub release. - Attach checksums during `gh release create` instead of uploading after release creation. - Resolve floating tags with `git/matching-refs/tags/*` and only accept valid 40-char SHAs. - Skip rollback restore/delete operations when the previous SHA is present but invalid. - Add corresponding `[Unreleased]` changelog entry. ## Changelog Entry ### Fixed - **Release workflow avoids immutable-release upload failures** - Generates `checksums-sha256.txt` before creating the GitHub release and attaches it during `gh release create` instead of uploading afterward - Hardens floating-tag SHA handling by resolving tags via `git/matching-refs`, validating SHA format, and skipping invalid rollback SHAs ## Testing - [ ] Tests pass locally (`npm test`) - [x] Manual testing performed (describe below) ### Manual Testing Details - Verified workflow logic changes by reviewing command flow in `.github/workflows/release.yml`. - Confirmed release command now includes checksum asset at creation time. - Confirmed tag SHA retrieval and rollback paths now validate SHA format. ## 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 - [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 - [ ] 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 No functional changes outside the release workflow and changelog update. Refs: #34
…xact ref - Resolve each floating tag via the exact "Get a reference" API (GET repos/.../git/ref/tags/$TAG) so the SHA is for the exact tag. - Run floating-tag updates in a dedicated job (update-floating-tags) that runs only after the release job succeeds. The main rollback job no longer captures or restores floating tags. - CHANGELOG: add Fixed entry for #38 Refs: #38
…lution ## Description Fixes release workflow errors when updating floating tags (vX, vX.Y): moves floating-tag updates to a separate job, resolves tags via the exact "Get a reference" API to avoid wrong SHA from prefix matches, and keeps rollback self-contained. Also fixes immutable release upload failures by generating and attaching `checksums-sha256.txt` during `gh release create`. ## Type of Change - [x] `fix` -- Bug fix - [ ] `feat` -- New feature - [ ] `docs` -- Documentation only - [ ] `chore` -- Maintenance task (deps, config, etc.) - [ ] `refactor` -- Code restructuring (no behavior change) - [ ] `test` -- Adding or updating tests - [x] `ci` -- CI/CD pipeline changes - [ ] `build` -- Build system or dependency changes - [ ] `revert` -- Reverts a previous commit - [ ] `style` -- Code style (formatting, whitespace) ### Modifiers - [ ] Breaking change (`!`) -- This change breaks backward compatibility ## Changes Made - **Floating-tag updates (#38):** Run in a separate job after the release job succeeds; main rollback no longer restores floating tags. Resolve floating tags via `GET /repos/{owner}/{repo}/git/ref/tags/{tag}` instead of matching-refs to avoid wrong SHA from prefix matches. New job captures current SHAs, updates tags, and on failure restores from captured SHAs (self-contained). - **Immutable release uploads:** Generate `checksums-sha256.txt` before creating the GitHub release and attach it during `gh release create` instead of uploading afterward. ## Changelog Entry ``` ### Fixed - **Release workflow avoids immutable-release upload failures** - Generates `checksums-sha256.txt` before creating the GitHub release and attaches it during `gh release create` instead of uploading afterward - **Release workflow: floating-tag updates and rollback** ([#38](#38)) - Floating-tag updates (vX, vX.Y) run in a separate job after the release job succeeds; main rollback no longer restores floating tags - Resolve floating tags via exact "Get a reference" API (`git/ref/tags/$TAG`) instead of `git/matching-refs` to avoid wrong-SHA from prefix matches - New job captures current SHAs, updates tags, and on failure restores from captured SHAs (self-contained) ``` ## Testing - [x] Tests pass locally (`npm test`) - [ ] Manual testing performed (describe below) ### Manual Testing Details Release workflow changes validated via CI and release dry-run / integration test flows. ## 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 Floating-tag update logic is isolated in a dedicated job so that release creation and asset uploads complete first; tag updates and their rollback are independent of the main release rollback. Refs: #38
Prepare CHANGELOG.md structure for version 0.2.2. Release date TBD (set during finalization).
c-vigo
approved these changes
Feb 26, 2026
Set release date to 2026-02-26 in CHANGELOG.md Bump package.json version to 0.2.2 Refs: #40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 0.2.2
This PR prepares release 0.2.2 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##checksums-sha256.txtbefore creating the GitHub release and attaches it duringgh release createinstead of uploading afterwardgit/ref/tags/$TAG) instead ofgit/matching-refsto avoid wrong-SHA from prefix matches--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 test:coverage)When Ready to Release
Run the Release workflow (
workflow_dispatch) with version0.2.2.This will:
Related