Skip to content

Merge pull request #1048 from kucherenko/docs/language-aware #579

Merge pull request #1048 from kucherenko/docs/language-aware

Merge pull request #1048 from kucherenko/docs/language-aware #579

Workflow file for this run

name: Rust
on:
push:
branches: [main, master, "heist/*"]
pull_request:
branches: [main, master, "heist/*"]
permissions:
contents: read
jobs:
build:
permissions:
contents: read
checks: write # dorny/test-reporter posts check runs
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
toolchain: "1.97.1"
components: clippy, rustfmt
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
with:
workspaces: "rust -> rust/target"
cache-on-failure: true
- name: Install cargo-nextest
uses: taiki-e/install-action@d438492cf8a250514fa2d34b30bc3c0dc37c65ff # v2.87.8
with:
tool: nextest
- name: Build
working-directory: rust
run: cargo build --workspace
- name: Test
working-directory: rust
run: cargo nextest run --workspace --profile ci
- name: Upload test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nextest-results-${{ matrix.os }}
path: rust/target/nextest/ci/nextest.xml
if-no-files-found: warn
- name: Test Report
if: always()
continue-on-error: true
uses: dorny/test-reporter@a43b3a5f7366b97d083190328d2c652e1a8b6aa2 # v3.0.0
with:
name: Rust Tests (${{ matrix.os }})
path: rust/target/nextest/ci/nextest.xml
reporter: java-junit
fail-on-error: false
- name: Clippy
working-directory: rust
run: cargo clippy --workspace -- -D warnings
- name: Format check
working-directory: rust
run: cargo fmt --check
# Bash-only steps below run on Linux; Windows defaults to pwsh.
- name: Tokenizer purity check
if: runner.os == 'Linux'
run: |
cd rust
TOKENIZER_DEPS=$(cargo metadata --format-version 1 | \
python3 -c "
import sys, json
meta = json.load(sys.stdin)
tokenizer_id = next(p['id'] for p in meta['packages'] if p['name'] == 'cpd-tokenizer')
dep_names = set()
queue = [tokenizer_id]
id_to_pkg = {p['id']: p for p in meta['packages']}
resolve_map = {n['id']: [d['pkg'] for d in n['deps']] for n in meta['resolve']['nodes']}
visited = set()
while queue:
pid = queue.pop()
if pid in visited: continue
visited.add(pid)
if pid in id_to_pkg:
dep_names.add(id_to_pkg[pid]['name'])
for dep_id in resolve_map.get(pid, []):
queue.append(dep_id)
print('\n'.join(dep_names))
")
echo "cpd-tokenizer transitive deps: $TOKENIZER_DEPS"
for crate in tokio async-std walkdir ignore jwalk; do
if echo "$TOKENIZER_DEPS" | grep -q "^$crate$"; then
echo "ERROR: cpd-tokenizer depends on I/O crate: $crate"
exit 1
fi
done
echo "Tokenizer purity check: PASS"
- name: publish=false check
if: runner.os == 'Linux'
run: |
cd rust
for toml in crates/*/Cargo.toml; do
if ! grep -q 'publish = false' "$toml"; then
echo "ERROR: $toml missing 'publish = false'"
exit 1
fi
done
echo "publish=false check: PASS"
- name: cargo-deny
if: matrix.os == 'ubuntu-latest'
working-directory: rust
run: cargo install cargo-deny --locked && cargo deny check
msrv:
name: MSRV
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Read declared MSRV
id: msrv
run: |
version=$(sed -nE 's/^rust-version = "([0-9.]+)"$/\1/p' rust/Cargo.toml | head -1)
if [ -z "$version" ]; then
echo "ERROR: no rust-version found in rust/Cargo.toml"
exit 1
fi
echo "Declared MSRV: $version"
echo "version=$version" >> "$GITHUB_OUTPUT"
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
toolchain: ${{ steps.msrv.outputs.version }}
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
with:
workspaces: "rust -> rust/target"
key: msrv-${{ steps.msrv.outputs.version }}
cache-on-failure: true
# `+toolchain` outranks rust-toolchain.toml, which pins a newer compiler
# for day-to-day development. Without it this job would silently test the
# pinned version instead of the MSRV.
- name: cargo check at MSRV
working-directory: rust
run: cargo +${{ steps.msrv.outputs.version }} check --workspace --all-targets --locked
# End-to-end run of the release binary over the multi-format corpus in
# fixtures/ (550 files across 130+ formats). Unit tests cover the parts;
# this catches a reporter or walker regression that only shows on the
# real corpus.
smoke:
name: smoke test (fixtures corpus)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
toolchain: "1.97.1"
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
with:
workspaces: "rust -> rust/target"
key: smoke-release
cache-on-failure: true
- name: Build release binary
working-directory: rust
run: cargo build --release -p jscpd --locked
- name: Scan fixtures (console + json)
working-directory: rust
run: ./target/release/jscpd ../fixtures --reporters console,json --output ../smoke-report --min-tokens 50
- name: Assert JSON report
run: |
report=smoke-report/jscpd-report.json
test -s "$report"
clones=$(jq '.statistics.total.clones' "$report")
sources=$(jq '.statistics.total.sources' "$report")
formats=$(jq '.statistics.formats | keys | length' "$report")
duplicates=$(jq '.duplicates | length' "$report")
echo "clones=$clones sources=$sources formats=$formats duplicates=$duplicates"
[ "$clones" -gt 0 ] || { echo "expected statistics.total.clones > 0"; exit 1; }
[ "$duplicates" -eq "$clones" ] || { echo "duplicates[] length ($duplicates) != statistics.total.clones ($clones)"; exit 1; }
[ "$sources" -ge 300 ] || { echo "expected at least 300 scanned files, got $sources"; exit 1; }
[ "$formats" -ge 100 ] || { echo "expected at least 100 detected formats, got $formats"; exit 1; }
- name: SARIF reporter
working-directory: rust
run: |
./target/release/jscpd ../fixtures --reporters sarif,silent --output ../smoke-report --min-tokens 50
jq -e '.runs[0].results | length > 0' ../smoke-report/jscpd-report.sarif
- name: HTML reporter
working-directory: rust
run: |
./target/release/jscpd ../fixtures --reporters html,silent --output ../smoke-report --min-tokens 50
test -s ../smoke-report/jscpd-report.html