Skip to content
Draft
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
104 changes: 104 additions & 0 deletions .github/workflows/bats_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Bats Tests

on:
pull_request:
branches:
- main

permissions:
contents: read

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

jobs:
actionlint:
name: Validate GitHub Workflows (actionlint)
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Install actionlint
run: |
ACTIONLINT_VERSION="1.7.7"
curl -sSfL "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
| tar -xz
sudo mv actionlint /usr/local/bin/actionlint
actionlint -version

- name: Run Workflow Linter
run: actionlint

shellcheck:
name: Lint Shell Scripts (shellcheck)
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Install shellcheck
run: |
sudo apt-get update -y
sudo apt-get install -y shellcheck

- name: Run Shell Linter
run: shellcheck scripts/*.sh

shfmt:
name: Check Shell Formatting (shfmt)
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Install shfmt
run: |
sudo apt-get update -y
sudo apt-get install -y shfmt

- name: Run Shell Formatter Check
run: git ls-files '*.sh' '*.bash' '*.bats' | xargs shfmt -d -i 4 -ci

bats:
name: Run Shell Test Suite (bats)
needs:
- shellcheck
- shfmt
- actionlint
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Install bats (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update -y
sudo apt-get install -y bats

- name: Install bats (macOS)
if: runner.os == 'macOS'
run: brew install bats-core

- name: Run bats Test Suite
run: bats --recursive tests/bats
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,16 @@ format:
package:
curl -s $(baseUrl)/check-swift-package.sh | bash

lint-shell:
curl -s $(baseUrl)/script-format.sh | bash

format-shell:
curl -s $(baseUrl)/script-format.sh | bash -s -- --fix

lint-workflows:
curl -s $(baseUrl)/run-actionlint.sh | bash

check: symlinks language deps lint docc-warnings headers

test-bats:
bats --recursive tests/bats
127 changes: 114 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ Detects source- and binary-level API breaking changes in Swift packages to preve
#### Behavior

* Uses `swift package diagnose-api-breaking-changes`
* Pull requests: compares against the PR base branch
* Other contexts: compares against the latest Git tag
* Pull requests: fetches `${GITHUB_BASE_REF}` into a local `pull-base-ref` and compares against that ref
* Other contexts: fetches tags and compares against the latest Git tag
* If no tags exist, exits successfully with a warning
* Fails when breaking changes are detected

Expand Down Expand Up @@ -233,7 +233,7 @@ Prevents accidental usage of local Swift package dependencies.

#### Behavior

* Scans all tracked `Package.swift` files
* Scans git-tracked `Package.swift` files only (ignores untracked files)
* Detects `.package(path:)`
* Fails immediately on detection

Expand Down Expand Up @@ -262,22 +262,29 @@ Runs a security scan of an OpenAPI specification using OWASP ZAP.
#### Behavior

* Executes inside Docker
* Skips execution if `openapi/` directory does not exist
* Accepts an OpenAPI file or directory (default: `openapi`)
* Relative `-f` paths are resolved from the git repository root first, then current working directory
* For file paths, supports `.yml`/`.yaml` extension fallback
* Skips execution if no OpenAPI specification can be resolved

#### Parameters

_None_
* `-f <path>` – OpenAPI file or directory path

#### Ignore files

_None_

#### Raw curl example
#### Raw curl examples

```sh
curl -s $(baseUrl)/check-openapi-security.sh | bash
```

```sh
curl -s $(baseUrl)/check-openapi-security.sh | bash -s -- -f openapi/openapi.yml
```

---

### check-openapi-validation.sh
Expand All @@ -289,22 +296,34 @@ Validates an OpenAPI specification for schema correctness.
#### Behavior

* Runs the OpenAPI validator in Docker
* Skips execution if `openapi/` directory does not exist
* Accepts an OpenAPI file or directory (default: `openapi`)
* Relative `-f` paths are resolved from the git repository root first, then current working directory
* For file paths, supports `.yml`/`.yaml` extension fallback
* Skips execution if no OpenAPI specification can be resolved

#### Parameters

_None_
* `-f <path>` – OpenAPI file or directory path

#### Ignore files

_None_

#### Raw curl example
#### Raw curl examples

```sh
curl -s $(baseUrl)/check-openapi-validation.sh | bash
```

```sh
curl -s $(baseUrl)/check-openapi-validation.sh | bash -s -- -f openapi/openapi.yaml
```

```sh
# Monorepo/nested project example (path relative to git root)
curl -s $(baseUrl)/check-openapi-validation.sh | bash -s -- -f mail-examples/mail-example-openapi/openapi/openapi.yaml
```

---

### check-swift-headers.sh
Expand All @@ -318,6 +337,10 @@ Ensures Swift source files contain a consistent, standardized header.
* Enforces a strict 5-line header format
* Can optionally insert or update headers in-place
* Processes only git-tracked Swift files
* Skips `Package.swift` explicitly
* Accepts `Created by ... on YYYY. MM. DD.` and legacy `..` suffix
* In `--fix` mode, normalizes legacy `..` to `.`
* When repairing malformed headers, preserves extracted author and date when possible

#### Parameters

Expand All @@ -326,7 +349,7 @@ Ensures Swift source files contain a consistent, standardized header.

#### Ignore files

* `.swiftheaderignore` – excludes paths from header validation
* `.swiftheaderignore` – excludes paths from header validation (replaces default exclusions when present)

#### Raw curl examples

Expand Down Expand Up @@ -354,6 +377,7 @@ Detects discouraged or outdated terminology to promote inclusive language.

* Case-insensitive, whole-word matching
* Scans git-tracked files only
* Lines containing `ignore-unacceptable-language` are excluded from failures

#### Parameters

Expand All @@ -379,9 +403,11 @@ Generates a CONTRIBUTORS.txt file from git commit history.

#### Behavior

* Uses `git shortlog`
* Uses `git shortlog -es HEAD`
* Respects `.mailmap`
* Overwrites the file deterministically
* Writes to repository root even when run from a subdirectory
* If the repository has no commits, exits successfully and does not create `CONTRIBUTORS.txt`

#### Parameters

Expand Down Expand Up @@ -506,7 +532,8 @@ Removes generated build artifacts and temporary files. ⚠️ Irreversible opera

#### Behavior

* Deletes `.build`, `.swiftpm`, and generated files
* Deletes `.build/` and `.swiftpm/`
* Deletes `openapi/openapi.yaml`, `db.sqlite`, and `migration-entries.json`
* Intended for local development use


Expand Down Expand Up @@ -563,24 +590,33 @@ Serves OpenAPI documentation locally using Docker.

#### Behavior

* Accepts an OpenAPI file or directory (default: `openapi`)
* Relative `-f` paths are resolved from the git repository root first, then current working directory
* If a file is provided, mounts its parent directory
* For file paths, supports `.yml`/`.yaml` extension fallback
* Runs Nginx in the foreground
* Exposes documentation over HTTP

#### Parameters

* `-n <name>` – container name
* `-p <host:container>` – port mapping
* `-f <path>` – OpenAPI file or directory path

#### Ignore files

_None_

#### Raw curl example
#### Raw curl examples

```sh
curl -s $(baseUrl)/run-openapi-docker.sh | bash -s -- -n openapi-preview
```

```sh
curl -s $(baseUrl)/run-openapi-docker.sh | bash -s -- -n openapi-preview -f openapi/openapi.yaml
```

---

### run-swift-format.sh
Expand Down Expand Up @@ -619,6 +655,71 @@ curl -s $(baseUrl)/run-swift-format.sh | bash -s -- --fix

---

### run-actionlint.sh

#### Purpose

Runs `actionlint` to validate GitHub Actions workflows.

#### Behavior

* Verifies `actionlint` is installed before running
* Runs from repository root for consistent workflow path resolution
* Passes through optional CLI arguments to `actionlint`

#### Parameters

* `<actionlint args...>` – optional arguments passed to `actionlint`

#### Ignore files

_None_

#### Raw curl example

```sh
curl -s $(baseUrl)/run-actionlint.sh | bash
```

---

### script-format.sh

#### Purpose

Runs `shfmt` to check or fix formatting for tracked shell-related files.

#### Behavior

* Verifies `shfmt` is installed before running
* Targets tracked `*.sh`, `*.bash`, and `*.bats` files
* Default mode checks formatting and fails on drift
* `--fix` mode applies formatting in-place

#### Parameters

* `--fix` – apply formatting in-place

#### Ignore files

_None_

#### Raw curl examples

_Check only:_

```sh
curl -s $(baseUrl)/script-format.sh | bash
```

_Fix formatting:_

```sh
curl -s $(baseUrl)/script-format.sh | bash -s -- --fix
```

---

### check-swift-package.sh

#### Purpose
Expand Down
9 changes: 6 additions & 3 deletions scripts/check-api-breakage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
set -euo pipefail

# Logging helpers
log() { printf -- "** %s\n" "$*" >&2; }
log() { printf -- "** %s\n" "$*" >&2; }
error() { printf -- "** ERROR: %s\n" "$*" >&2; }
fatal() { error "$@"; exit 1; }
fatal() {
error "$@"
exit 1
}

# Determine baseline reference
if [ -n "${GITHUB_BASE_REF:-}" ] && [ -n "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_SERVER_URL:-}" ]; then
Expand Down Expand Up @@ -45,4 +48,4 @@ log "Using baseline: ${BASELINE_REF}"
# This command exits non-zero if API-breaking changes are detected.
swift package diagnose-api-breaking-changes "$BASELINE_REF"

log "✅ No API-breaking changes detected."
log "✅ No API-breaking changes detected."
Loading