feat: API client with non-blocking CI integration (Story 1.4)#3
Merged
maximn merged 1 commit intoMar 6, 2026
Merged
Conversation
Add HTTP API client that POSTs parsed test results to the TestGlance API with exponential backoff retry (3 attempts), format auto-detection, and comprehensive error handling. The Action never calls core.setFailed() ensuring CI pipelines are never broken by TestGlance failures. - src/api/client.ts: HTTP client with retry logic, AbortController timeout - src/utils/detect-format.ts: file extension-based format detection - src/utils/errors.ts: non-blocking warning handlers (core.warning only) - src/index.ts: full pipeline wiring (read → detect → parse → send) - 58 new tests (127 total), all passing - Test suite optimized from 18.3s to 526ms via proper fake timers - CLAUDE.md updated with new architecture tree
10 tasks
maximn
added a commit
that referenced
this pull request
Apr 28, 2026
Handlebars.compile() defers parsing until render time, so without the eager parse() call, syntax errors in user templates surface as "render error" warnings instead of "parse error" warnings. The spec for story 8.3 requires the "parse error in <path>: <reason>" format for compile-time failures (AC #3). The previous code-review labelled this call "redundant" but it is load-bearing.
maximn
added a commit
that referenced
this pull request
Apr 29, 2026
Handlebars.compile() defers parsing until render time, so without the eager parse() call, syntax errors in user templates surface as "render error" warnings instead of "parse error" warnings. The spec for story 8.3 requires the "parse error in <path>: <reason>" format for compile-time failures (AC #3). The previous code-review labelled this call "redundant" but it is load-bearing.
maximn
added a commit
that referenced
this pull request
Apr 29, 2026
* feat: add custom Handlebars templates for CI summary and PR comments
Introduces two new optional inputs that let users replace the default
rendering of the CI Job Summary and the PR comment body with their own
Handlebars templates:
- summary-template: replaces the default CI summary
- comment-template: replaces the default per-job PR comment body
Both inputs share a single TemplateContext shape (results, failures,
slowest, suites, history, delta, flaky, trends, perfRegression, meta)
built once via buildTemplateContext, so the mental model is identical
across surfaces. Compiled templates are cached by absolute path.
Render errors (missing file, parse error, runtime error) are caught and
surfaced via core.warning, and the Action falls back to the default
rendering — exit code remains 0 (non-blocking, per ANFR1). PR-comment
custom output is wrapped in the existing per-job markers so multi-job
merging continues to work.
Helpers registered: formatDuration, truncate, escapeHtml, passRate.
Closes story 8.3.
* docs: keep handlebars examples readable with prettier-ignore
* fix(templates): harden custom-template renderer and wire missing context
Code-review follow-up for story 8.3.
Security:
- Reject template paths that resolve outside GITHUB_WORKSPACE (lexical and via realpath)
- Reject symlinks pointing outside the workspace
- Reject paths containing newline characters (log-injection vector)
- Reject non-regular files and files larger than 1 MB
- Disable Handlebars prototype-property/method access at render time
- Use an isolated Handlebars.create() instance so helpers cannot leak across processes
Correctness:
- Plumb loadedHistory.entries through to both surfaces so {{#each history}} actually populates
- Pass slowestLimit to the PR-comment buildTemplateContext call so summary and comment match
- Strip embedded <!-- tj:* --> markers from rendered comment bodies before wrapping
- Use lastIndexOf for the closing marker in mergeTestJobSection (defense-in-depth)
- Fall back to "tests" when the sanitized job-name marker key is empty
- Wrap generateSummary and postPrComment in try/catch in index.ts so renderer errors
cannot break CI
- Cap rendered summary at ~900K and rendered comment body at ~60K to fit GitHub limits
- Trim summary-template/comment-template inputs so whitespace-only values are treated as unset
- Strip leading UTF-8 BOM after reading template files
- Key the compile cache on (path, mtimeMs, size) so edits invalidate stale entries
- Drop the redundant Handlebars.parse() call before compile()
Docs:
- Replace the broken @index_lt_25 example with a working {{#each (limit … N)}} example
- Add a "limit" helper to the registered set
- Document the {{{triple-stash}}} risk on failures.* fields with adversarial test names
- Document the workspace-containment and 1 MB sandboxing rules
Tests:
- Add coverage for path-traversal rejection, newline rejection, symlink escape, prototype
access denial, and history flattening
- Switch helper-registration and compile-spy tests to use an internal instance hook
- Add coverage for marker-injection scrubbing and empty-jobName fallback
- Set GITHUB_WORKSPACE per-test where templates are rendered
- Remove unused runtime-error.hbs fixture
* fix(templates): restore eager Handlebars.parse for syntax-error warnings
Handlebars.compile() defers parsing until render time, so without the eager
parse() call, syntax errors in user templates surface as "render error"
warnings instead of "parse error" warnings. The spec for story 8.3 requires
the "parse error in <path>: <reason>" format for compile-time failures
(AC #3).
The previous code-review labelled this call "redundant" but it is load-bearing.
* chore: rebuild dist
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.
Summary
src/api/client.ts) that POSTs parsed test results toPOST /api/v1/runswith Bearer token auth, exponential backoff retry (3 attempts: 1s, 2s delays), and 10s AbortController timeoutsrc/utils/detect-format.ts) from file extension (.xml→ JUnit,.json→ CTRF) with fallback to trying both parserssrc/utils/errors.ts) — all errors usecore.warning(), nevercore.setFailed()(FR5 compliance)src/index.ts: read file → detect format → parse → send to API → log resultTest plan
setFailednever called)run()pipeline: happy paths, all error scenarios, format detection, explicit override, AC7 guarantee)pnpm buildcompiles cleanlypnpm lintpassesgrepconfirmscore.setFailedabsent from all source files