ghaperf

module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2025 License: MIT

README

ghaperf

ghaperf analyzes the performance of GitHub Actions workflows using GitHub API and raw job logs. Unlike other tools, it can detect bottlenecks inside composite actions by parsing job logs and extracting step-level timing data.

Why ghaperf?

Existing tools rely on the Workflow Jobs API, which doesn't include step-level data from composite actions. ghaperf solves this by:

  • Retrieving and parsing raw job logs via the API
  • Extracting timing data from all log groups, including steps within composite actions

Quick Start

  1. Install ghaperf
  2. Set your GitHub Access token to download action logs
  3. Run ghaperf
export GITHUB_TOKEN=xxx

# Analyze a workflow across multiple runs
ghaperf --repo aquaproj/aqua-registry --workflow test.yaml --count 10 --threshold 2s
Example Report
Example Report Output

This report was generated by ghaperf.

ghaperf versionv0.1.0
Created At2025-11-02T20:38:03+09:00
Threshold2s
Repositoryaquaproj/aqua-registry
The Number of Workflow Runs10
Workflow Nametest.yaml

Job: test / test / test (macos-13)

Average Job Duration1m15s (11m11s/9)
Slowest Jobs8m25s, 24s, 23s
Slow steps
  1. 1m4s (8m31s/8): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 1m36s (7m58s/5): Run aqua i --test
    2. 16s (16s/1): Run rustup update
  2. 6s (48s/8): Set up job
    1. 6s (49s/8): GITHUB_TOKEN Permissions
  3. 4s (30s/8): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
  4. 4s (29s/8): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 3s (21s/8): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then

Job: test / test / test (windows-latest, arm64)

Average Job Duration1m6s (10m59s/10)
Slowest Jobs6m19s, 41s, 39s
Slow steps
  1. 36s (5m57s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 5m4s (5m4s/1): Run aqua i --test
    2. 18s (18s/1): Run rustup update
    3. 2s (17s/8): Run aqua exec -- ci-info run | sed -E "s/^export //" >> "$GITHUB_ENV"
  2. 13s (2m10s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 11s (1m25s/8): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    2. 4s (36s/8): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then
  3. 8s (1m23s/10): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 2s (23s/10): Setting up auth
  4. 4s (38s/10): Set up job
    1. 4s (37s/10): GITHUB_TOKEN Permissions
  5. 2s (23s/10): Post Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 3s (18s/7): Run aqua i --test
    2. 6s (6s/1): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    3. 5s (5s/1): Checking out the ref

Job: test / test / test (windows-latest)

Average Job Duration1m4s (10m36s/10)
Slowest Jobs6m0s, 37s, 36s
Slow steps
  1. 34s (5m43s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 4m44s (4m44s/1): Run aqua i --test
    2. 20s (20s/1): Run rustup update
    3. 2s (17s/8): Run aqua exec -- ci-info run | sed -E "s/^export //" >> "$GITHUB_ENV"
    4. 2s (13s/6): Run if grep '- import:' aqua/test.yaml | sed 's| - import: ../(.*)/pkg.yaml|\1/registry.yaml|' | xargs cat | grep "type: cargo" > /dev/null 2>&1; then
  2. 13s (2m9s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 10s (1m22s/8): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    2. 5s (40s/8): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then
  3. 7s (1m12s/10): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 2s (22s/10): Setting up auth
  4. 4s (39s/10): Set up job
    1. 4s (39s/10): GITHUB_TOKEN Permissions
  5. 2s (23s/10): Post Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 3s (18s/7): Run aqua i --test
    2. 5s (5s/1): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    3. 5s (5s/1): Checking out the ref

Job: test / test / test (macos-14)

Average Job Duration34s (5m40s/10)
Slowest Jobs2m52s, 26s, 21s
Slow steps
  1. 19s (3m7s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 39s (2m37s/4): Run aqua i --test
    2. 10s (10s/1): Run rustup update
  2. 6s (55s/10): Set up job
    1. 5s (55s/10): GITHUB_TOKEN Permissions
  3. 3s (30s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 2s (24s/10): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then
  4. 2s (21s/10): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

Job: test / test / test (ubuntu-24.04)

Average Job Duration28s (4m42s/10)
Slowest Jobs2m46s, 18s, 15s
Slow steps
  1. 19s (3m5s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 32s (2m40s/5): Run aqua i --test
    2. 9s (9s/1): Run rustup update
  2. 3s (31s/10): Set up job
    1. 3s (32s/10): GITHUB_TOKEN Permissions

Job: test / test / test (ubuntu-24.04-arm)

Average Job Duration27s (4m32s/10)
Slowest Jobs2m30s, 16s, 16s
Slow steps
  1. 16s (2m43s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 22s (2m13s/6): Run aqua i --test
    2. 7s (7s/1): Run rustup update
  2. 3s (31s/10): Set up job
    1. 3s (31s/10): GITHUB_TOKEN Permissions
  3. 2s (24s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342

Job: test / lintnet / lintnet

Average Job Duration15s (2m34s/10)
Slowest Jobs19s, 18s, 18s
Slow steps
  1. 6s (59s/10): Run lintnet lint
    1. 8s (1m5s/8): Run lintnet lint
  2. 3s (30s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
  3. 2s (22s/10): Post Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

Job: test / ci-info / ci-info

Average Job Duration9s (1m33s/10)
Slowest Jobs12s, 12s, 10s
Slow steps
  1. 2s (22s/10): Run suzuki-shunsuke/ci-info-action/store@ceeb10dd50cd632db31e7eccf92cbbb6856f3191

Job: test / check-files / check-files

Average Job Duration5s (54s/10)
Slowest Jobs7s, 6s, 6s

The job has no slow steps

Job: test / path-filter

Average Job Duration4s (40s/10)
Slowest Jobs6s, 5s, 5s

The job has no slow steps

Job: status-check

Average Job Duration4s (7s/2)
Slowest Jobs4s, 3s, 0s

The job has no slow steps

Key Features

  • Deep visibility into composite actions - Detect bottlenecks inside composite actions that other tools miss
  • Multiple analysis modes - Analyze workflows, workflow runs, or individual jobs
  • Markdown reports - Generate shareable performance reports
  • No infrastructure needed - Just a CLI tool, no backend or metrics storage required
  • Intelligent caching - Cache GitHub API responses for completed runs to speed up analysis
  • Flexible filtering - Filter and normalize job names using configuration files

Installation

See INSTALL.md for detailed installation instructions.

Usage

For complete usage documentation, see USAGE.md.

Prerequisites

A GitHub access token is required to download action logs. See GitHub Access Token for details.

export GITHUB_TOKEN=xxx
Analysis Modes

1. Analyze multiple workflow runs (recommended for performance insights)

ghaperf \
  --repo suzuki-shunsuke/ghaperf \
  --workflow test.yaml \
  --count 10 \
  --threshold 2s

[!NOTE] Higher --count values provide better insights but take longer to process.

2. Analyze a single workflow run

ghaperf \
  --repo "suzuki-shunsuke/tfaction" \
  --run-id "<workflow run id>"

3. Analyze a specific job

ghaperf \
  --repo suzuki-shunsuke/tfaction \
  --job-id "<workflow job id>"

4. Analyze a local log file

ghaperf --log-file path/to/job.log

See the example log file for format reference.

Configuration

Environment Variables
Variable Description Default
GHAPERF_LOG_LEVEL Log level: debug, info, warn, error info
GHAPERF_GITHUB_TOKEN GitHub access token -
GITHUB_TOKEN GitHub access token (alternative) -
GHAPERF_GHTKN Enable ghtkn integration false
GHAPERF_THRESHOLD Default threshold for slow steps/log groups 30s
GitHub Access Token

A GitHub access token is required to fetch workflow runs, jobs, and logs via the GitHub API.

[!WARNING] Even if repositories are public, an access token is required. This is a known issue of GitHub. https://github.com/orgs/community/discussions/24742

{
  "message": "Must have admin rights to Repository.",
  "documentation_url": "https://docs.github.com/rest/actions/workflow-jobs#download-job-logs-for-a-workflow-run",
  "status": "403"
}

The message says Must have admin rights to Repository., but actually we confirmed the message is wrong because non admin user can download logs.

Required Permissions:

  • Public repositories
  • Private repositories: Actions: Read permission

Setup:

# Option 1: Use GITHUB_TOKEN
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx

# Option 2: Use GHAPERF_GITHUB_TOKEN
export GHAPERF_GITHUB_TOKEN=ghp_xxxxxxxxxxxxx

# Option 3: Use ghtkn integration
export GHAPERF_GHTKN=true
Threshold

ghaperf reports steps and log groups that exceed the specified threshold:

Threshold Configuration:

  • Default: 30s
  • Set via --threshold flag or GHAPERF_THRESHOLD environment variable
  • Format: Go duration (e.g., 1s, 2m30s)
Configuration File

Use configuration files to filter jobs by job name and normalize job names. All settings are optional.

Scaffold the configuration file:

ghaperf --init # Generate ghaperf.yaml

Pass the configuration file:

ghperf --config <configuration file path> ...

e.g.

# Only analyze jobs matching these regular expressions
job_names:
  - "test / test / test .*"

# Exclude jobs matching these regular expressions
# excluded_job_names:
#   - "test / test / test .*"

# Normalize matrix job names for aggregation
job_name_mappings:
  "test / test / test .*": "test / test / test"

Available Fields:

  • job_names: List of regular expressions - only matching jobs are analyzed
  • excluded_job_names: List of regular expressions - matching jobs are excluded
  • job_name_mappings: Map of regular expressions to normalized names for matrix jobs and old job names

JSON Schema and Validation:

The configuration schema is available at json-schema/ghaperf.json.

Validate your configuration with ajv-cli:

ajv --spec=draft2020 -s json-schema/ghaperf.json -d ghaperf.yaml

IDE Support:

Enable auto-completion in your editor by adding this to your config file:

Latest version:

# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/ghaperf/main/json-schema/ghaperf.json

Or pin to a specific version:

# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/ghaperf/v0.0.3/json-schema/ghaperf.json

Advanced Topics

Caching

ghaperf automatically caches API responses for completed workflow runs and jobs to improve performance on subsequent analyses.

Cache location: ${XDG_CACHE_HOME:-${HOME}/.cache}/ghaperf/

This speeds up repeated analyses and reduces API calls.

Important Notes

  1. Log availability timing: Job logs must be fully processed by GitHub. If a job just completed, the API may not have logs ready yet. Wait a few moments and retry.

  2. Log format changes: GitHub's log format is not officially documented. ghaperf parses logs based on observed patterns, which may break if GitHub changes the format unexpectedly.

  3. Log retention: GitHub retains workflow logs for 90 days by default. Analysis of older runs may fail if logs have been deleted.

While these tools are excellent for analyzing GitHub Actions performance, they don't provide step-level visibility into composite actions like ghaperf does. We don't aim to replace these tools with ghaperf. For this reason, it is not our intention to re-implement features already present in other tools, such as CIAnalyzer, in ghaperf. Rather, ghaperf preserves features that other tools are missing. Tools like CIAnalyzer are more suitable if you want to know how performance changes over the medium to long term. On the other hand, ghaperf is more suitable if you want to investigate current performance bottlenecks in more detail.

Directories

Path Synopsis
cmd
gen-jsonschema command
ghaperf command
pkg
cli
log
xdg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL