Skip to content
Open
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
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{md,yml,json,json5,toml}]
indent_size = 2

[*.luau]
indent_style = tab
147 changes: 147 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
name: CI

on:
push:
branches: [main]
pull_request:

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -D warnings

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

jobs:
lint:
name: Format and lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: Swatinem/rust-cache@v2
- run: cargo fmt --all --check
- run: cargo clippy --all-targets

build:
name: Build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v5
- uses: Swatinem/rust-cache@v2
- run: cargo build --release

docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: Swatinem/rust-cache@v2
- uses: astral-sh/setup-uv@v7
- run: cargo build --release

# The catalogue lives in the binary. A committed page that disagrees with it is
# worse than no page, so regenerating and diffing is the whole check.
- run: ./target/release/pcmp explain --format markdown > docs/diagnostics.md
- run: git diff --exit-code docs/diagnostics.md

# `--strict` turns a broken link or a dead anchor into a failure. Most of those
# anchors are the diagnostic codes, so renaming a code without fixing what points at
# it fails here rather than shipping.
- run: uvx zensical build --strict

behaviour:
name: Behaviour
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: Swatinem/rust-cache@v2
- run: cargo build --release

# A fixture in a heredoc rather than in the repository: this exercises the binary
# a user gets, and leaves nothing behind to keep in step with the code.
- name: Build a fixture, lock it, and reproduce it
run: |
set -euxo pipefail
pcmp="$GITHUB_WORKSPACE/target/release/pcmp"
mkdir -p /tmp/fixture/src && cd /tmp/fixture

cat > src/init.luau <<'LUAU'
--!strict
local VERSION: string = PCMP_VERSION
if DEBUG then print("stripped") end
return { version = VERSION, retries = RETRIES }
LUAU

cat > pcmp.luau <<'MANIFEST'
return {
vars = { name = "fixture", version = "v1.0.0", retries = 3, built = pcmp.now() },
profiles = {
release = {
entry = "src/init.luau",
output = "dist/{name}.luau",
define = { DEBUG = false },
header = { "-- {name} {version} ({built})" },
darklua = {
generator = "dense",
rules = {
"compute_expression",
"remove_unused_if_branch",
"remove_types",
"remove_comments",
},
},
},
},
}
MANIFEST

# This manifest reads the clock and no lock records the answer, which is the
# one thing `--strict` is there to catch.
! "$pcmp" check --strict

"$pcmp" build --lock
test -f pcmp.lock
"$pcmp" check --strict

# The property the whole tool exists for. A different second, a timestamp
# baked into the header, and the artifacts still match the lock.
sleep 1
"$pcmp" build --frozen

# The honest inverse, with the clock live again. A manifest that asks the time
# is a different build each second, so this must not report a cache hit.
sleep 1
"$pcmp" build --json | jq -e '[.tasks[] | select(.status == "cached")] | length == 0'

# Everything below pins the clock, so each check varies one thing. Without the
# pin, `pcmp.now()` alone would explain every rebuild and prove nothing.
export SOURCE_DATE_EPOCH=1700000000

# The pinned instant is now the only one, so the first build settles the cache
# and the second finds nothing to do.
"$pcmp" build
"$pcmp" build --json | jq -e '[.tasks[] | select(.status != "cached")] | length == 0'

# An artifact edited by hand is noticed, not trusted. Nothing else moved, so a
# rebuild here can only come from the artifact digest.
echo "-- tampered" > dist/fixture.luau
"$pcmp" build --json | jq -e '[.tasks[] | select(.status != "built")] | length == 0'
! grep -q "tampered" dist/fixture.luau

audit:
name: Advisories
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# A prebuilt binary rather than `cargo install`: building cargo-audit from source
# resolves its dependencies to their latest versions, whose MSRV moves ahead of the
# toolchain this repository pins, and the build fails on a dependency nobody chose.
- uses: taiki-e/install-action@v2
with:
tool: cargo-audit
- run: cargo audit
39 changes: 0 additions & 39 deletions .github/workflows/publish-docs.yml

This file was deleted.

68 changes: 68 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Release

on:
push:
tags: ["v*"]
workflow_dispatch:

permissions:
contents: write

jobs:
build:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, name: linux-x86_64 }
- { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, name: linux-aarch64 }
- { os: macos-latest, target: x86_64-apple-darwin, name: macos-x86_64 }
- { os: macos-latest, target: aarch64-apple-darwin, name: macos-aarch64 }
- { os: windows-latest, target: x86_64-pc-windows-msvc, name: windows-x86_64 }
steps:
- uses: actions/checkout@v5
- uses: Swatinem/rust-cache@v2
- run: rustup target add ${{ matrix.target }}
- uses: taiki-e/install-action@v2
if: matrix.target == 'aarch64-unknown-linux-gnu'
with:
tool: cross
- name: Build
shell: bash
run: |
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
cross build --release --locked --target ${{ matrix.target }}
else
cargo build --release --locked --target ${{ matrix.target }}
fi
- name: Package
shell: bash
run: |
set -eu
staging="pcmp-${{ github.ref_name }}-${{ matrix.name }}"
mkdir -p "$staging"
if [ "${{ matrix.os }}" = "windows-latest" ]; then
cp "target/${{ matrix.target }}/release/pcmp.exe" "$staging/"
else
cp "target/${{ matrix.target }}/release/pcmp" "$staging/"
fi
cp README.md LICENSE "$staging/"
zip -r "$staging.zip" "$staging"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}
path: "*.zip"

publish:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
merge-multiple: true
- uses: softprops/action-gh-release@v2
with:
files: "*.zip"
generate_release_notes: true
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
generated/
.env
pipeline/.pcmp.local.json
target/
.pcmp/
dist/
site/
.cache/
6 changes: 0 additions & 6 deletions .markdownlint.json

This file was deleted.

Loading