Metadata-Version: 2.4
Name: gh-action-pulse
Version: 1.1.0
Summary: Get Health/Propose modifications of each GitHub Action in a repository
Project-URL: repository, https://github.com/jylenhof/gh-action-pulse
Author-email: Jean-Yves LENHOF <jygithub@lenhof.eu.org>
License-File: LICENSE
Requires-Python: >=3.14
Requires-Dist: pygithub<3.0.0,>=2.9.0
Requires-Dist: pyyaml<7.0.0,>=6.0.2
Requires-Dist: rich<16.0.0,>=14.0.0
Requires-Dist: semver<4.0.0,>=3.0.4
Requires-Dist: typer<0.28.0,>=0.26.0
Description-Content-Type: text/markdown

# gh-action-pulse

`gh-action-pulse` scans a repository for GitHub Actions `uses:` references, checks them against the GitHub API, and rewrites them to safer or more current references when a better upstream target exists.

It is aimed at repositories that want to keep GitHub Actions dependencies understandable, current, and pinned with more confidence.

## Key Features

- **Automatic scanning**: Detects `uses:` statements across workflow and reusable action files.
- **Reference classification**: Distinguishes whether an action is currently pinned to a commit SHA, tag, or branch.
- **Recommendation engine**: Looks up upstream metadata and recommends an updated reference based on available SemVer tags and branch state.
- **Repository redirect handling**: Rewrites moved repositories to their canonical name when GitHub reports a redirect.
- **Freshness checks**: Warns or fails when the newest eligible SemVer tag is older than your configured threshold.
- **Node.js runtime check**: Recursively verifies that actions, including composite and local composite dependencies, run on at least a configurable minimum Node.js version (`--minimum-nodejs-version`, default `24`), failing with a dedicated exit code (`3`) when an outdated runtime is detected.

## How It Works

For each detected `uses:` line, `gh-action-pulse`:

1. Finds GitHub Actions references in the configured workflow and action directories.
2. Queries the GitHub API for the referenced repository.
3. Detects whether the current reference is a tag, branch, or SHA.
4. Selects the newest SemVer tag that is at least `--min-age` days old.
5. Falls back to a branch recommendation when that is safer or newer than the eligible tag.
6. Rewrites redirected repositories to their canonical upstream name.

In practice, this means the tool can:

- convert branch or tag references into pinned SHAs annotated with the matching tag,
- preserve branch intent when no suitable tag exists,
- surface stale upstream action releases with a non-zero exit code.

## Example

Before:

```yaml
- uses: google-github-actions/auth@v2
```

After:

```yaml
- uses: google-github-actions/auth@<commit-sha> # v2.1.10
```

If an action repository has moved, the repository name may also be rewritten to the canonical upstream location.

## Setup

`gh-action-pulse` talks to the GitHub API.

Set a token explicitly:

```bash
export GITHUB_TOKEN=your_github_token_here
```

If `GITHUB_TOKEN` is not set, the tool can fall back to using the GitHub CLI authentication flow when `gh` is available.

The project currently requires `Python >= 3.14`.

## Installation

### Install from PyPI with `uv`

```bash
uv tool install gh-action-pulse
```

### Install from PyPI with `pipx`

```bash
pipx install gh-action-pulse
```

### Install the local checkout

```bash
uv tool install . --force --reinstall
```

## CLI Usage

Run against the current repository:

```bash
gh-action-pulse
```

Preview changes without writing files:

```bash
gh-action-pulse --dry-run
```

Require action tags to be at least 14 days old before they can be selected:

```bash
gh-action-pulse --min-age 14
```

Fail when the newest eligible tag is older than 180 days:

```bash
gh-action-pulse --min-age 14 --max-age 180
```

Require actions to run on at least Node.js 20:

```bash
gh-action-pulse --minimum-nodejs-version 20
```

Show more detail while debugging:

```bash
gh-action-pulse --log-level DEBUG
```

Print the installed version:

```bash
gh-action-pulse --version
```

### Output

The CLI uses [Rich](https://github.com/Textualize/rich) for progress and summaries on stderr:

- a progress bar while enriching actions from the GitHub API (and while checking Node.js runtimes);
- colored phase lines for scan, freshness, and Node.js checks;
- a table of proposed or applied `uses:` rewrites (yellow header in `--dry-run`);
- a closing summary panel with update counts, warnings, and the exit code.

Routine per-file and per-action chatter is logged at `DEBUG`. Use `--log-level DEBUG` (or `WARNING` / `ERROR`) when you need diagnostic detail; warnings and errors still use Rich-formatted logging without repeating the main user-facing summary.

## CLI Options

- `--dry-run` (`GH_ACTION_PULSE_DRY_RUN`): show the updates without writing files.
- `--log-level` (`GH_ACTION_PULSE_LOG_LEVEL`): set the logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`).
- `--min-age` (`GH_ACTION_PULSE_MIN_AGE`): require tags to be at least this many days old before recommending them.
- `--max-age` (`GH_ACTION_PULSE_MAX_AGE`): fail when the chosen `--min-age`-eligible upstream tag is older than this many days. Use `0` to disable the check.
- `--minimum-nodejs-version` (`GH_ACTION_PULSE_MINIMUM_NODEJS_VERSION`): fail when an action, or any of its composite/local dependencies, runs on a Node.js major version below this value (default `24`). Use `0` to disable the check.
- `--version`: print the package version and exit.

CLI flags override the matching environment variables when both are set.

## Exit Codes

`gh-action-pulse` uses its exit code to signal the outcome of a run:

- `0`: the run completed and no failing condition was detected.
- `2`: GitHub authentication failed (`GITHUB_TOKEN` could not be resolved).
- `3`: a Node.js runtime problem was detected in the repository. When an action, or any of its composite/local composite dependencies, runs on a Node.js major version below `--minimum-nodejs-version` (default `24`), the tool logs an error and exits with status `3`. Set `--minimum-nodejs-version 0` to disable this check.
- `4`: a referenced upstream action repository is archived.
- `5`: a `--max-age` staleness failure occurred.

When multiple failing conditions are detected in the same run, the exit code with the lowest number is returned: authentication (`2`) and archived repositories (`4`) stop the run early, and among end-of-run checks the Node.js exit code (`3`) takes precedence over stale tags (`5`).

## Limitations

- Local actions such as `./.github/actions/my-action` are not part of the GitHub API lookup flow.
- Recommendations depend on repositories exposing usable SemVer tags.
- The tool needs GitHub API access, so rate limits and authentication still apply.

### Node.js version check (`--minimum-nodejs-version`)

The Node.js runtime check does not inspect every `uses:` line in the repository. In practice it:

- only starts from remote GitHub Actions referenced as `owner/repo@ref` (or `owner/repo/path@ref`) in `.github/workflows` and `.github/actions`;
- skips local actions such as `uses: ./.github/actions/my-action` because they do not match the `name@reference` pattern used during scanning;
- inspects the **recommended** upstream reference (the one the tool would update to), not the currently pinned reference when a recommendation exists;
- only flags JavaScript actions whose manifest declares `runs.using: nodeXX` (for example `node20`, `node24`);
- skips Docker actions (`docker://`), unresolvable references, missing manifests, and other non-`nodeXX` runtimes;
- walks composite actions recursively and checks nested `uses:` dependencies, including relative `./path` steps inside a **remote** composite action (resolved within that upstream repository);
- does not meaningfully check reusable workflows referenced as `uses: org/repo/.github/workflows/foo.yml@ref`, because it looks for `action.yml`/`action.yaml` manifests rather than workflow files.

Set `--minimum-nodejs-version 0` to disable this check entirely.

## Roadmap

Possible future improvements:

- Maybe Separate unit tests with appropriate workflow (pytest) if checks takes times
- Add E2E tests with appropriate workflow (pytest and/or bats)
- Change to versioned version of tools in mise.toml when near stable version (could depend on tools)

Potential future CLI options (to get the idea):

- `--config-file`: load configuration, including ignore parameters or specific rules for some workflows (needs thinking).
- `--only-workflow`: restrict scanning to a specific workflow.
- `--workflow-omit`: exclude specific workflows from scanning.
- `--github-action-omit`: exclude specific GitHub Actions from the checks.

## Contributing

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the code layout, local setup, and the full list of linters and checks run in CI.
