Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Org-wide lint check, required on every PR in every wethegit repo through an
# organization ruleset (managed in Terraform). As a required workflow it runs in
# the context of the PR's repository, so checkout and all paths below refer to
# that repo, not to wethegit/.github.
name: Org lint

on:
pull_request:
merge_group:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
ACTIONLINT_VERSION: 1.7.12
ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8

jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Detect what to lint
id: detect
shell: bash
run: |
set -euo pipefail
mode=skip pm= pnpm_version= node_version_file= node_version=

if [[ -f package.json ]]; then
# jq exits 1 for "no lint script" and >1 for invalid JSON, which should fail the check.
if jq -e '(.scripts.lint // "") | length > 0' package.json > /dev/null; then
mode=node
elif [[ $? -gt 1 ]]; then
echo "::error file=package.json::package.json is not valid JSON"
exit 1
fi
fi

if [[ $mode == skip ]] && compgen -G '.github/workflows/*.y*ml' > /dev/null; then
mode=actionlint
fi

if [[ $mode == node ]]; then
if [[ -f package-lock.json ]]; then
pm=npm
elif [[ -f pnpm-lock.yaml ]]; then
pm=pnpm
# pnpm/action-setup reads packageManager when present; otherwise pick a
# pnpm major that understands the lockfile format.
if ! jq -e '(.packageManager // "") | startswith("pnpm@")' package.json > /dev/null; then
case "$(sed -n "s/^lockfileVersion: *'\{0,1\}\([0-9]*\).*/\1/p" pnpm-lock.yaml)" in
5) pnpm_version=7 ;;
6) pnpm_version=8 ;;
9) pnpm_version=10 ;;
*) pnpm_version=latest ;;
esac
fi
elif [[ -f yarn.lock ]]; then
pm=yarn
else
pm=npm-no-lock
fi

if [[ -f .nvmrc ]]; then
node_version_file=.nvmrc
elif jq -e '(.engines.node // "") | length > 0' package.json > /dev/null; then
node_version_file=package.json
else
node_version=lts/*
fi
fi

{
echo "mode=$mode"
echo "pm=$pm"
echo "pnpm-version=$pnpm_version"
echo "node-version-file=$node_version_file"
echo "node-version=$node_version"
} >> "$GITHUB_OUTPUT"
echo "mode=$mode pm=$pm node=${node_version_file:-$node_version}"

# package.json "lint" script

- name: Set up pnpm
if: steps.detect.outputs.pm == 'pnpm'
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: ${{ steps.detect.outputs.pnpm-version }}

# Yarn 2+ is provided through Corepack; it must be on PATH before setup-node
# queries yarn for its cache directory.
- name: Enable Corepack
if: steps.detect.outputs.pm == 'yarn' && hashFiles('.yarnrc.yml') != ''
shell: bash
run: corepack enable

- name: Set up Node
if: steps.detect.outputs.mode == 'node'
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ steps.detect.outputs.node-version }}
node-version-file: ${{ steps.detect.outputs.node-version-file }}
cache: ${{ steps.detect.outputs.pm != 'npm-no-lock' && steps.detect.outputs.pm || '' }}

- name: Install dependencies
if: steps.detect.outputs.mode == 'node'
shell: bash
env:
PM: ${{ steps.detect.outputs.pm }}
run: |
set -euo pipefail
case "$PM" in
npm) npm ci ;;
npm-no-lock) npm install --no-audit --no-fund ;;
pnpm) pnpm install --frozen-lockfile ;;
yarn)
if [[ "$(yarn --version)" == 1.* ]]; then
yarn install --frozen-lockfile
else
yarn install --immutable
fi
;;
esac

- name: Run lint script
if: steps.detect.outputs.mode == 'node'
shell: bash
env:
PM: ${{ steps.detect.outputs.pm }}
run: |
set -euo pipefail
case "$PM" in
npm|npm-no-lock) npm run lint ;;
pnpm) pnpm run lint ;;
yarn) yarn run lint ;;
esac

# No lint script: lint workflow files

- name: Run actionlint
if: steps.detect.outputs.mode == 'actionlint'
shell: bash
run: |
set -euo pipefail
archive="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
curl -fsSL -o "$RUNNER_TEMP/$archive" \
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/$archive"
echo "$ACTIONLINT_SHA256 $RUNNER_TEMP/$archive" | sha256sum -c -
tar -xzf "$RUNNER_TEMP/$archive" -C "$RUNNER_TEMP" actionlint
# shellcheck is off so existing run: scripts across the org don't start failing.
"$RUNNER_TEMP/actionlint" -color -shellcheck=

# Nothing to lint

- name: Skip
if: steps.detect.outputs.mode == 'skip'
shell: bash
run: |
echo "::notice title=Org lint::No lint script found, skipped"
{
echo "### Org lint"
echo
echo "No lint script found, skipped."
echo
echo 'To opt in, add a `"lint"` script to `package.json`.'
} >> "$GITHUB_STEP_SUMMARY"
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# We the collective

We’re a fast-moving independent creative agency helping gaming, toys, sports, and entertainment brands build generational fandom.

## Org lint check

[`.github/workflows/lint.yml`](.github/workflows/lint.yml) runs as the **Org lint / lint** check on every pull request (and merge queue group) in every repo in the org. It's required by an organization ruleset, which is managed separately in Terraform. You don't need to copy the workflow into your repo, and you can't turn it off there.

What it runs depends on the repo:

1. **`package.json` has a `lint` script.** It sets up Node from `.nvmrc`, or from `engines.node` in `package.json`, and falls back to the current LTS. It installs dependencies with the package manager matching your lockfile (`package-lock.json` → npm, `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn), with caching, then runs `lint`.
2. **No lint script, but there are workflow files.** It runs [actionlint](https://github.com/rhysd/actionlint) on `.github/workflows`.
3. **Neither.** It passes and adds a "No lint script found, skipped" notice to the job summary.

To opt in, add a `lint` script to `package.json`, for example `"lint": "eslint ."`, and commit your lockfile. The check has a 10-minute timeout, and a new push to a PR cancels the run already in progress.
Loading