diff --git a/.forgejo/workflows/ci-gates.yml b/.forgejo/workflows/ci-gates.yml new file mode 100644 index 0000000..d513985 --- /dev/null +++ b/.forgejo/workflows/ci-gates.yml @@ -0,0 +1,112 @@ +name: ci-gates + +on: + pull_request: {} + push: + branches: [main] + workflow_dispatch: {} + +jobs: + checks: + runs-on: codeberg-medium-lazy + steps: + - name: Fetch source (no git required) + env: + GITHUB_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + if [[ -z "${GITHUB_TOKEN:-}" ]]; then + echo "error: missing github.token" + exit 2 + fi + if ! command -v curl >/dev/null 2>&1; then + echo "error: curl is required" + exit 2 + fi + if ! command -v tar >/dev/null 2>&1; then + echo "error: tar is required" + exit 2 + fi + if [[ -z "${GITHUB_SHA:-}" ]]; then + echo "error: missing GITHUB_SHA" + exit 2 + fi + + rm -rf .repo + mkdir -p .repo + curl -fsSL -H "Authorization: token ${GITHUB_TOKEN}" \ + "https://codeberg.org/api/v1/repos/every-channel/every.channel/archive/${GITHUB_SHA}.tar.gz?rev=${GITHUB_SHA}" \ + -o .repo/src.tgz + tar -xzf .repo/src.tgz -C .repo --strip-components=1 + rm -f .repo/src.tgz + + - name: Bootstrap Rust + web build tools + shell: bash + run: | + set -euo pipefail + cd .repo + install -d -m 755 "$HOME/.local/bin" + echo "PATH=$HOME/.local/bin:$PATH" >> "$GITHUB_ENV" + export PATH="$HOME/.local/bin:$PATH" + + if ! command -v curl >/dev/null 2>&1; then + echo "error: curl is required" + exit 2 + fi + + if ! command -v cargo >/dev/null 2>&1; then + curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal + . "$HOME/.cargo/env" + elif [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + + rustup target add wasm32-unknown-unknown + + if ! command -v trunk >/dev/null 2>&1; then + trunk_version="0.21.14" + arch="$(uname -m)" + case "${arch}" in + x86_64|amd64) trunk_target="x86_64-unknown-linux-gnu" ;; + aarch64|arm64) trunk_target="aarch64-unknown-linux-gnu" ;; + *) + echo "error: unsupported runner arch for trunk prebuilt binary: ${arch}" + exit 2 + ;; + esac + curl -fsSL "https://github.com/trunk-rs/trunk/releases/download/v${trunk_version}/trunk-${trunk_target}.tar.gz" \ + | tar -xz -C "$HOME/.local/bin" trunk + fi + + cargo --version + rustc --version + trunk --version + + - name: ECP lint + shell: bash + run: | + set -euo pipefail + cd .repo + bash ./scripts/ecp-lint.sh + + - name: Rust tests (core subset) + shell: bash + run: | + set -euo pipefail + cd .repo + if [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + cargo test -p ec-core -p ec-crypto -p ec-moq -p ec-iroh -p ec-linux-iptv + + - name: Build web (apps/web) + shell: bash + run: | + set -euo pipefail + cd .repo + if [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + cd apps/web + env -u NO_COLOR trunk build --release --public-url / diff --git a/.forgejo/workflows/deploy-cloudflare.yml b/.forgejo/workflows/deploy-cloudflare.yml index dfe203b..3aecdd7 100644 --- a/.forgejo/workflows/deploy-cloudflare.yml +++ b/.forgejo/workflows/deploy-cloudflare.yml @@ -10,7 +10,108 @@ concurrency: cancel-in-progress: true jobs: + checks: + runs-on: codeberg-medium-lazy + steps: + - name: Fetch Source (no git required) + env: + GITHUB_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + if [[ -z "${GITHUB_TOKEN:-}" ]]; then + echo "error: missing github.token" + exit 2 + fi + if ! command -v curl >/dev/null 2>&1; then + echo "error: curl is required" + exit 2 + fi + if ! command -v tar >/dev/null 2>&1; then + echo "error: tar is required" + exit 2 + fi + if [[ -z "${GITHUB_SHA:-}" ]]; then + echo "error: missing GITHUB_SHA" + exit 2 + fi + + rm -rf .repo + mkdir -p .repo + + curl -fsSL -H "Authorization: token ${GITHUB_TOKEN}" \ + "https://codeberg.org/api/v1/repos/every-channel/every.channel/archive/${GITHUB_SHA}.tar.gz?rev=${GITHUB_SHA}" \ + -o .repo/src.tgz + tar -xzf .repo/src.tgz -C .repo --strip-components=1 + rm -f .repo/src.tgz + + - name: Bootstrap Rust + web build tools + shell: bash + run: | + set -euo pipefail + cd .repo + install -d -m 755 "$HOME/.local/bin" + echo "PATH=$HOME/.local/bin:$PATH" >> "$GITHUB_ENV" + export PATH="$HOME/.local/bin:$PATH" + + if ! command -v curl >/dev/null 2>&1; then + echo "error: curl is required" + exit 2 + fi + + if ! command -v cargo >/dev/null 2>&1; then + curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal + . "$HOME/.cargo/env" + elif [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + rustup target add wasm32-unknown-unknown + + if ! command -v trunk >/dev/null 2>&1; then + trunk_version="0.21.14" + arch="$(uname -m)" + case "${arch}" in + x86_64|amd64) trunk_target="x86_64-unknown-linux-gnu" ;; + aarch64|arm64) trunk_target="aarch64-unknown-linux-gnu" ;; + *) + echo "error: unsupported runner arch for trunk prebuilt binary: ${arch}" + exit 2 + ;; + esac + curl -fsSL "https://github.com/trunk-rs/trunk/releases/download/v${trunk_version}/trunk-${trunk_target}.tar.gz" \ + | tar -xz -C "$HOME/.local/bin" trunk + fi + + - name: ECP lint + shell: bash + run: | + set -euo pipefail + cd .repo + bash ./scripts/ecp-lint.sh + + - name: Rust tests (core subset) + shell: bash + run: | + set -euo pipefail + cd .repo + if [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + cargo test -p ec-core -p ec-crypto -p ec-moq -p ec-iroh -p ec-linux-iptv + + - name: Build site (web) + shell: bash + run: | + set -euo pipefail + cd .repo + if [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + cd apps/web + env -u NO_COLOR trunk build --release --public-url / + deploy: + needs: checks runs-on: codeberg-medium-lazy steps: - name: Fetch Source (no git required) diff --git a/justfile b/justfile index 4c6b8e3..c5d871a 100644 --- a/justfile +++ b/justfile @@ -3,6 +3,9 @@ set shell := ["bash", "-eu", "-o", "pipefail", "-c"] default: @just --list +ecp-lint: + ./scripts/ecp-lint.sh + test-core: cargo test -p ec-core -p ec-crypto -p ec-moq -p ec-iroh -p ec-linux-iptv diff --git a/scripts/ecp-lint.sh b/scripts/ecp-lint.sh new file mode 100755 index 0000000..ee4c735 --- /dev/null +++ b/scripts/ecp-lint.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "${root}" + +min_id="${EVERY_CHANNEL_ECP_LINT_MIN_ID:-63}" + +files=() +if [[ "$#" -gt 0 ]]; then + for arg in "$@"; do + files+=("${arg}") + done +else + while IFS= read -r f; do + files+=("${f}") + done < <(find evolution/proposals -maxdepth 1 -type f -name 'ECP-*.md' | sort) +fi + +if [[ "${#files[@]}" -eq 0 ]]; then + echo "ecp-lint: no ECP files found" + exit 0 +fi + +errors=0 + +check_pattern() { + local file="$1" + local regex="$2" + local message="$3" + if ! rg -q --pcre2 "${regex}" "${file}"; then + echo "ecp-lint: ${file}: ${message}" >&2 + errors=$((errors + 1)) + fi +} + +for file in "${files[@]}"; do + [[ -f "${file}" ]] || continue + + base="$(basename "${file}")" + if [[ ! "${base}" =~ ^ECP-([0-9]{4})- ]]; then + continue + fi + id=$((10#${BASH_REMATCH[1]})) + if (( id < min_id )); then + continue + fi + + check_pattern "${file}" '^# ECP-[0-9]{4}:' "missing or invalid title" + check_pattern "${file}" '^Status: (Draft|Accepted|Implemented|Superseded|Rejected)$' "missing or invalid Status line" + check_pattern "${file}" '^## (Problem|Context|Motivation)\b' "missing Problem/Context/Motivation section" + check_pattern "${file}" '^## Decision\b' "missing Decision section" + check_pattern "${file}" '^## (Alternatives considered|Alternatives)\b' "missing Alternatives considered section" + check_pattern "${file}" '^## (Rollout / teardown|Rollout / teardown plan|Rollout / Reversibility|Rollout|Reversibility)\b' "missing Rollout/teardown (or Reversibility) section" +done + +if (( errors > 0 )); then + echo "ecp-lint: failed with ${errors} issue(s)" >&2 + exit 1 +fi + +echo "ecp-lint: ok"