Skip to content

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.

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
- uses: figueiredoluiz/[email protected]
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-code
  • duplicate-rate
  • duplicate-definitions
  • total-definitions
  • json-report
  • html-report
  • sarif-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.

Report only findings that involve files changed from a Git revision while still comparing those files against the complete corpus:

Terminal window
cuke-dedup . --changed-since origin/main

Paths 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.

Create or replace a baseline from a complete analysis:

Terminal window
cuke-dedup . \
--baseline .cuke-dedup-baseline.json \
--update-baseline

Then allow only a configured number of findings beyond it:

Terminal window
cuke-dedup . --baseline .cuke-dedup-baseline.json --fail-on-new
cuke-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.

Instead of committing a baseline file, compare with a revision that is already fetched locally:

Terminal window
cuke-dedup . --baseline-from-ref origin/main --fail-on-new

The 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.

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.