HawkEye

repository·main·Indexed 41 days ago

https://github.com/korandoru/hawkeye

A license header checker and formatter providing a CLI and Rust library to ensure consistent licensing across codebases. It supports checking for missing or non-canonical headers, automatically formatting files to include headers, and removing recognized headers based on a TOML configuration.

Tokens
10.7K
Snippets
39
Records
47
Agent score
51%

What's inside HawkEye

  1. Use Properties and Jinja Templates in v7

    main

    v7 uses MiniJinja for templating. Unlike v6, which converted all properties to strings, v7 preserves original types (integers, booleans, arrays, tables) under the [props] table.

    Important Migration Notes:

    • Case Sensitivity: Built-in templates (Apache/Elastic) use snake_case. You must convert {{props.camelCase}} to {{ props.snake_case }}.
    • Strictness: v7 uses strict undefined values. If a property is missing from [props], the template will fail to render rather than producing an empty string.
    • Available Attributes: You can access file metadata via the attrs object:
      • attrs.filename
      • attrs.disk_file_created_year
      • attrs.disk_file_modified_year
      • attrs.git_file_created_year
      • attrs.git_file_modified_year
      • attrs.git_authors
    {# v6 style (string conversion) #}
    {{props["inceptionYear"]}} {{props["copyrightOwner"]}}
    
    {# v7 style (type preserved, snake_case) #}
    {{ props.inception_year }} {{ props.copyright_owner }}
  2. Use Path Templates in configuration

    main

    The files.root and header.path keys accept MiniJinja templates. These variables are captured when the configuration is loaded.

    VariableMeaning
    cwdThe absolute process working directory.
    config_dirThe absolute directory containing the config file, after resolving symlinks.

    Important Notes:

    • Relative paths and relative template results resolve from config_dir (the default scan directory if root is omitted).
    • Path templates do not expose environment variables.
    • For cross-platform compatibility (Windows), use the join_path filter: path = "{{ [config_dir, 'HEADER.txt'] | join_path }}".
    [files]
    root = "{{ cwd }}"
    
    [header]
    path = "{{ config_dir }}/HEADER.txt"
  3. Define File Selection and Rules

    main

    File Selection

    • files.includes and files.excludes use Git-ignore-style patterns relative to files.root.
    • An empty includes list selects all discovered files.
    • .git is always excluded.
    • File symlinks are followed; directory symlinks are not traversed.

    Rules and Styles

    Rules match complete filenames or case-insensitive filename suffixes (e.g., extensions = ["rs", "d.ts"]).

    • style_out: The canonical format written by HawkEye.
    • styles_in: A list of formats that may be recognized and safely replaced/removed. If empty, it defaults to [style_out]. A non-empty list must include style_out.
    • User rules are matched in declaration order before built-in rules.
  4. Configure Header Templates and Context

    main

    Headers can be defined using header.builtin (accepts Apache-2.0, Apache-2.0-ASF, or Elastic-2.0), header.path (loads a UTF-8 template from a file), or header.text (inline template).

    Templates use MiniJinja. The available context includes:

    ValueMeaning
    propsThe complete user-defined [props] table.
    attrs.filenameThe current file name.
    attrs.disk_file_created_yearFilesystem creation year, or null.
    attrs.disk_file_modified_yearFilesystem modification year, or null.
    attrs.git_file_created_yearYear the current exact-path lifetime began, or null.
    attrs.git_file_modified_yearLatest year in current exact-path history.
    attrs.git_authorsSorted distinct author names from current exact-path history.

    Note: HawkEye does not substitute the current year for unavailable values; fallbacks must be explicit in the template.

  5. Inventorying a v6 HawkEye setup

    main

    Before upgrading to v7, you must identify all existing HawkEye inputs, configuration files, and integrations. Use the following commands to locate configuration files and search for v6-specific keywords in your codebase.

    Locating Configuration Files

    Search for licenserc.toml or .licenserc.toml files:

    find . -name 'licenserc.toml' -o -name '.licenserc.toml'

    Searching for v6 Keywords

    Use rg (ripgrep) to find occurrences of v6 configuration keys and CLI terms:

    rg -n 'hawkeye|hawkeye-fmt|headerPath|inlineHeader|additionalHeaders|useDefault' .

    Checklist of items to record

    Ensure you have documented the following before converting to v7:

    • The selected config file and its baseDir.
    • The header delivery method (inline, bundled, or loaded from a file).
    • All files referenced by additionalHeaders.
    • Custom entries under [mapping.*] and the status of useDefaultMapping.
    • Negated exclude patterns and directories previously covered by v6 default excludes.
    • CLI flags that influence exit-code behavior in CI.
    • Existing integrations (GitHub Actions, Docker, pre-commit, Cargo, or library integrations).
    find . -name 'licenserc.toml' -o -name '.licenserc.toml'
    rg -n 'hawkeye|hawkeye-fmt|headerPath|inlineHeader|additionalHeaders|useDefault' .
  6. Update HawkEye CLI command line flags when migrating to v7

    main

    When migrating from v6 to v7, several CLI flags and behaviors have changed.

    • Failure modes: --fail-if-unknown is now --fail-on-unknown. For format and remove, use --fail-on-change to mimic the old behavior of failing if files were modified. By default, these commands now succeed after making changes.
    • Output: The --output <file> flag is replaced by --output-format json > <file>. All reports are sent to stdout, while logs and errors go to stderr.
    • Check command: check --fail-if-missing=true is no longer needed as check fails by default when changes are required. There is no direct equivalent for false; instead, consume the JSON report for non-failing audits.
    • Dry runs: --dry-run performs no writes. Note that v6 sibling files like .formatted or .removed are no longer created; use the JSON report instead.
    • Path arguments: v7 allows passing specific files or directories after the subcommand (e.g., hawkeye check src/lib.rs). If no paths are provided, it scans the configured set.
    # v6 style
    hawkeye --fail-if-unknown --output report.json
    
    # v7 style
    hawkeye --fail-on-unknown --output-format json > report.json
    
    # v7 check with specific paths
    hawkeye check src/lib.rs src/bin
  7. Install HawkEye as a Library-only Dependency

    main

    By default, the hawkeye crate includes the application feature which builds the command-line tool. If you only need the library, you can omit the CLI dependencies to reduce build time and dependency footprint:

    hawkeye = { version = "7", default-features = false }
  8. Migrate HawkEye v6 configuration to v7

    main

    When migrating from v6 to v7, the configuration structure changes from a flat or loosely grouped format to a strictly categorized one. Key changes include moving file settings under [files], header settings under [header], and properties under [props].

    Key Field Mappings:

    • baseDir $\rightarrow$ files.root (Use {{ cwd }} to maintain invocation-relative paths).
    • headerPath $\rightarrow$ header.builtin (for bundled headers) or header.path (for custom files).
    • properties $\rightarrow$ props (Values retain original types like integers/booleans).
    • git.attrs $\rightarrow$ git.file_attrs.
    • [mapping.STYLE] $\rightarrow$ [[rules]] (Rules are now an ordered list).

    Example Migration:

    v6 Config:

    baseDir = ".
    headerPath = "Apache-2.0.txt"
    strictCheck = true
    includes = ["**/*.rs"]
    [properties]
    inceptionYear = 2022
    [git]
    attrs = "disable"

    v7 Config:

    [header]
    builtin = "Apache-2.0"
    
    [files]
    root = "{{ cwd }}"
    includes = ["**/*.rs"]
    
    [props]
    inception_year = 2022
    
    [git]
    file_attrs = "disable"
  9. Integrate HawkEye with GitHub Actions

    main

    You do not need a dedicated GitHub Action. Simply install the released binary using taiki-e/install-action and run the hawkeye command directly in your workflow.

    - uses: actions/checkout@v7
    - uses: taiki-e/install-action@v2
      with:
        tool: hawkeye
    - run: hawkeye check
  10. Migrating from HawkEye v6 to v7

    main

    HawkEye v7 is a complete rewrite. It is not backward compatible with v6 configuration aliases and has transitioned from camelCase to snake_case for configuration keys. This migration guide is intended for users moving from v6.5.x to v7.

    Migration Rules

    • Clean Branch: Work on a separate branch and keep the v6 configuration intact until the v7 configuration is verified.
    • No Aliases: Do not attempt to add v6 compatibility aliases to the v7 configuration. You must replace every v6 field and invocation at its source.
    • Preservation: Maintain the same rendered license text, selected files, and failure policies unless a v7 semantic change is explicitly noted.
    • Exit Codes:
      • exit code 1: Indicates the configuration loaded successfully, but one or more files require attention (e.g., via check).
      • exit code 2: Indicates a migration error or a runtime error.
    • Safety: Always review a dry-run report before allowing the format command to write files. Do not ignore conflict outcomes.
  11. Update pre-commit configuration for HawkEye v7

    main

    Update your .pre-commit-config.yaml to use the new repository and revision.

    Note on file selection: By default, v7 hooks pass only the files selected by pre-commit. To force a full-repository scan, set pass_filenames: false and always_run: true in your hook configuration.

    repos:
      - repo: https://github.com/fast/hawkeye
        rev: v7.0.0
        hooks:
          - id: hawkeye-format
  12. Update Docker integration for HawkEye v7

    main

    When using Docker, use the new image namespace and mount your repository at /workspace.

    docker run --rm --user "$(id -u):$(id -g)" --volume "$PWD:/workspace" ghcr.io/fast/hawkeye:v7.0.0 check