python-license 1.2.2
Automatically adds or updates SPDX license and copyright headers in source files.
License: Apache-2.0
Requires Python: >=3.11
Keywords: copyright, headers, license, source-code, spdx

# Python License

[![PyPI version](https://badge.fury.io/py/python-license.svg)](https://badge.fury.io/py/python-license)
[![Python versions](https://img.shields.io/pypi/pyversions/python-license.svg)](https://pypi.org/project/python-license/)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Tests](https://github.com/eznix86/python-license/workflows/Tests/badge.svg)](https://github.com/eznix86/python-license/actions)

One command to add SPDX license headers to all your source files. Works best with pre-commit hooks.

## What It Does

Automatically adds SPDX-compliant license headers to your source files.

**For Python files:**
```python
# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2025  Your Name

def your_code():
    pass
```

**For JavaScript/TypeScript/Go/Rust:**
```javascript
// SPDX-License-Identifier: MIT
// Copyright (C) 2025  Your Company

function yourCode() {}
```

**For CSS/HTML:**
```css
/* SPDX-License-Identifier: Apache-2.0 */
/* Copyright (C) 2025  Your Name */

body { margin: 0; }
```

### Key Features

- Supports 50+ file types including Python, JavaScript, TypeScript, Go, Rust, Java, C/C++, Swift, Kotlin, Ruby, Shell, SQL, and more
- Automatically updates copyright year ranges (e.g., `2023` becomes `2023-2025` when modified)
- Check mode for CI/CD integration to ensure all files have headers
- Respects `.licenseignore` and `.gitignore` files automatically
- Preserves shebang lines in executable scripts
- Handles multiple comment styles (hash, slash, dash, block comments)

## Supported Languages

**Hash comments (#):** Python, Shell (bash/zsh/fish), Ruby, Perl, R, YAML, TOML, CMake

**Slash comments (//):** JavaScript, TypeScript, Go, Rust, Java, C/C++, Swift, Kotlin, C#, PHP, Scala, Objective-C, Gradle, Groovy, SCSS, Sass, Less

**Dash comments (--):** SQL, Lua, Haskell, Elm

**Block comments:** CSS (`/* */`), HTML/XML/SVG (`<!-- -->`)

**Special files:** Dockerfile, Makefile, Jenkinsfile, Vagrantfile, Rakefile, Gemfile, Podfile, Fastfile, CMakeLists.txt, and more

## Installation

```sh
pipx install python-license
```

Or with pip:
```sh
pip install python-license
```

## Usage

### Command Line

Basic syntax:
```sh
license <license-id> "<author>" [options]
```

Examples:
```sh
# Check files without modifying (dry-run)
license Apache-2.0 "John Doe" --check

# Add/update headers in specific directory
license MIT "Jane Smith" --fix --dir src/

# Use custom ignore file
license GPL-3.0 "ACME Corp" --ignore-file .licenseignore --fix

# Process specific files only
license Apache-2.0 "Your Name" --fix file1.py file2.js

# Set custom copyright year
license MIT "Your Company" --fix --year 2024
```

### Pre-commit Hook (Recommended)

Add to your `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/eznix86/python-license
    rev: v1.0.1
    hooks:
      - id: license-headers
        args: ['--check', 'Apache-2.0', 'Your Name']
```

For automatic fixing on commit:
```yaml
repos:
  - repo: https://github.com/eznix86/python-license
    rev: v1.0.1
    hooks:
      - id: license-headers
        args: ['--fix', 'Apache-2.0', 'Your Name']
```

See [.pre-commit-config.yaml](./.pre-commit-config.yaml) for a complete example.

### Options

| Option | Description |
|--------|-------------|
| `--check` | Check files without modifying (default mode) |
| `--fix` | Add or update headers in files |
| `--dir DIR` | Root directory to process (default: current directory) |
| `--year YEAR` | Copyright year (default: current year) |
| `--no-recursive` | Don't process subdirectories |
| `--verbose`, `-v` | Show all processed files |
| `--ignore-file FILE` | Path to ignore file (default: .licenseignore or .gitignore) |
| `files` | Specific files to process (overrides --dir) |

### Ignore Files

Create a `.licenseignore` file to exclude specific files or directories:

```
# Ignore patterns (similar to .gitignore)
*.min.js
*.min.css
generated/*
vendor/
third_party/
build/
dist/

# Negate patterns (don't ignore these)
!important.min.js
```

If no `.licenseignore` exists, the tool automatically uses `.gitignore` patterns.

See [.licenseignore](./.licenseignore) for an example.

## FAQ

### Does it overwrite existing headers?

No, it intelligently updates them. If a file already has an SPDX header, it will:
- Update the license identifier if changed
- Update the copyright year range (e.g., `2023` → `2023-2025`)
- Preserve the existing header structure

### How does it handle copyright years?

The tool automatically manages copyright year ranges:
- First added: `Copyright (C) 2025  Your Name`
- After modification in 2026: `Copyright (C) 2025-2026  Your Name`
- If already current: no change

### Can I use it in CI/CD?

Yes! Use `--check` mode to fail the build if any files are missing headers:

```yaml
# GitHub Actions example
- name: Check license headers
  run: license Apache-2.0 "Your Name" --check
```

This returns exit code 1 if any files need updating.

### What files are excluded by default?

The tool automatically excludes common build artifacts and dependencies:
- Version control: `.git/`, `.svn/`, `.hg/`
- Dependencies: `node_modules/`, `vendor/`, `third_party/`
- Build outputs: `build/`, `dist/`, `target/`, `__pycache__/`
- Minified files: `*.min.js`, `*.min.css`
- Lock files: `*.lock`, `*.sum`, `go.mod`
- Config files: `*.json`, `*.toml`, `*.yaml`

### Can I use custom SPDX license identifiers?

Yes! Use any valid SPDX license identifier. Common examples:
- `MIT`
- `Apache-2.0`
- `GPL-3.0-or-later`
- `BSD-3-Clause`
- `ISC`

See [SPDX License List](https://spdx.org/licenses/) for all valid identifiers.

### Does it work with monorepos?

Yes! You can:
- Run it on the entire repo
- Use `--dir` to target specific packages
- Use different `.licenseignore` files in different directories
- Process specific files only

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

## License

This project is licensed under the [Apache License 2.0](./LICENSE).

See the [NOTICE](./NOTICE) file for additional information.