CI and Baselines
CukeDedup can gate a repository through its CLI or GitHub Action. Start with warnings or a baseline when introducing it to an established suite, then tighten policy deliberately.
GitHub Action
Section titled “GitHub Action”The Action downloads the native binary for the runner and verifies its checksum, provenance bundle, build identity, and archive contents before execution.
permissions: contents: read
steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 persist-credentials: false
id: cuke-dedup with: path: . threshold: 5 config: .cuke-dedup.json exclude: | generated/** fixtures/vendor/** reporters: terminal,json,html,sarif changed-since: ${{ github.event.pull_request.base.sha }} no-metrics: true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: name: cuke-dedup-reports path: reports/cuke-dedup/The Action exposes:
exit-codeduplicate-rateduplicate-definitionstotal-definitionsjson-reporthtml-reportsarif-report
It adds JSON internally when necessary so these outputs remain available. Omitted threshold, reporter, and output inputs preserve project configuration; explicit Action inputs override it. Inputs are passed directly to the native executable as an argument array.
Set reporters: jsonl for an agent-oriented stream in the step log. The Action still creates its
internal JSON report. Set fail-on-incomplete: true when truncated comparisons or an incomplete
corpus must fail with exit code 2.
Downloads require the archive, adjacent SHA-256 checksum, provenance bundle, and exact expected
archive structure. Verification uses the GitHub CLI installed on GitHub-hosted runners and needs
no repository secret or expanded permission. A self-hosted runner must provide gh on PATH.
For security-sensitive workflows, pin CukeDedup to the release tag’s full commit SHA. Use
continue-on-error only when a later step deliberately evaluates the exit-code output.
The GitHub Action retries HTTP 404 responses while release assets become available, with at most ten attempts and 65 seconds of total backoff per asset. Other HTTP errors, network failures, and stream failures stop immediately. Checksum and provenance verification remain required.
Changed-file analysis
Section titled “Changed-file analysis”Report only findings that involve files changed from a Git revision while still comparing those files against the complete corpus:
cuke-dedup . --changed-since origin/mainPaths remain correct from a repository subdirectory, and untracked files are included. Summary definition counts and the duplication-threshold denominator describe the complete corpus.
An empty changed-file set warns. Changed-file filtering does not relax corpus validation:
operational read, extraction and feature-parse errors remain fatal even in unchanged files. Use
--fail-on-unparseable for definition parse failures or --fail-on-incomplete for all
incompleteness.
Semantic baselines
Section titled “Semantic baselines”Create or replace a baseline from a complete analysis:
cuke-dedup . \ --baseline .cuke-dedup-baseline.json \ --update-baselineThen allow only a configured number of findings beyond it:
cuke-dedup . --baseline .cuke-dedup-baseline.json --fail-on-newcuke-dedup . --baseline .cuke-dedup-baseline.json --fail-on-new 3--fail-on-new defaults to zero when no count is supplied and requires --baseline or
--baseline-from-ref. --update-baseline requires the file form and cannot be combined with
--fail-on-new. The Action exposes baseline, baseline-from-ref, and fail-on-new inputs.
Baselines store sorted semantic fingerprints with multiplicity counts. Renames and unrelated line
changes do not make a finding new, while an additional occurrence beyond the recorded count does.
Version 1 and 2 baselines can be replaced by running the version 3 tool with
--update-baseline; comparison rejects mismatched schemas and names the regeneration command.
Updates reject --changed-since and are skipped after incomplete analysis or an operational
error, preventing a partial scan from erasing accepted findings.
Compare against a Git revision
Section titled “Compare against a Git revision”Instead of committing a baseline file, compare with a revision that is already fetched locally:
cuke-dedup . --baseline-from-ref origin/main --fail-on-newThe corresponding Action inputs are:
with: baseline-from-ref: ${{ github.event.pull_request.base.sha }} fail-on-new: '0'Use checkout with fetch-depth: 0, or fetch the revision before analysis. CukeDedup does not
fetch revisions, initialize submodules, install dependencies, or run project code.
The base is scanned in a temporary independent Git checkout using the current effective
CukeDedup configuration, including rule overrides, patterns and suppressions. Missing
refs/directories, unsupported submodules, base extraction errors, and definitions without a
feature corpus fail with exit code 2; none become an empty accepted baseline. Any other
incomplete base is used for the findings it extracted and reported with a warning, since a finding
it missed may appear as new; --fail-on-incomplete rejects it with exit code 2. Hooks and
configured checkout filters are disabled, so Git LFS content is not hydrated. The full repository
snapshot is limited to 512 MiB of tracked content and 100,000 files; larger repositories can use a
committed baseline instead. Git submodules anywhere in that snapshot are rejected because their
content is not materialized.
The new-finding allowance is an additional gate: it does not disable the duplication threshold or independent error rules.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 |
The threshold passed and no independent error policy failed. |
1 |
The threshold, an error-level rule, or the new-finding allowance failed. |
2 |
Discovery, parsing, configuration, or another operational failure. |
Warnings alone do not produce exit code 1. See Rules for threshold behavior and
Reports for generated artifacts.