name: build-deb on: push: branches: ["**"] tags: ["v*"] pull_request: concurrency: group: build-deb-${{ github.ref }} cancel-in-progress: true defaults: run: shell: bash # the runner's default is sh; steps below use bash syntax env: GITEA_URL: https://code.lotusguild.org OWNER: LotusGuild REPO: LotusGuild/devdesk jobs: build: name: Lint, test, package runs-on: ubuntu-latest # Bookworm (tmux 3.3, debhelper 13); the node image keeps actions/checkout working. container: image: node:22-bookworm steps: - uses: actions/checkout@v3 - name: Install build tools run: | apt-get update -qq apt-get install -y -qq --no-install-recommends \ build-essential debhelper devscripts lintian fakeroot bats tmux fzf jq curl ca-certificates xz-utils >/dev/null VER=v0.10.0 curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors -o shellcheck.tar.xz \ "https://github.com/koalaman/shellcheck/releases/download/${VER}/shellcheck-${VER}.linux.x86_64.tar.xz" tar -xJf shellcheck.tar.xz install "shellcheck-${VER}/shellcheck" /usr/local/bin/shellcheck rm -rf shellcheck.tar.xz "shellcheck-${VER}" shellcheck --version | head -2 - name: npm ci run: | for i in 1 2 3; do npm ci --no-audit --no-fund && break echo "npm ci failed (attempt $i), retrying"; sleep 10 done git diff --exit-code package-lock.json - name: Lint run: make lint - name: Test run: make test - name: Set package version id: version env: DEBEMAIL: ci@lotusguild.org DEBFULLNAME: Lotus CI run: | base=$(dpkg-parsechangelog -S Version) case "$GITHUB_REF" in refs/tags/v*) version=${GITHUB_REF#refs/tags/v} ;; *) version="${base}+ci${GITHUB_RUN_NUMBER}.g${GITHUB_SHA::7}" ;; esac if [ "$version" != "$base" ]; then dch --newversion "$version" --distribution bookworm --force-distribution "CI build of ${GITHUB_SHA::7}" fi echo "version=$version" >> "$GITHUB_OUTPUT" echo "Building devdesk $version" - name: Build package run: | DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -us -uc -b mkdir -p out && mv ../devdesk_*.deb out/ ls -l out/ - name: Lintian run: lintian --fail-on error --info out/*.deb - name: Smoke test run: | set -x apt-get install -y -qq ./out/devdesk_*.deb >/dev/null /usr/lib/devdesk/bin/ttyd --version test -s /etc/devdesk/secret.env . /etc/devdesk/secret.env mkdir -p /run/devdesk tmux -u -D -S /run/devdesk/tmux.sock -f /usr/share/devdesk/tmux.conf & /usr/lib/devdesk/devdesk-tmux-ready DEVDESK_CREDENTIAL="$DEVDESK_CREDENTIAL" /usr/lib/devdesk/devdesk-serve & for _ in $(seq 1 30); do curl -s -o /dev/null localhost:7681/ && break; sleep 0.2; done code=$(curl -s -o /dev/null -w '%{http_code}' localhost:7681/) [ "$code" = 401 ] || { echo "expected 401 without credential, got $code"; exit 1; } # Download first: `curl | grep -q` fails under pipefail (grep exits early, curl gets SIGPIPE). curl -sf -u "$DEVDESK_CREDENTIAL" -o page.html localhost:7681/ grep -q 'name="generator" content="devdesk"' page.html curl -sf -u "$DEVDESK_CREDENTIAL" localhost:7681/token | jq -e '.token | length > 0' DEVDESK_NO_SYSTEMD=1 devdesk attach --list | jq -e '.default == "main"' echo "smoke test passed" - name: Upload artifact uses: actions/upload-artifact@v3 with: name: devdesk_${{ steps.version.outputs.version }}_amd64 path: out/*.deb - name: Publish to Gitea apt registry if: startsWith(github.ref, 'refs/tags/v') env: TOKEN: ${{ secrets.PACKAGE_TOKEN || secrets.NPM_PUBLISH_TOKEN }} VERSION: ${{ steps.version.outputs.version }} run: | deb=$(ls out/devdesk_*.deb) pool="$GITEA_URL/api/packages/$OWNER/debian/pool/bookworm/main" upload() { curl -s -o resp.txt -w '%{http_code}' -H "Authorization: token $TOKEN" --upload-file "$deb" "$pool/upload"; } code=$(upload) if [ "$code" = 409 ]; then echo "devdesk $VERSION already published; replacing it" curl -sf -X DELETE -H "Authorization: token $TOKEN" "$pool/devdesk/$VERSION/amd64" code=$(upload) fi [ "$code" = 201 ] || { echo "registry upload failed: HTTP $code"; cat resp.txt; exit 1; } echo "published devdesk $VERSION to $GITEA_URL/$OWNER/-/packages/debian/devdesk" - name: Create Gitea release if: startsWith(github.ref, 'refs/tags/v') env: TOKEN: ${{ secrets.RELEASE_TOKEN }} TAG: ${{ github.ref_name }} run: | api="$GITEA_URL/api/v1/repos/$REPO" auth=(-H "Authorization: token $TOKEN") id=$(curl -sf "${auth[@]}" "$api/releases/tags/$TAG" | jq -r '.id // empty' || true) if [ -z "$id" ]; then body=$(jq -n --arg tag "$TAG" '{tag_name: $tag, name: ("devdesk " + $tag), draft: false, prerelease: false, body: "Install: `apt update && apt install devdesk` (Gitea apt registry), or download the .deb below."}') id=$(curl -sf "${auth[@]}" -H 'Content-Type: application/json' -d "$body" "$api/releases" | jq -r '.id') fi deb=$(ls out/devdesk_*.deb) name=$(basename "$deb") existing=$(curl -sf "${auth[@]}" "$api/releases/$id/assets" | jq -r --arg n "$name" '.[] | select(.name == $n) | .id') [ -n "$existing" ] && curl -sf -X DELETE "${auth[@]}" "$api/releases/$id/assets/$existing" curl -sf "${auth[@]}" -H 'Content-Type: application/octet-stream' --data-binary "@$deb" \ "$api/releases/$id/assets?name=$name" >/dev/null echo "release $TAG: $GITEA_URL/$REPO/releases/tag/$TAG" deploy: name: Deploy to CT 126 runs-on: ubuntu-latest needs: [build] if: startsWith(github.ref, 'refs/tags/v') steps: # CT 126's webhook listener runs /usr/lib/devdesk/devdesk-deploy, which # waits for this version in the apt registry and upgrades the package. # The hook answers when the install is done (HTTP 500 if it failed), so # this job's result is the deploy's result. - name: Trigger devdesk-deploy webhook env: WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }} GIT_REF: ${{ github.ref }} run: | PAYLOAD="{\"ref\":\"${GIT_REF}\"}" SIG=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}') code=$(curl -sS --connect-timeout 10 --max-time 900 -o /tmp/deploy.out -w '%{http_code}' \ -X POST \ -H "Content-Type: application/json" \ -H "X-Gitea-Signature: ${SIG}" \ -d "$PAYLOAD" \ "http://10.10.10.58:9000/hooks/devdesk-deploy") || code=000 cat /tmp/deploy.out 2>/dev/null || true echo "webhook: HTTP $code" [ "$code" = 200 ] notify-failure: name: Notify on failure runs-on: ubuntu-latest needs: [build, deploy] if: failure() && github.event_name == 'push' steps: - name: Send Matrix alert env: MATRIX_WEBHOOK_URL: ${{ secrets.MATRIX_WEBHOOK_URL }} REPO: ${{ github.repository }} BRANCH: ${{ github.ref_name }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} run: | if [ -z "$MATRIX_WEBHOOK_URL" ] || [ "$MATRIX_WEBHOOK_URL" = "CONFIGURE_ME" ]; then exit 0; fi curl -sf -X POST "$MATRIX_WEBHOOK_URL" \ -H "Content-Type: application/json" \ -d "{\"text\":\"CI FAILED: ${REPO} @ ${BRANCH} — ${RUN_URL}\"}"