Skip to content

Latest commit

 

History

History
244 lines (173 loc) · 19.3 KB

File metadata and controls

244 lines (173 loc) · 19.3 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]


[1.0.1] — 2026-05-25

Fixed

  • --ignore doublestar (**) glob patterns — patterns like **/generated/**, docs/**/*.md, and **/node_modules now resolve correctly at any directory depth. The scanner previously used filepath.Match, which silently ignored ** patterns. It now uses github.com/bmatcuk/doublestar/v4 for both relative-path and basename matching. Simple glob patterns (*.pb.go) and substring patterns (generated) continue to work unchanged.

Improved

  • Ecosystem documentation — README now includes an Ecosystem section linking addlicense-action, addlicense-npm, addlicense-winget, and the Homebrew tap. The GitHub Action example was corrected (GregoireF/addlicense-action@v1, not the core repo).

[1.0.0] — 2026-05-22

Added

  • --sbom <file> flag — generates a minimal SPDX 2.3 tag-value document from the existing licence headers in the scanned files. No files are modified. Output path accepts - for stdout. For each file: LicenseInfoInFile comes from the SPDX-License-Identifier: header in the file; LicenseConcluded falls back to --license when the file has no header; FileCopyrightText comes from the copyright line. Designed for EU Cyber Resilience Act compliance (ENISA CRA guidance, SPDX 2.3 file-element section).
  • internal/sbom package — pure-Go SPDX 2.3 tag-value document builder. No external SPDX library dependency — keeps the binary lean and the build reproducible. Build(Document) string generates valid SPDX 2.3 with document header, package section, file elements, and CONTAINS relationships. Deterministic output (walk order from filepath.WalkDir).
  • injector.ExtractLicenseInfo(path) — reads the first 20 lines and returns the SPDX-License-Identifier value and the first copyright line. Used by the SBOM mode to audit existing file state without modifying files.
  • Sbom string in pkg/addlicense.Options — SBOM mode available from the public Go library API.

Changed

  • validateOpts refactored into validateOutputOpts + validateModeMutualExclusion to keep cyclomatic complexity under the gocyclo-15 lint threshold after adding the new --sbom exclusions.
  • pkg/addlicense.DefaultIgnore is now an independent copy of the internal default list (not an alias). Appending to it is safe across callers without risk of mutating the shared source.

Fixed

  • PATH conflict documentedgo install overwrites google/addlicense when both are installed. README now warns and recommends binary download or Docker to avoid the collision.

Stable API (v1.0.0 guarantee)

The pkg/addlicense package is now under semantic versioning freeze. Any rename, removal, or signature change to an exported symbol requires a v2.0.0 major version bump. internal/ packages remain free to evolve.

Extended test suite:

  • internal/sbom/sbom_test.go: 8 tests — header section, file with/without header, fallback licence, multiple files, namespace, defaults, path normalisation.
  • internal/injector: 5 new TestExtractLicenseInfo tests — both fields present, REUSE style, no header, file not found, beyond scan window.
  • tests/integration: 4 new SBOM tests — writes file, unlicensed fallback, mutual exclusion, stdout.
  • tests/cli: 3 new SBOM tests — writes file, stdout, mutual exclusion.
  • pkg/addlicense: 1 new SBOM test.

[0.9.0] — 2026-05-22

Added

  • Extended language support — 8 new file types recognised out of the box:

    Extension(s) Comment style Language
    .lua -- line Lua
    .nix # line Nix
    .zig // line Zig
    .dockerfile # line Dockerfile (named variants, e.g. app.dockerfile)
    .mk # line Makefile fragments
    .md .mdx <!-- block --> Markdown / MDX (HTML comments are invisible in rendered output)
  • --author-file flag — reads copyright holders from a text file, one per line. Lines starting with # and blank lines are ignored. Mutually exclusive with --author. Useful for organisations that maintain an AUTHORS file or CODEOWNERS list.

    # AUTHORS
    Alice Dupont
    Bob Martin
    
    addlicense --license MIT --author-file AUTHORS .
  • Extended test suite:

    • internal/header: 7 new TestLangFor cases for new extensions.
    • tests/integration: 5 new tests — TestRun_NewLang_Lua, _Nix, _Zig, _Dockerfile, _Markdown.
    • tests/cli: 4 new tests — TestCLI_AuthorFile_InjectsAllAuthors, _MutualExclusionWithAuthor, _NotFound, _Empty_Error.

[0.8.0] — 2026-05-22

Added

  • Public Go API (pkg/addlicense)addlicense is now importable as a Go library without invoking a subprocess. Import path: github.com/GregoireF/addlicense/pkg/addlicense. The public surface is a distinct Options struct and a Run(Options) error function, backed by the mature internal/ implementation. This allows IDE plugins, CI runners, and code generators to embed addlicense natively.
    • Options mirrors all CLI flags: License, Author, Template, Ignore, Year, Paths, CheckOnly, Reuse, Remove, Update, DryRun, Diff, YearRange, Dep5, Verbose, Quiet, Format, Workers.
    • DefaultIgnore re-exported from internal/config so callers can extend without modifying the original slice.
    • FormatText and FormatJSON constants for the Format field.
    • A thin toInternal conversion layer maps pkg.Options → config.Options; internal/ packages can refactor freely without breaking the public API.
  • pkg/addlicense/addlicense_test.go — 12 tests covering: licensed/unlicensed check mode, header injection, idempotence, diff mode (no write), dry run (no write), remove, REUSE mode, multi-author, and mutual-exclusion validation.

[0.7.0] — 2026-05-22

Fixed

  • File permission preservationinjector.Inject and injector.Remove now preserve the original file's permission bits (info.Mode().Perm()) instead of always writing 0o644. Previously, executable scripts (chmod +x deploy.sh) would silently lose their execute bit after an addlicense run. The fix is a no-op on Windows where the OS does not enforce Unix permission bits.

Improved

  • Coverage: 89.1% → 90.4% — 10 new integration tests covering diffFile error paths, remove-with-header, remove-without-header, update-no-header, and malformed-template error propagation. Dead code removed from emit (text-mode diff branch was unreachable since handleResults forces JSON when --diff is set). emit function is now 100% covered.
  • Documentation--ignore matching rules documented (glob + substring semantics). Multi-author + --update replace semantics documented in README.

Added

  • TestInject_PreservesPermissions and TestRemove_PreservesPermissions (skipped on Windows).

[0.6.0] — 2026-05-22

Added

  • Multi-author support--author now accepts a comma-separated list of copyright holders (e.g. --author "Alice, Bob"). Each author gets its own copyright line in the rendered header; single-author behaviour is unchanged. Works with --reuse (emits SPDX-FileCopyrightText: per author) and --year-range.
  • --diff flag — emits JSON Lines ({"file":"…","status":"diff-add|diff-update|diff-remove","header":"…"}) for every file that would be modified, without writing to disk. Exit 1 if any file would change, exit 0 if the tree is already up to date. Designed for PR validation pipelines: "does this PR introduce files without license headers?" Mutually exclusive with --check.
  • Error double-print fixSilenceErrors: true added to the Cobra root command; errors are now printed exactly once (by main) instead of twice (Cobra + main).
  • Extended test suite:
    • tests/integration/: 9 new tests — multi-author (two authors, REUSE mode, single-author unchanged); --diff (no-write exit 1, already-licensed exit 0, JSON with header field, --update emits diff-update, --check conflict).
    • tests/cli/: 4 new tests — TestCLI_MultiAuthor, TestCLI_Diff_NoWrite_ExitsOne, TestCLI_Diff_AlreadyLicensed_ExitsZero, TestCLI_Diff_CheckConflict.
    • internal/injector/bench_test.go — 7 micro-benchmarks (HasHeader, Inject, Remove, ExtractYear, large-file variants).
    • tests/bench/pipeline_bench_test.go — 12 pipeline benchmarks (Add/Check/Idempotent at scale, Workers 1/4/NumCPU).

[0.5.0] — 2026-05-20

Added

  • --year-range flag — when combined with --update, reads the original copyright year from the existing header and emits YYYY-YYYY (e.g. Copyright 2023-2026 Author) instead of overwriting with the current year alone. Falls back silently to a single year when the original year cannot be extracted or equals the current year. Works with --reuse (emits SPDX-FileCopyrightText: 2023-2026 Author).
  • --dep5 flag — generates a REUSE-compliant .reuse/dep5 bulk-licence declaration for files that cannot carry inline SPDX headers (images, fonts, binaries, and any other extension not in the language map). The dep5 root defaults to the first path argument. Supports --dry-run (prints [dry-run] would-write: .reuse/dep5).
  • Native GitHub Action (action.yml) — composite action using runner.os and runner.arch detection to download the correct binary from the GitHub Release tag, add it to $GITHUB_PATH, and run addlicense. Supports ubuntu-*, macos-*, and windows-* runners on amd64 + arm64. Usage: uses: GregoireF/addlicense@v0.5.0 with optional args input (default: --check .).
  • internal/dep5 package — pure Go dep5 document generator; Build(paths, year, author, license) returns the formatted dep5 content.
  • Extended test suite:
    • internal/injector: 5 new unit tests for ExtractYear — copyright, SPDX-FileCopyrightText, no year, file not found, beyond scan window.
    • internal/dep5: 5 unit tests — with paths, empty paths (header-only), no author, multiple paths (continuation lines), forward-slash path normalisation.
    • tests/integration/: 7 new tests — --year-range (original preserved, same year, no header, with REUSE); --dep5 (creates file, no unhandled files, dry-run).

[0.4.0] — 2026-05-20

Added

  • --remove / -R flag — strips existing license headers from files. Detection uses the same heuristic as the idempotence check (top-20-line scan for spdx-license-identifier or copyright); only comment blocks that contain a license marker are removed — non-license comment blocks (package docs, etc.) are left untouched. Handles both line-comment (//, #, --) and block-comment (<!-- -->, /* */) styles.
  • --update / -u flag — replaces the existing header with a new one in a single pass (--remove + inject). The canonical migration workflow: addlicense --update --license EUPL-1.2 .
  • --dry-run / -n flag — previews changes without writing to disk. Emits [dry-run] would-add: <path>, [dry-run] would-remove: <path>, [dry-run] would-update: <path> for every file that would be affected.
  • --verbose / -v flag — prints every processed file, including already-licensed ones (skipped / ok), in addition to the default modified-file output.
  • --quiet / -q flag — suppresses all stdout; errors still go to stderr. Designed for pure CI pipelines where only the exit code matters.
  • --format / -f flag — selects output format: text (default, human-readable) or json (JSON Lines: {"file":"…","status":"…","error":"…"}). The string flag is extensible to future formats without breaking the CLI contract.
  • --workers flag — controls the number of parallel goroutines (default: runtime.NumCPU()). Files are processed concurrently via a buffered jobs channel and a sync.WaitGroup-managed worker pool, bounded to min(workers, len(files)).
  • reuse: field in .addlicenserc.yamlreuse: true in the config file now activates REUSE/FSFE mode without requiring the --reuse flag on every invocation. CLI flag takes precedence per the usual merge order.
  • .pre-commit-hooks.yaml — official pre-commit hook definitions shipped in the repository root. Two hooks: addlicense-check (exit 1 on missing headers, read-only) and addlicense-add (inject missing headers). Language is golang; pre-commit installs the binary automatically via go install. Both hooks set pass_filenames: false and always_run: true.
  • Extended test suite:
    • internal/injector: 8 new unit tests covering Remove — line-comment removal, shebang preservation, idempotence, non-license-comment safety, block-comment HTML/CSS styles, nonexistent-file error.
    • internal/config: 3 new unit tests covering reuse: merge — from config file, CLI precedence, default false.
    • tests/integration/: 20 new integration tests covering --remove, --update, --dry-run, --quiet, --verbose, --format json, --workers, --format xml (invalid), all mutual-exclusion flag combinations, reuse: from config file, and parallel processing across 20 files.

Changed

  • Mutual exclusion validation (validateOpts): --verbose--quiet, --check ⊕ (--remove--update), --remove--update — all return descriptive errors before any file I/O.
  • Runner refactored into runParallel + processFile + per-mode functions (checkFile, addFile, removeFile, updateFile) to keep cyclomatic complexity under the gocyclo-15 limit.

[0.3.0] — 2026-05-20

Added

  • --reuse / -r flag — emits SPDX-FileCopyrightText: <year> <author> instead of Copyright <year> <author>, complying with the REUSE/FSFE specification. Idempotence works transparently (FileCopyrightText contains copyright as a substring). Opt-in flag rather than default to preserve grep -r "Copyright" workflows; making it the default would require a major version bump.
  • header.Data.CopyrightLine — pre-formatted string computed once by runner.buildCopyrightLine(year, author, reuse) and consumed by all built-in templates via {{.CopyrightLine}}; removes per-template {{if .Author}} conditionals and centralises REUSE/non-REUSE logic in one place.
  • Built-in SPDX templates: EUPL-1.2, AGPL-3.0-only, LGPL-2.1-only, LGPL-3.0-only — EU public sector and strong-copyleft licences (see ROADMAP.md for compliance context).
  • golangci-lint v2 configuration (.golangci.yml): 15 linters beyond the default — bodyclose, exhaustive, goconst, gocritic, gocyclo, godot, misspell, nestif, nilerr, prealloc, revive, unconvert, unparam; goimports in formatters section (v2 separates formatters from linters).
  • Codecov (.codecov.yml): 90 % coverage threshold enforced on both project and patch.
  • Extended test suite — coverage ≥ 90 %:
    • internal/scanner: 4 unit tests — glob ignore patterns, invalid root, no-extension files, markdown/JSON collection
    • internal/injector: 5 unit tests — file-not-found, empty file, scan-window boundary, case-insensitive detection
    • internal/config: 11 unit tests — Load priority rules, YAML/YML/JSON auto-detection, CLI flag override, invalid YAML error
    • tests/integration/: 3 REUSE tests + 8 additional scenarios (block/HTML/SQL comment styles, EU licences, multiple roots, custom templates)
  • CONTRIBUTING.md — development setup, test commands, lint config decisions, commit/PR conventions, adding-a-language and adding-a-template guides, release process, design principles.
  • CHANGELOG.md and ROADMAP.md — version planning and EU/French compliance context.
  • GitHub issue templates (.github/ISSUE_TEMPLATE/): bug report and feature request with structured fields.
  • GitHub PR template (.github/PULL_REQUEST_TEMPLATE.md): checklist covering tests, CHANGELOG, lint, coverage.
  • CODEOWNERS — GregoireF as default reviewer on all PRs.

Changed

  • GoReleaser v2: brews: key replaced by homebrew_casks: (removed in v2.10) — Homebrew tap formula now lives at Casks/addlicense.rb; old Formula/addlicense.rb removed from tap.
  • CI coverage: -coverpkg=./... flag ensures integration tests in tests/integration/ correctly attribute coverage to internal/ packages.
  • Test organisation: integration tests promoted from internal/runner/ to dedicated tests/integration/ package (package integration_test), following Go conventions.

Fixed

  • internal/header/header.go: Lang struct and langs map brought into strict gofmt compliance — gofmt aligns map-literal values per comment-separated group (comments reset the tabwriter), not globally.

[0.2.0] — 2026-05-19

Added

  • Extended language support: .html, .vue, .svelte (<!-- -->), .css, .scss (/* */), .proto (//), .sql (--)
  • Docker image published to GHCR (ghcr.io/gregoiref/addlicense) on every release tag
  • Codecov integration — coverage badge in README
  • .addlicenserc.yaml dogfooding — repo now uses its own config file; CI no longer hardcodes --license and --author flags
  • Dependabot for Go modules and GitHub Actions (weekly, auto-merge on passing checks)
  • Auto-merge workflow for Dependabot PRs

Changed

  • GitHub Actions bumped to Node.js 24 compatible versions: actions/checkout v6, actions/setup-go v6, goreleaser/goreleaser-action v7, golangci-lint-action v9
  • CI caching re-enabled after go.sum committed
  • goreleaser-action version locked to ~> v2 (was latest)

Fixed

  • errcheck lint violations: HasHeader refactored from bufio.Scanner + defer f.Close() to os.ReadFile — no unchecked close error
  • f.Close() in injector test helper now checked and fatal on error

[0.1.0] — 2026-05-18

Added

  • Initial release
  • Unified CLI — single command, no subcommands: addlicense [flags] [path...]
  • Flags: --license / -l, --author / -a, --year / -y (defaults to current year), --template / -t, --ignore / -i, --check / -c, --version
  • Built-in SPDX templates: MIT, Apache-2.0, GPL-3.0-only, MPL-2.0, BSD-2-Clause, BSD-3-Clause
  • Generic fallback template for any other SPDX identifier
  • Custom header template support via --template ./header.txt
  • Config file auto-detection in priority order: .addlicenserc.yaml, .addlicenserc.yml, .addlicenserc.json, addlicense.json
  • Idempotent header detection — scans first 20 lines for SPDX-License-Identifier: or copyright; already-licensed files are skipped
  • Shebang line preservation (#!/usr/bin/env bash stays on line 1)
  • Supported languages: Go, TypeScript/TSX, JavaScript/JSX, Java, C/C++/H, Rust, Python, Shell/Bash, YAML, Terraform, TOML, Ruby, Swift, Kotlin, Scala, PHP, C#
  • Check mode: exit 0 if all files are licensed, exit 1 with list of missing files
  • Multi-platform binaries: Linux, macOS, Windows × amd64, arm64 — via GoReleaser
  • Homebrew tap: brew install GregoireF/tap/addlicense
  • Docker image (FROM scratch, ~3 MB): ghcr.io/gregoiref/addlicense
  • Dogfooding: the license-check CI workflow runs addlicense on its own source on every push