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
8 changes: 8 additions & 0 deletions .config/mise/tasks/github/actions/ci/lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
#MISE description="Lint every workflow and shell script"
set -euo pipefail

actionlint

# -r keeps this a no-op rather than an error when nothing matches.
git ls-files -z '*.sh' '.config/mise/tasks/**' | xargs -0 -r shellcheck -x
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions: {}

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

jobs:
check:
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# Tool versions live in mise.toml and the task lives under
# .config/mise/tasks, so a contributor runs exactly what CI runs.
- uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0

- run: mise run github:actions:ci:lint
21 changes: 21 additions & 0 deletions .github/workflows/semconv.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: SemConv

on:
pull_request:
types: [opened, edited, synchronize, reopened]

permissions: {}

jobs:
lint-pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: ./actions/semconv/pull-request
9 changes: 9 additions & 0 deletions actions/semconv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# semconv

Actions that enforce [Conventional Commits][spec] across a repository.

| Action | Enforces |
| --- | --- |
| [`pull-request`](pull-request) | The pull request title |

[spec]: https://www.conventionalcommits.org/en/v1.0.0/
68 changes: 68 additions & 0 deletions actions/semconv/pull-request/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# semconv/pull-request

Fails a pull request whose title is not a Conventional Commit. A thin wrapper
around [`amannn/action-semantic-pull-request`][upstream] that fixes the grammar
so every repository agrees on it.

## Usage

The job name matters. Repository rulesets require the check by the literal
string `Validate PR Title`, so renaming the job silently stops the required
check from ever reporting.

```yaml
name: SemConv

on:
pull_request:
types: [opened, edited, synchronize, reopened]

permissions: {}

jobs:
lint-pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
pull-requests: read
steps:
- uses: TrogonStack/github-actions/actions/semconv/pull-request@<full-sha>
```

The reference must be a full commit SHA. Both organizations set
`sha_pinning_required`, so a branch or tag reference makes the job refuse to
start rather than fail.

## Grammar

```
<type>[(scope)][!]: <description>
```

`feat`, `fix`, and `chore` are the only types. Anything that is not a feature or
a fix is a chore. The description must not start with an uppercase letter.

The type list is not an input. One grammar for every repository is the reason
this action exists; a knob invites back the divergence it was built to remove.

## Inputs

| Input | Default | Description |
| --- | --- | --- |
| `extra-ignore-labels` | none | Further labels that skip the check, one per line. |
| `token` | `github.token` | Read access is sufficient. |

`bot`, `dependencies`, and `autorelease: pending` are always ignored. The last
is release-please's own pull request, which does not follow the grammar it
exists to produce.

## Title only

Only the title is checked, because only the title reaches the default branch on
a squash merge. Repositories that allow merge or rebase commits, or that squash
with `COMMIT_OR_PR_TITLE`, can still land an unconventional subject. That is a
repository settings problem and is fixed in the Terraform that owns those
settings, not here.

[upstream]: https://github.com/amannn/action-semantic-pull-request
44 changes: 44 additions & 0 deletions actions/semconv/pull-request/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Validate PR Title
description: >-
Fails a pull request whose title is not a Conventional Commit.
author: TrogonStack

inputs:
extra-ignore-labels:
description: >-
Further labels that skip the check, one per line. Bot and release labels
are already ignored.
required: false
default: ''
token:
description: Token used to read the pull request. Read access is sufficient.
required: false
default: ${{ github.token }}

runs:
using: composite
steps:
- name: Validate PR title
uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
env:
GITHUB_TOKEN: ${{ inputs.token }}
with:
# Anything that is not a feature or a fix is a chore. This list is
# deliberately not an input: one grammar for every repository is the
# reason this action exists.
types: |
feat
fix
chore
requireScope: false
subjectPattern: ^(?![A-Z]).+$
subjectPatternError: |
The subject "{subject}" in the pull request title "{title}" should start
with a lowercase letter.
# "autorelease: pending" is release-please's own pull request, which does
# not follow the grammar it exists to produce.
ignoreLabels: |
bot
dependencies
autorelease: pending
${{ inputs.extra-ignore-labels }}
3 changes: 3 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[tools]
actionlint = "1.7.12"
shellcheck = "0.11.0"
Loading