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
20 changes: 11 additions & 9 deletions .github/workflows/actionlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ on:
paths:
- ".github/workflows/**"
- "action.yml"
- "action.yaml"
- "**/action.yml"
- "**/action.yaml"
push:
branches: [main]
paths:
- ".github/workflows/**"
- "action.yml"
- "action.yaml"
- "**/action.yml"
- "**/action.yaml"
workflow_dispatch:
workflow_call:

Expand All @@ -26,16 +30,14 @@ jobs:
actionlint:
name: actionlint
runs-on: ubuntu-latest
permissions:
contents: read
checks: write # github-check reporter
pull-requests: write # github-pr-review reporter
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Run actionlint
uses: reviewdog/action-actionlint@a7d35aaf8c309203a4ae861d32b7bd490baa7bf3 # v1.83.0
with:
reporter: ${{ github.event_name == 'pull_request' && 'github-pr-review' || 'github-check' }}
filter_mode: ${{ github.event_name == 'pull_request' && 'file' || 'nofilter' }}
fail_level: error
shell: bash
env:
ACTIONLINT_IMAGE: rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667
run: |
docker run --rm -v "$PWD:/repo" -w /repo "$ACTIONLINT_IMAGE" \
-format '{{range $err := .}}::error file={{$err.Filepath}},line={{$err.Line}},col={{$err.Column}}::{{$err.Message}}\n{{end}}'
9 changes: 8 additions & 1 deletion .github/workflows/check-refs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ on:
pull_request:
paths:
- ".github/workflows/*.yml"
- ".github/workflows/*.yaml"
- "action.yml"
- "action.yaml"
- "**/action.yml"
- "**/action.yaml"
push:
branches: [main]
paths:
- ".github/workflows/*.yml"
- ".github/workflows/*.yaml"
- "action.yml"
- "action.yaml"
- "**/action.yml"
- "**/action.yaml"
workflow_dispatch:
workflow_call:

Expand All @@ -26,6 +32,7 @@ jobs:
check-refs:
name: dotactions references
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

Expand All @@ -36,7 +43,7 @@ jobs:
path='(/[A-Za-z0-9_./-]+)?'
self="${GITHUB_REPOSITORY//./\\.}${path}"
org="${GITHUB_REPOSITORY_OWNER//./\\.}/[A-Za-z0-9_.-]+${path}"
files=('.github/workflows/*.yml' 'action.yml' '*/action.yml')
files=('.github/workflows/*.yml' '.github/workflows/*.yaml' 'action.yml' 'action.yaml' '*/action.yml' '*/action.yaml')
failed=0

# Self-references stay @main on main; the release workflow rewrites them to the release tag.
Expand Down
25 changes: 14 additions & 11 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,37 @@ jobs:
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: true # tests source .tooling/tests/lib.sh; shellcheck -x must resolve it

- name: Run ShellCheck
shell: bash
env:
ACTIONLINT_IMAGE: rhysd/actionlint:1.7.12@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667
run: |
git ls-files '*.sh' '*.bash' ':!:tests/fixtures/*' | xargs -r shellcheck -x
git ls-files -z '*.sh' '*.bash' ':!:tests/fixtures/*' \
| xargs -0 -r docker run --rm -v "$PWD:/repo" -w /repo --entrypoint shellcheck "$ACTIONLINT_IMAGE" -x

psscriptanalyzer:
name: PSScriptAnalyzer
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Run PSScriptAnalyzer
shell: pwsh
run: |
if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) {
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser
}

$scripts = git ls-files "*.ps1" ":!:tests/*"
if ($scripts) {
$issues = $scripts | Invoke-ScriptAnalyzer -Severity Error, Warning
if ($issues) {
$issues | Format-Table -AutoSize
exit 1
}
if (-not $scripts) { exit 0 }

Install-Module -Name PSScriptAnalyzer -RequiredVersion 1.25.0 -Force -Scope CurrentUser
Import-Module PSScriptAnalyzer -RequiredVersion 1.25.0
$issues = $scripts | Invoke-ScriptAnalyzer -Severity Error, Warning
if ($issues) {
$issues | Format-Table -AutoSize
exit 1
}
25 changes: 19 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ name: Release
# 1. rewrites every self-reference (<owner>/<repo>[/path]@main) to @v<version> in a release commit
# 2. tags that commit v<version> and publishes a GitHub release with generated notes
# 3. moves the floating tags (v<major>, and v0.<minor> during 0.x) to it, unless it's a pre-release
# or an older version than the one the floating tag already has (so a hotfix never moves v1 backwards)
# main itself is never modified, so it keeps @main.
#
# Authenticates as a GitHub App (short-lived installation token, scoped to the caller's repo) because
Expand Down Expand Up @@ -39,6 +40,7 @@ permissions:
jobs:
release:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate inputs
shell: bash
Expand Down Expand Up @@ -85,7 +87,8 @@ jobs:
VERSION: ${{ inputs.version }}
run: |
self="${GITHUB_REPOSITORY//./\\.}(/[A-Za-z0-9_./-]+)?"
mapfile -t files < <(git ls-files '.github/workflows/*.yml' 'action.yml' '*/action.yml')
mapfile -t files < <(git ls-files '.github/workflows/*.yml' '.github/workflows/*.yaml' \
'action.yml' 'action.yaml' '*/action.yml' '*/action.yaml')
sed -i -E "s#(${self})@main\b#\1@v${VERSION}#g" "${files[@]}"

if git grep -nE "${self}@main\b" -- "${files[@]}"; then
Expand Down Expand Up @@ -133,11 +136,21 @@ jobs:
REST="${VERSION#*.}"
MINOR="${REST%%.*}"

git tag -fa "v${MAJOR}" -m "Update v${MAJOR} to v${VERSION}"
git push origin "v${MAJOR}" --force

# highest stable release tag matching the pattern; the new tag is already created locally.
highest() {
git tag -l "$1" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1
}
float() {
if [ "$(highest "$1.*")" != "v${VERSION}" ]; then
echo "::notice::Not moving $1: a newer release than v${VERSION} exists ($(highest "$1.*"))"
return
fi
git tag -fa "$1" -m "Update $1 to v${VERSION}"
git push origin "$1" --force
}

float "v${MAJOR}"
# float minor tag during 0.x, where minors may contain breaking changes
if [ "$MAJOR" = "0" ]; then
git tag -fa "v0.${MINOR}" -m "Update v0.${MINOR} to v${VERSION}"
git push origin "v0.${MINOR}" --force
float "v0.${MINOR}"
fi
9 changes: 8 additions & 1 deletion .github/workflows/test-scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
test-scripts:
name: Shell tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
Expand All @@ -33,8 +34,14 @@ jobs:
- name: Run tests/*.test.sh
shell: bash
run: |
shopt -s nullglob
tests=(tests/*.test.sh)
if [ "${#tests[@]}" -eq 0 ]; then
echo "::error::No tests/*.test.sh found; don't call test-scripts.yml from a repo without script tests"
exit 1
fi
failed=0
for t in tests/*.test.sh; do
for t in "${tests[@]}"; do
echo "::group::$t"
bash "$t" || failed=1
echo "::endgroup::"
Expand Down
6 changes: 0 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
node_modules/
.pnpm-store/
*.log
.DS_Store
Thumbs.db
.dart_tool/
**/build/
**/ephemeral/
build-args.json
4 changes: 0 additions & 4 deletions .prettierignore

This file was deleted.

14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ Shared CI for the `dotactions/*` repos: reusable workflows plus the shell test h

| Workflow | Does | Caller job needs |
| :--- | :--- | :--- |
| `release.yml` | Rewrites the caller's `@main` self-references to `@v<version>` in a release commit, tags it, creates the GitHub release, moves `v<major>` (and `v0.<minor>` during `0.x`) | `secrets: inherit` |
| `release.yml` | Rewrites the caller's `@main` self-references to `@v<version>` in a release commit, tags it, creates the GitHub release, moves `v<major>` (and `v0.<minor>` during `0.x`) forward only | `secrets: inherit` |
| `check-refs.yml` | Self-references must be `@main`; other repos in the org must be `@<40-char release-tag sha> # vX.Y.Z` | — |
| `actionlint.yml` | actionlint via reviewdog | `checks: write`, `pull-requests: write` |
| `lint.yml` | ShellCheck and PSScriptAnalyzer on tracked scripts | — |
| `test-scripts.yml` | `tests/*.test.sh` on ubuntu, macOS and Windows, with submodules | — |
| `actionlint.yml` | actionlint (pinned image), errors as annotations | — |
| `lint.yml` | ShellCheck (pinned image) and PSScriptAnalyzer (pinned version) on tracked scripts | — |
| `test-scripts.yml` | `tests/*.test.sh` on ubuntu, macOS and Windows, with submodules; fails if there are none | — |

Inside a called workflow, `github.*` and `vars` belong to the **caller**, so every workflow acts on the calling repo.

Expand Down Expand Up @@ -50,13 +50,9 @@ permissions:
jobs:
actionlint:
uses: dotactions/tooling/.github/workflows/actionlint.yml@<sha> # v1.0.0
permissions:
contents: read
checks: write
pull-requests: write
```

`check-refs.yml`, `lint.yml` and `test-scripts.yml` are called the same way, with no `with:` or extra permissions.
`check-refs.yml`, `lint.yml` and `test-scripts.yml` are called the same way. None needs `with:` or permissions beyond `contents: read`.

## Test harness

Expand Down
Loading