Homebrew/brew GitHub Actions scorecard

Public GitHub Actions data, last 30 days. Updated .

Data sourced from public GitHub. GitSpider is not affiliated with or endorsed by this repository's owners. Request removal.

136 min/mo
recoverable (~5% of CI time) · across 32 patterns · ≈$1/mo
Estimated from wall-clock time · public repos pay $0, $ = private-repo equivalent
See all 32 fixes, each with the exact YAML ↓
2.0%
failure rate, 30d
8m
avg time to recover from a failure
Since : findings 36 → 32 · recoverable ~128 → ~136 min/mo
36 workflows · 2,500 runs (83.3/day) · 2,581 CI-min (wall-clock) · ≈$15 at private-repo rates (30d)
CI minutes, cost and failure rate are from the latest 500 of 2,500 runs.

Where the minutes go (30d)

CI~838 min · 66 runs
Docker~736 min · 67 runs
Documentation~500 min · 66 runs
or track on every push →

Waste detected

Biggest wins first, each with the exact config fix.

No concurrency control · Docker

~74 min/mo

Add a `concurrency:` block keyed on branch to cancel superseded runs when devs push twice quickly.

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Full guide: how to fix this →

No concurrency control · Documentation

~50 min/mo

Add a `concurrency:` block keyed on branch to cancel superseded runs when devs push twice quickly.

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Full guide: how to fix this →

No concurrency control · CodeQL

~9 min/mo

Add a `concurrency:` block keyed on branch to cancel superseded runs when devs push twice quickly.

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Full guide: how to fix this →

No concurrency control · Licenses

~2 min/mo

Add a `concurrency:` block keyed on branch to cancel superseded runs when devs push twice quickly.

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Full guide: how to fix this →

No concurrency control · Commit Style

~1 min/mo

Add a `concurrency:` block keyed on branch to cancel superseded runs when devs push twice quickly.

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Full guide: how to fix this →

Also found: 27 more config fixes with negligible recoverable minutes: timeouts, retention, path filters

No path filters on triggers · CI

~0 min/mo

Runs on every push/PR with no `paths:` filter, so docs-only changes still trigger full CI. Add a `paths:` filter if that's common.

on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

Full guide: how to fix this →

Premium runners (macOS / Windows) · CI

~0 min/mo

macOS bills ~10x and Windows ~2x a Linux minute. The cost estimate above assumes Linux, so your real spend is higher. Move any job that doesn't need them to `ubuntu-latest`.

jobs:
  build:
    runs-on: ubuntu-latest  # ~10x cheaper than macos-latest

Full guide: how to fix this →

No job timeout · Docker

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Artifacts at default retention · Docker

~0 min/mo

`upload-artifact` has no `retention-days`, so artifacts keep up to 90 days (storage cost). Set e.g. `retention-days: 7`.

- uses: actions/upload-artifact@v4
  with:
    name: build
    path: dist/
    retention-days: 7

Full guide: how to fix this →

No path filters on triggers · Docker

~0 min/mo

Runs on every push/PR with no `paths:` filter, so docs-only changes still trigger full CI. Add a `paths:` filter if that's common.

on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

Full guide: how to fix this →

No job timeout · Update SPDX license data

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Scheduled at the top of the hour · Update SPDX license data

~0 min/mo

The schedule fires at minute :00, GitHub's peak window, where scheduled runs get delayed or skipped. Shift to any other minute for the same cadence with less contention.

on:
  schedule:
    - cron: '10 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

Full guide: how to fix this →

No job timeout · Update Sorbet files

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Premium runners (macOS / Windows) · Update Sorbet files

~0 min/mo

macOS bills ~10x and Windows ~2x a Linux minute. The cost estimate above assumes Linux, so your real spend is higher. Move any job that doesn't need them to `ubuntu-latest`.

jobs:
  build:
    runs-on: ubuntu-latest  # ~10x cheaper than macos-latest

Full guide: how to fix this →

Scheduled at the top of the hour · Update Sorbet files

~0 min/mo

The schedule fires at minute :00, GitHub's peak window, where scheduled runs get delayed or skipped. Shift to any other minute for the same cadence with less contention.

on:
  schedule:
    - cron: '13 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

Full guide: how to fix this →

No job timeout · CodeQL

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

No path filters on triggers · CodeQL

~0 min/mo

Runs on every push/PR with no `paths:` filter, so docs-only changes still trigger full CI. Add a `paths:` filter if that's common.

on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

Full guide: how to fix this →

No job timeout · Update sponsors, maintainers, manpage and completions

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Scheduled at the top of the hour · Update sponsors, maintainers, manpage and completions

~0 min/mo

The schedule fires at minute :00, GitHub's peak window, where scheduled runs get delayed or skipped. Shift to any other minute for the same cadence with less contention.

on:
  schedule:
    - cron: '47 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

Full guide: how to fix this →

No path filters on triggers · Documentation

~0 min/mo

Runs on every push/PR with no `paths:` filter, so docs-only changes still trigger full CI. Add a `paths:` filter if that's common.

on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

Full guide: how to fix this →

No job timeout · Autogenerated files check

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

No job timeout · Actionlint

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Artifacts at default retention · Actionlint

~0 min/mo

`upload-artifact` has no `retention-days`, so artifacts keep up to 90 days (storage cost). Set e.g. `retention-days: 7`.

- uses: actions/upload-artifact@v4
  with:
    name: build
    path: dist/
    retention-days: 7

Full guide: how to fix this →

No path filters on triggers · Actionlint

~0 min/mo

Runs on every push/PR with no `paths:` filter, so docs-only changes still trigger full CI. Add a `paths:` filter if that's common.

on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

Full guide: how to fix this →

System packages reinstalled every run · Actionlint

~0 min/mo

System packages install from the network on every run with no cache. Cache them (cache-apt-pkgs-action) or check whether the runner image already has the tool.

- uses: awalsh128/cache-apt-pkgs-action@latest
  with:
    packages: <your packages>
    version: 1.0

Full guide: how to fix this →

No job timeout · Update SBOM schema

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Scheduled at the top of the hour · Update SBOM schema

~0 min/mo

The schedule fires at minute :00, GitHub's peak window, where scheduled runs get delayed or skipped. Shift to any other minute for the same cadence with less contention.

on:
  schedule:
    - cron: '55 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

Full guide: how to fix this →

No job timeout · Check pull requests

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

No job timeout · Manage stale issues and pull requests

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

Scheduled at the top of the hour · Manage stale issues and pull requests

~0 min/mo

The schedule fires at minute :00, GitHub's peak window, where scheduled runs get delayed or skipped. Shift to any other minute for the same cadence with less contention.

on:
  schedule:
    - cron: '54 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

Full guide: how to fix this →

No job timeout · Commit Style

~0 min/mo

No job sets `timeout-minutes`, so a hung step can run to GitHub's 6-hour default. Add `timeout-minutes` to each job.

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Full guide: how to fix this →

No path filters on triggers · Commit Style

~0 min/mo

Runs on every push/PR with no `paths:` filter, so docs-only changes still trigger full CI. Add a `paths:` filter if that's common.

on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

Full guide: how to fix this →

Copy every fix as one block (11 snippets, annotated per workflow)
# No concurrency control (applies to: Docker, Documentation, CodeQL, Licenses, Commit Style)
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

# No path filters on triggers (applies to: CI, Docker, CodeQL, Documentation, Actionlint, Commit Style)
on:
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'

# Premium runners (macOS / Windows) (applies to: CI, Update Sorbet files)
jobs:
  build:
    runs-on: ubuntu-latest  # ~10x cheaper than macos-latest

# No job timeout (applies to: Docker, Update SPDX license data, Update Sorbet files, CodeQL, Update sponsors, maintainers, manpage and completions, Autogenerated files check, Actionlint, Update SBOM schema, Check pull requests, Manage stale issues and pull requests, Commit Style)
jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

# Artifacts at default retention (applies to: Docker, Actionlint)
- uses: actions/upload-artifact@v4
  with:
    name: build
    path: dist/
    retention-days: 7

# Scheduled at the top of the hour (applies to: Update SPDX license data)
on:
  schedule:
    - cron: '10 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

# Scheduled at the top of the hour (applies to: Update Sorbet files)
on:
  schedule:
    - cron: '13 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

# Scheduled at the top of the hour (applies to: Update sponsors, maintainers, manpage and completions)
on:
  schedule:
    - cron: '47 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

# System packages reinstalled every run (applies to: Actionlint)
- uses: awalsh128/cache-apt-pkgs-action@latest
  with:
    packages: <your packages>
    version: 1.0

# Scheduled at the top of the hour (applies to: Update SBOM schema)
on:
  schedule:
    - cron: '55 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

# Scheduled at the top of the hour (applies to: Manage stale issues and pull requests)
on:
  schedule:
    - cron: '54 0 * * *'  # was '0 0 * * *' — any non-:00 minute avoids the herd

Each snippet is representative. Merge into the named workflow files rather than pasting wholesale.

Add the badge to your README

Live CI-health badge → GitSpider badge

[![GitSpider](https://gitspider.com/badge/Homebrew/brew.svg)](https://gitspider.com/scan/Homebrew/brew)

Want this on every push?

This scorecard is a one-time snapshot. Install the free GitHub App to track this repo continuously: new regressions caught as they land, trends over time, on your public and private repos. Team adds the offending commit on the PR + Slack alerts.

Install & monitor this repo →

💬 On Team, every PR gets an automatic comment when its CI run fails or runs slow, right where your team already looks. See plans →

Not ready to install? Get this report by email. No spam, unsubscribe anytime.

Share this scorecard: https://gitspider.com/scan/Homebrew/brew