name: Development CI on: push: branches: [main] pull_request: workflow_dispatch: permissions: contents: read concurrency: group: rawmark-development cancel-in-progress: false jobs: check-and-package: runs-on: ubuntu-latest timeout-minutes: 55 env: CGO_ENABLED: '0' steps: - uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: persist-credentials: false - uses: https://github.com/actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version-file: go.mod cache: false - name: Install frontend dependencies run: | corepack enable corepack prepare pnpm@12.11.2 --activate pnpm -C web install --frozen-lockfile --registry=https://registry.npmjs.org - name: Check and build frontend run: | pnpm -C web lint:check pnpm -C web typecheck pnpm -C web test pnpm -C web build pnpm -C web build:demo - name: Check backend run: | go vet -tags dev ./... go test ./internal/... go test -tags dev ./web ./cmd/rawmark go vet ./... go test ./web ./cmd/rawmark - name: Test filesystem permissions as an unprivileged user run: | for package in vault watch; do go test -c -o "/tmp/rawmark-$package.test" "./internal/$package" (cd "internal/$package" && runuser -u node -- "/tmp/rawmark-$package.test" -test.v) done - name: Build platform packages and smoke-test Linux amd64 run: | mkdir -p package/licenses downloads cp LICENSE package/ cp web/LICENSE package/licenses/vue3-starter-MIT.txt cp web/src/common/appearance/fonts/*-OFL.txt package/licenses/ cp web/src/common/appearance/fonts/maple/LICENSE.txt package/licenses/Maple-Mono-OFL.txt for target in linux/amd64 linux/arm64 windows/amd64 darwin/arm64 darwin/amd64; do export GOOS="${target%/*}" GOARCH="${target#*/}" extension='' if [ "$GOOS" = windows ]; then extension='.exe'; fi rm -f package/rawmark package/rawmark.exe go vet ./... go build -trimpath -ldflags="-s -w -X main.releaseVersion=$(cat VERSION)" -o "package/rawmark$extension" ./cmd/rawmark if [ "$target" = linux/amd64 ]; then python3 scripts/smoke-release.py package/rawmark fi python3 scripts/package-release.py "$GOOS" "$GOARCH" done - name: Check upload sizes and generate checksums run: | python3 - <<'PY' import hashlib from pathlib import Path archives = sorted(Path('downloads').glob('rawmark_*')) if len(archives) != 5: raise SystemExit(f'Expected five platform packages, found {len(archives)}') checksums = [] for archive in archives: size = archive.stat().st_size print(f'{archive.name}: {size:,} bytes') if size >= 90_000_000: raise SystemExit(f'{archive.name} exceeds the 90 MB upload budget (Cloudflare limit: 100 MB)') checksums.append(f'{hashlib.file_digest(archive.open("rb"), "sha256").hexdigest()} {archive.name}\n') Path('downloads/SHA256SUMS').write_text(''.join(checksums)) PY - uses: https://github.com/actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: linux-amd64 path: downloads/*_linux_amd64.tar.gz compression-level: 0 if-no-files-found: error retention-days: 7 - uses: https://github.com/actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: linux-arm64 path: downloads/*_linux_arm64.tar.gz compression-level: 0 if-no-files-found: error retention-days: 7 - uses: https://github.com/actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: windows-amd64 path: downloads/*_windows_amd64.zip compression-level: 0 if-no-files-found: error retention-days: 7 - uses: https://github.com/actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: darwin-arm64 path: downloads/*_darwin_arm64.tar.gz compression-level: 0 if-no-files-found: error retention-days: 7 - uses: https://github.com/actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: darwin-amd64 path: downloads/*_darwin_amd64.tar.gz compression-level: 0 if-no-files-found: error retention-days: 7 - uses: https://github.com/actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: checksums path: downloads/SHA256SUMS if-no-files-found: error retention-days: 7 docker-smoke: needs: check-and-package runs-on: docker timeout-minutes: 15 defaults: run: shell: sh steps: - name: Install CI action and smoke-test runtimes run: apk add --no-cache nodejs python3 - uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: persist-credentials: false - uses: https://github.com/actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: linux-amd64 path: downloads - uses: https://github.com/actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: checksums path: downloads - name: Verify the tested binary archive run: | python3 - <<'PY' import hashlib from pathlib import Path expected = {line.split()[1]: line.split()[0] for line in Path('downloads/SHA256SUMS').read_text().splitlines()} archive = Path(f'downloads/rawmark_{Path("VERSION").read_text().strip()}_linux_amd64.tar.gz') with archive.open('rb') as source: assert hashlib.file_digest(source, 'sha256').hexdigest() == expected[archive.name] PY mkdir -p image/linux/amd64 image/data tar -xzf "downloads/rawmark_$(cat VERSION)_linux_amd64.tar.gz" -C image/linux/amd64 - name: Build and test the isolated container image env: COMMIT_SHA: ${{ gitea.sha }} RUN_ID: ${{ gitea.run_id }} RUN_ATTEMPT: ${{ gitea.run_attempt }} run: | set -eu image="rawmark-ci:$COMMIT_SHA-$RUN_ID-$RUN_ATTEMPT" docker build --build-arg TARGETARCH=amd64 --tag "$image" -f deploy/Dockerfile.release image trap 'docker image rm "$image"' EXIT python3 scripts/smoke-docker.py "$image" --client-container "$(hostname)"