Skip to content

Latest commit

Β 

History

111 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

gh-slimify

Go Version License GitHub CLI

Warning

Migrating to ubuntu-slim may cause workflow instability or increased execution time.

gh-slimify scan output

Tip

πŸ’‘ Wait, couldn't you just copy-paste the following prompt into AI agent and skip using this tool altogether? πŸ€”

Goal: For every workflow file under `.github/workflows`, migrate jobs that currently run on `ubuntu-latest` to the container-based runner `ubuntu-slim`. Use the following decision rules in order when judging whether to migrate a job:

1. Only consider jobs (including matrix entries) whose `runs-on` is `ubuntu-latest` or `ubuntu-24.04`.
2. Skip any job that uses service containers (`jobs.<job_id>.services`).
3. Skip any job already running inside a container (`jobs.<job_id>.container`).
4. Skip any job whose setup steps provision an environment that assumes a non-container host.
5. Skip any job whose run scripts rely on host-only commands or elevated system privileges that containers cannot provide (e.g., `mount`, `iptables`, `modprobe`, `sysctl`, `nsenter`, `systemctl`, `systemd`, etc.).
6. Skip any job whose execution time exceeds 15 minutes. Use the GitHub CLI to check the duration of the most recent successful run. Example commands:

   ```bash
   # Get the database ID of the latest successful run
   id=$(gh run list \
     --repo ${owner}/${repo} \
     --workflow ${workflow_file_name} \
     --status success \
     --limit 1 \
     --json databaseId | jq .'[0].databaseId')

   # List jobs from that run to inspect start/completion times
   gh api \
     repos/{owner}/{repo}/actions/runs/${id}/jobs | jq '.jobs[] | {name: .name, started_at: .started_at, completed_at: .completed_at}'

Based on these rules, review each workflow and migrate every eligible job to ubuntu-slim. Afterward, report both the jobs that were successfully migrated and, for those that were not, the specific reasons they were ineligible.

🎯 Motivation

GitHub Actions recently introduced the lightweight ubuntu-slim runner (1 vCPU / 5 GB RAM, max 15 min runtime) as a cost-efficient alternative to ubuntu-latest. However, manually identifying which workflows can safely migrate is tedious and error-prone:

  • ❌ Jobs using Docker commands or containers cannot migrate
  • ❌ Jobs using services: containers are incompatible
  • ❌ Jobs exceeding 15 minutes will fail
  • ❌ Container-based GitHub Actions are not supported
  • ❌ Jobs using privileged operations (e.g., mount, iptables, modprobe) are incompatible

gh-slimify automates this entire process, analyzing your workflows and safely migrating eligible jobs with a single command.

πŸ“¦ Installation

Install as a GitHub CLI extension:

gh extension install fchimpan/gh-slimify

Note

The built-in list of tools pre-installed on ubuntu-slim is a snapshot of the runner image and may drift as GitHub updates it weekly. See the official ubuntu-slim installed software list for the current state, and always verify manually before migrating critical workflows.

πŸš€ Quick Start

Important

All commands must be executed from the repository root directory (where .github/workflows/ is located).

Get help:

$ gh slimify --help

Scan Workflows

Scan specific workflow file(s) to find migration candidates:

gh slimify .github/workflows/ci.yml

Or scan multiple workflow files:

gh slimify .github/workflows/ci.yml .github/workflows/test.yml

To scan all workflows in .github/workflows/, use the --all flag:

gh slimify --all

Example Output:

πŸ“„ .github/workflows/lint.yml
  βœ… Safe to migrate (1 job(s)):
     β€’ "lint" (L8) - Last execution time: 4m
       .github/workflows/lint.yml:8
  ⚠️  Can migrate but requires attention (1 job(s)):
     β€’ "build" (L15)
       ⚠️  Setup may be required (go), Last execution time: unknown
       .github/workflows/lint.yml:15
  ❌ Cannot migrate (2 job(s)):
     β€’ "docker-build" (L25)
       ❌ uses Docker commands
       .github/workflows/lint.yml:25
     β€’ "test-with-db" (L35)
       ❌ uses service containers
       .github/workflows/lint.yml:35

βœ… 1 job(s) can be safely migrated
⚠️  1 job(s) can be migrated but require attention
❌ 2 job(s) cannot be migrated
πŸ“Š Total: 2 job(s) eligible for migration

The output shows:

  • βœ… Safe to migrate: Jobs with no missing commands and known execution time
  • ⚠️ Can migrate but requires attention: Jobs with missing commands or unknown execution time
  • ❌ Cannot migrate: Jobs that cannot be migrated with specific reasons (e.g., uses Docker commands, uses service containers, uses container syntax, does not run on ubuntu-latest)
  • Warning reasons: Displayed in a single line for easy understanding
  • Relative file paths: Clickable links that work in VS Code, iTerm2, and other terminal emulators

Auto-Fix Workflows

Automatically update eligible jobs to use ubuntu-slim. By default, only safe jobs (no missing commands and known execution time) are updated.

Specify workflow file(s):

gh slimify fix .github/workflows/ci.yml

Or use --all to fix all workflows:

gh slimify fix --all

Example Output (default - safe jobs only):

Updating workflows to use ubuntu-slim (safe jobs only)...
Skipping 1 job(s) with warnings. Use --force to update them.

Updating .github/workflows/lint.yml
  βœ“ Updated job "lint" (L8) β†’ ubuntu-slim

Successfully updated 1 job(s) to use ubuntu-slim.

To also update jobs with warnings (missing commands or unknown execution time), use the --force flag:

gh slimify fix --force

Example Output (with --force):

Updating workflows to use ubuntu-slim (including jobs with warnings)...

Updating .github/workflows/lint.yml
  ⚠️  Updated job "build" (L15) β†’ ubuntu-slim (with warnings)
  βœ“ Updated job "lint" (L8) β†’ ubuntu-slim

Successfully updated 2 job(s) to use ubuntu-slim.

πŸ“– Usage

Scan All Workflows

To scan all workflows in .github/workflows/, use the --all flag:

gh slimify --all

Using --file Flag

You can also use the --file (or -f) flag to specify workflow files:

gh slimify -f .github/workflows/ci.yml -f .github/workflows/test.yml

Skip Duration Check

Skip fetching job durations from GitHub API. This is useful for:

  • API rate limit management: Avoid hitting GitHub API rate limits when scanning many workflows
  • Faster scans: Skip API calls for quicker results
  • When API access is unavailable: Use when GitHub API is not accessible
gh slimify --skip-duration

Offline Mode

Skip all GitHub API access β€” job durations and remote action metadata. Docker-action detection falls back to offline heuristics (docker/ prefix, docker:// images, local action.yml files); execution times are reported as unknown.

gh slimify --offline --all

Use the --verbose flag to enable debug output, which can help troubleshoot issues with API calls or workflow parsing:

gh slimify --verbose

Force Update Jobs with Warnings

Update jobs with warnings (missing commands or unknown execution time):

gh slimify fix --force

JSON Output

Use --json to output results in machine-readable JSON format. This is useful for CI/CD pipelines, AI agents, or other tools that need to parse the results programmatically.

gh slimify --json --all
gh slimify fix --json --all

Example scan output:

{
  "jobs": [
    {
      "workflow_path": ".github/workflows/ci.yml",
      "job_id": "lint",
      "job_name": "Lint",
      "line_number": 8,
      "status": "safe",
      "status_description": "Safe to migrate to ubuntu-slim. No missing commands and execution time is known.",
      "recommended_action": "migrate",
      "duration_seconds": 143
    },
    {
      "workflow_path": ".github/workflows/ci.yml",
      "job_id": "build",
      "job_name": "Build",
      "line_number": 25,
      "status": "warning",
      "status_description": "Can migrate but requires attention. Setup may be required for: docker.",
      "recommended_action": "review_before_migrate",
      "duration_seconds": 230,
      "missing_commands": ["docker"]
    }
  ],
  "summary": {
    "safe": 1,
    "warning": 1,
    "ineligible": 0,
    "already_slim": 0,
    "total": 2
  }
}

Scan job statuses:

Status Recommended Action Description
safe migrate Safe to migrate, no issues found
warning review_before_migrate Can migrate but has missing commands or unknown duration
ineligible do_not_migrate Cannot migrate to ubuntu-slim
already_slim no_action_needed Already using ubuntu-slim

Fix job statuses:

Status Recommended Action Description
updated verify_workflow Successfully updated to ubuntu-slim
updated (with warnings) verify_workflow_carefully Updated but requires careful verification
skipped review_then_force Skipped due to warnings, use --force to update
error investigate_error Failed to update
not_found investigate_error Job not found in workflow file

Combine Options

gh slimify fix .github/workflows/ci.yml --skip-duration --force
gh slimify --all --skip-duration
gh slimify fix --all --force
gh slimify --json --all --skip-duration

πŸ” Migration Criteria

A job is eligible for migration to ubuntu-slim if all of the following conditions are met:

  1. βœ… Runs on ubuntu-latest or ubuntu-24.04 with a single label (multi-label runs-on arrays target self-hosted runners and are skipped; reusable workflow calls and expression-based runs-on such as ${{ matrix.os }} are reported with their own reasons)
  2. βœ… Does not invoke container tooling β€” docker with any subcommand (build, buildx, run, load, save, ...), docker-compose, podman, nerdctl, buildah β€” including invocations passed to bash -c, eval, or heredocs. Run scripts are parsed as shell, so command names inside comments or string arguments do not cause false positives.
  3. βœ… Does not use Docker-based GitHub Actions. The docker/ organization and docker:// images are detected offline; for other publishers the tool fetches each action's metadata (runs.using: docker) from the GitHub API β€” catching Dockerfile-based actions like super-linter/super-linter or hadolint/hadolint-action β€” and follows nested composite actions. Local actions (uses: ./path) are read from disk. If metadata cannot be fetched (offline, rate limit), detection falls back to the prefix heuristics.
  4. βœ… Does not use services: containers (PostgreSQL, Redis, MySQL, etc.)
  5. βœ… Does not use container: syntax (jobs running inside Docker containers)
  6. βœ… Does not invoke privileged operations (mount, iptables, modprobe, sysctl, nsenter, etc.)
  7. βœ… Latest successful run duration is under 15 minutes (checked via GitHub API). Jobs over the limit are reported as cannot migrate; jobs over 10 minutes are flagged with a warning because ubuntu-slim's single vCPU is often slower than ubuntu-latest.
  8. ⚠️ Jobs using commands that exist in ubuntu-latest but not in ubuntu-slim will be flagged with warnings but are still eligible for migration. You may need to add setup steps to install these tools in ubuntu-slim.

Note

Setup Action Detection: If a job uses popular setup actions from GitHub Marketplace (e.g., actions/setup-go,hashicorp/setup-terraform), the commands provided by those actions (e.g., go, terraform) will not be flagged as missing. This is because these setup actions install the necessary tools, making the job safe to migrate. The tool recognizes setup actions from GitHub Marketplace's verified creators, including official GitHub actions and popular third-party actions.

If any condition is violated, the job will not be migrated.

Job Status Classification

Jobs are classified into three categories:

  • βœ… Safe to migrate: No missing commands, execution time is known and comfortably under the limit
  • ⚠️ Can migrate but requires attention: Has missing commands, execution time is unknown, or the last run exceeded 10 minutes (close to the 15-minute limit on a slower 1 vCPU runner)
  • ❌ Cannot migrate: Does not meet migration criteria (e.g., uses Docker commands, uses service containers, uses container syntax, does not run on ubuntu-latest, last execution time exceeds the 15-minute limit)

Missing commands are tools that exist in ubuntu-latest but need to be installed in ubuntu-slim (e.g., nvm). These jobs can still be migrated, but you may need to add setup steps to install the required tools.

When a job cannot be migrated, the specific reason(s) are displayed, such as:

  • "does not run on ubuntu-latest or ubuntu-24.04"
  • "calls a reusable workflow (its runner is defined in the called workflow)"
  • "runs-on is set by an expression (e.g. matrix) and was not analyzed"
  • "uses multiple runner labels (self-hosted runner)"
  • "uses Docker commands"
  • "uses container-based GitHub Actions"
  • "uses Docker container action(s) (hadolint/hadolint-action@v3.1.0)"
  • "uses service containers"
  • "uses container syntax"
  • "uses privileged operations (mount, iptables, ...)"
  • "last execution time (23m) exceeds ubuntu-slim's 15-minute limit"

πŸ“ Examples

Example 1: Simple Lint Job βœ…

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm run lint

Example 2: Docker Build Job ❌

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true

Result: ❌ Not eligible β€” Uses Docker-based action

Example 3: Job with Services ❌

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:14
    steps:
      - run: npm test

Result: ❌ Not eligible β€” Uses services: containers

Example 4: Container Job ❌

jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: node:18
    steps:
      - run: node --version

Result: ❌ Not eligible β€” Uses container: syntax

Example 5: Job with Privileged Operations ❌

jobs:
  network-test:
    runs-on: ubuntu-latest
    steps:
      - run: |
          sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
          sudo sysctl -w net.ipv4.ip_forward=1

Result: ❌ Not eligible β€” Uses privileged operations (iptables, sysctl)

πŸ› οΈ How It Works

  1. Parse Workflows: Scans .github/workflows/*.yml files and parses job definitions
  2. Check Criteria: Evaluates each job against migration criteria (Docker, services, containers)
  3. Detect Missing Commands: Identifies commands used in jobs that exist in ubuntu-latest but not in ubuntu-slim
  4. Fetch Durations: Retrieves latest job execution times from GitHub API (unless --skip-duration is used)
  5. Classify Jobs: Separates jobs into "safe" (no warnings), "requires attention" (has warnings), and "cannot migrate" (does not meet criteria) categories
  6. Report Results: Displays eligible jobs grouped by status with:
    • Visual indicators (βœ… for safe, ⚠️ for warnings, ❌ for ineligible)
    • Ineligibility reasons for jobs that cannot be migrated
    • Warning reasons in a single line
    • Relative file paths with line numbers (clickable in most terminals)
    • Execution durations
    • Machine-readable JSON output (--json) with status descriptions and recommended actions for AI agents and automation
  7. Auto-Fix (optional): Updates runs-on: ubuntu-latest to runs-on: ubuntu-slim:
    • By default: Only safe jobs are updated
    • With --force: All eligible jobs (including those with warnings) are updated

πŸ“„ License

MIT License

About

πŸš€ Automatically detect and migrate GitHub Actions workflows to `ubuntu-slim` for cost-efficient CI

Topics

Resources

Stars

109 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages