ci: redesign workflows into lint + build (#1330)

Replace 5 workflow files with 2 clean ones:

- lint.yml: Go lint and UI lint as parallel jobs with consistent
  push + pull_request triggers (fixes fork PRs never getting UI lint)
- build.yml: stripped to compile + test only, with pull_request
  trigger added (PRs now get build feedback before merge)

Removed:
- stale-issues.yml (permanent dry-run no-op)
- smoketest.yml (frequently failing device tests)
- dependabot.yml (automated dependency bumps)
- golangci-lint.yml (folded into lint.yml)
- ui-lint.yml (folded into lint.yml)

Also fixed build.yml cache restore-keys to use a proper prefix
fallback instead of duplicating the full key.
This commit is contained in:
Adam Shiervani
2026-03-25 18:44:34 +01:00
committed by GitHub
parent 66b71385ad
commit db4452d0bb
7 changed files with 61 additions and 408 deletions
-17
View File
@@ -1,17 +0,0 @@
version: 2
updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: monthly
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
open-pull-requests-limit: 10
- package-ecosystem: npm
directory: /ui
open-pull-requests-limit: 10
schedule:
interval: monthly
+20 -46
View File
@@ -1,71 +1,45 @@
name: build image name: build
on: on:
push: push:
branches: branches: [dev, main]
- dev pull_request:
- main
workflow_dispatch: workflow_dispatch:
pull_request_review:
types: [submitted]
jobs: jobs:
build: build:
name: Build and test
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Build
if: github.event_name != 'pull_request_review' || github.event.review.state == 'approved'
steps: steps:
- name: Checkout - uses: actions/checkout@v5
uses: actions/checkout@v5 - name: Prepare Docker build context
- name: Set up docker image context run: ./scripts/ci_helper.sh prepare
run: | - uses: docker/setup-buildx-action@v3
./scripts/ci_helper.sh prepare - uses: docker/build-push-action@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build docker image
uses: docker/build-push-action@v6
with: with:
context: ${{ env.DOCKER_BUILD_CONTEXT_DIR }} context: ${{ env.DOCKER_BUILD_CONTEXT_DIR }}
file: ${{ env.DOCKER_BUILD_CONTEXT_DIR }}/Dockerfile.build file: ${{ env.DOCKER_BUILD_CONTEXT_DIR }}/Dockerfile.build
tags: ${{ env.DOCKER_BUILD_TAG }} tags: ${{ env.DOCKER_BUILD_TAG }}
push: false push: false
load: true load: true
- name: Set up Cmake cache - uses: actions/cache@v5
uses: actions/cache@v5
with: with:
path: internal/native/cgo/build path: internal/native/cgo/build
key: jetkvm-cgo-${{ hashFiles('internal/native/cgo/**/*.c', 'internal/native/cgo/**/*.h', 'internal/native/cgo/**/*.patch', 'internal/native/cgo/**/*.txt', 'internal/native/cgo/**/*.sh', '!internal/native/cgo/build/**') }} key: jetkvm-cgo-${{ hashFiles('internal/native/cgo/**/*.c', 'internal/native/cgo/**/*.h', 'internal/native/cgo/**/*.patch', 'internal/native/cgo/**/*.txt', 'internal/native/cgo/**/*.sh', '!internal/native/cgo/build/**') }}
restore-keys: | restore-keys: jetkvm-cgo-
jetkvm-cgo-${{ hashFiles('internal/native/cgo/**/*.c', 'internal/native/cgo/**/*.h', 'internal/native/cgo/**/*.patch', 'internal/native/cgo/**/*.txt', 'internal/native/cgo/**/*.sh', '!internal/native/cgo/build/**') }} - uses: actions/setup-node@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with: with:
node-version: "22" node-version: "22"
cache: "npm" cache: npm
cache-dependency-path: "**/package-lock.json" cache-dependency-path: "**/package-lock.json"
- name: Set up Golang - uses: actions/setup-go@v6
uses: actions/setup-go@v6
with: with:
go-version: "^1.25.1" go-version: "^1.25.1"
- name: Build frontend - name: Build frontend
run: | run: make frontend
make frontend - name: Build application
- name: Build application inside Docker container run: ./scripts/ci_helper.sh make build_dev
run: |
./scripts/ci_helper.sh make build_dev
- name: Run tests - name: Run tests
run: | run: go test ./... -json > testreport.json
go test ./... -json > testreport.json - uses: becheran/go-testreport@v0.3.2
- name: Make test cases
run: |
./scripts/ci_helper.sh make build_dev_test
- name: Golang Test Report
uses: becheran/go-testreport@v0.3.2
with: with:
input: "testreport.json" input: testreport.json
- name: Upload artifact
uses: actions/upload-artifact@v6
with:
name: jetkvm-app
path: |
bin/jetkvm_app
device-tests.tar.gz
-37
View File
@@ -1,37 +0,0 @@
---
name: golangci-lint
on:
push:
paths:
- "go.sum"
- "go.mod"
- "**.go"
- ".github/workflows/golangci-lint.yml"
- ".golangci.yml"
pull_request:
permissions: # added using https://github.com/step-security/secure-repo
contents: read
jobs:
golangci:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: "^1.25.1"
- name: Create empty resource directory
run: |
mkdir -p static && touch static/.gitkeep
- name: Lint
uses: golangci/golangci-lint-action@v8
with:
args: --verbose
version: v2.4
+41
View File
@@ -0,0 +1,41 @@
name: lint
on:
push:
branches: [dev, main]
pull_request:
permissions:
contents: read
jobs:
go:
name: Go
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: "^1.25.1"
- run: mkdir -p static && touch static/.gitkeep
- uses: golangci/golangci-lint-action@v8
with:
args: --verbose
version: v2.4
ui:
name: UI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: "22"
cache: npm
cache-dependency-path: "**/package-lock.json"
- run: npm ci
working-directory: ui
- run: npm run lint
working-directory: ui
-174
View File
@@ -1,174 +0,0 @@
name: smoketest
on:
repository_dispatch:
types: [smoketest]
jobs:
ghbot_payload:
name: Ghbot payload
runs-on: ubuntu-latest
steps:
- name: "GH_CHECK_RUN_ID=${{ github.event.client_payload.check_run_id }}"
run: |
echo "== START GHBOT_PAYLOAD =="
cat <<'GHPAYLOAD_EOF' | base64
${{ toJson(github.event.client_payload) }}
GHPAYLOAD_EOF
echo "== END GHBOT_PAYLOAD =="
deploy_and_test:
runs-on: buildjet-4vcpu-ubuntu-2204
name: Smoke test
concurrency:
group: smoketest-jk
steps:
- name: Download artifact
run: |
wget -O /tmp/jk.zip "${{ github.event.client_payload.artifact_download_url }}"
unzip /tmp/jk.zip
- name: Configure WireGuard and check connectivity
run: |
WG_KEY_FILE=$(mktemp)
echo -n "$CI_WG_PRIVATE" > $WG_KEY_FILE && \
sudo apt-get update && sudo apt-get install -y wireguard-tools && \
sudo ip link add dev wg-ci type wireguard && \
sudo ip addr add $CI_WG_IPS dev wg-ci && \
sudo wg set wg-ci listen-port 51820 \
private-key $WG_KEY_FILE \
peer $CI_WG_PUBLIC \
allowed-ips $CI_WG_ALLOWED_IPS \
endpoint $CI_WG_ENDPOINT \
persistent-keepalive 15 && \
sudo ip link set up dev wg-ci && \
sudo ip r r $CI_HOST via $CI_WG_GATEWAY dev wg-ci
ping -c1 $CI_HOST || (echo "Failed to ping $CI_HOST" && sudo wg show wg-ci && ip r && exit 1)
env:
CI_HOST: ${{ vars.JETKVM_CI_HOST }}
CI_WG_IPS: ${{ vars.JETKVM_CI_WG_IPS }}
CI_WG_GATEWAY: ${{ vars.JETKVM_CI_GATEWAY }}
CI_WG_ALLOWED_IPS: ${{ vars.JETKVM_CI_WG_ALLOWED_IPS }}
CI_WG_PUBLIC: ${{ secrets.JETKVM_CI_WG_PUBLIC }}
CI_WG_PRIVATE: ${{ secrets.JETKVM_CI_WG_PRIVATE }}
CI_WG_ENDPOINT: ${{ secrets.JETKVM_CI_WG_ENDPOINT }}
- name: Configure SSH
run: |
# Write SSH private key to a file
SSH_PRIVATE_KEY=$(mktemp)
echo "$CI_SSH_PRIVATE" > $SSH_PRIVATE_KEY
chmod 0600 $SSH_PRIVATE_KEY
# Configure SSH
mkdir -p ~/.ssh
cat <<EOF >> ~/.ssh/config
Host jkci
HostName $CI_HOST
User $CI_USER
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
IdentityFile $SSH_PRIVATE_KEY
EOF
env:
CI_USER: ${{ vars.JETKVM_CI_USER }}
CI_HOST: ${{ vars.JETKVM_CI_HOST }}
CI_SSH_PRIVATE: ${{ secrets.JETKVM_CI_SSH_PRIVATE }}
- name: Run tests
run: |
set -e
echo "+ Copying device-tests.tar.gz to remote host"
ssh jkci "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz
echo "+ Running go tests"
ssh jkci ash << 'EOF'
set -e
TMP_DIR=$(mktemp -d)
cd ${TMP_DIR}
tar zxf /tmp/device-tests.tar.gz
./gotestsum --format=testdox \
--jsonfile=/tmp/device-tests.json \
--post-run-command 'sh -c "echo $TESTS_FAILED > /tmp/device-tests.failed"' \
--raw-command -- ./run_all_tests -json
GOTESTSUM_EXIT_CODE=$?
if [ $GOTESTSUM_EXIT_CODE -ne 0 ]; then
echo "❌ Tests failed (exit code: $GOTESTSUM_EXIT_CODE)"
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
exit 1
fi
TESTS_FAILED=$(cat /tmp/device-tests.failed)
if [ "$TESTS_FAILED" -ne 0 ]; then
echo "❌ Tests failed $TESTS_FAILED tests failed"
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
exit 1
fi
echo "✅ Tests passed"
rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz
EOF
ssh jkci "cat /tmp/device-tests.json" > device-tests.json
- name: Set up Golang
uses: actions/setup-go@v6
with:
go-version: "1.24.4"
- name: Golang Test Report
uses: becheran/go-testreport@v0.3.2
with:
input: "device-tests.json"
- name: Deploy application
run: |
set -e
# Copy the binary to the remote host
echo "+ Copying the application to the remote host"
cat bin/jetkvm_app | gzip | ssh jkci "cat > /userdata/jetkvm/jetkvm_app.update.gz"
# Deploy and run the application on the remote host
echo "+ Deploying the application on the remote host"
ssh jkci ash <<EOF
# Extract the binary
gzip -d /userdata/jetkvm/jetkvm_app.update.gz
# Flush filesystem buffers to ensure all data is written to disk
sync
# Clear the filesystem caches to force a read from disk
echo 1 > /proc/sys/vm/drop_caches
# Reboot the application
reboot -d 5 -f &
EOF
sleep 10
echo "Deployment complete, waiting for JetKVM to come back online "
function check_online() {
for i in {1..60}; do
if ping -c1 -w1 -W1 -q $CI_HOST >/dev/null; then
echo "JetKVM is back online"
return 0
fi
echo -n "."
sleep 1
done
echo "JetKVM did not come back online within 60 seconds"
return 1
}
check_online
env:
CI_HOST: ${{ vars.JETKVM_CI_HOST }}
- name: Run smoke tests
run: |
echo "+ Checking the status of the device"
curl -v http://$CI_HOST/device/status && echo
echo "+ Waiting for 15 seconds to allow all services to start"
sleep 15
echo "+ Collecting logs"
local_log_tar=$(mktemp)
ssh jkci ash > $local_log_tar <<'EOF'
log_path=$(mktemp -d)
dmesg > $log_path/dmesg.log
cp /userdata/jetkvm/last.log $log_path/last.log
tar -czf - -C $log_path .
EOF
tar -xf $local_log_tar
cat dmesg.log last.log
env:
CI_HOST: ${{ vars.JETKVM_CI_HOST }}
- name: Upload logs
uses: actions/upload-artifact@v6
with:
name: device-logs
path: |
last.log
dmesg.log
device-tests.json
-100
View File
@@ -1,100 +0,0 @@
name: Close stale issues and PRs (dry-run)
on:
schedule:
- cron: '30 1 * * *' # Runs daily at 01:30 UTC
workflow_dispatch: # Allow manual runs from the Actions tab
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
with:
# ──────────────────────────────────────────────────────────────────────
# OVERVIEW — HOW THIS WORKS
# 1) The job scans issues/PRs once per run.
# 2) If an item has had no activity for `days-before-stale`, its labeled `Stale`
# and receives the relevant “stale” comment.
# 3) If theres still no activity for `days-before-close` AFTER being marked
# stale, the item is closed and receives a closing comment.
# 4) Any new activity (comment, label change, commit, edit) clears `Stale`
# and resets the timers if `remove-stale-when-updated` is true.
# ──────────────────────────────────────────────────────────────────────
# ── TIMING / BEHAVIOR ────────────────────────────────────────────────
# Number of idle days before applying the `Stale` label + stale comment.
days-before-stale: 60
# Number of days AFTER staling with no activity before auto-closing.
# (Measured from when `Stale` was added.) Set to -1 to never auto-close.
days-before-close: 14
# If someone comments/updates, automatically remove `Stale` and reset timers.
remove-stale-when-updated: true
# Dont nag draft PRs; they are explicitly a work-in-progress stage.
exempt-draft-pr: true
# Fetch ordering when scanning items. `updated` helps focus on the most recently touched.
sort-by: updated
# ── MESSAGES (markdown) ──────────────────────────────────────────────
stale-issue-message: |
**This issue has been inactive for 60 days and is now marked as stale.**
To keep the tracker focused, older inactive issues are flagged.
If this still applies:
- Add a comment with **reproduction steps**, **environment details**, and **JetKVM version**.
- Verify whether it still occurs with the current build: see [OTA / Updates](https://jetkvm.com/docs/advanced-usage/ota-updates).
- Any new comment or update will remove the *Stale* label automatically.
Issues not updated within 14 days after being marked stale may be closed.
stale-pr-message: |
**This pull request has been inactive for 60 days and is now marked as stale.**
To continue:
- Push a commit or add a comment about next steps — this removes the *Stale* label automatically.
- Ensure the changes work with the current build: see [OTA / Updates](https://jetkvm.com/docs/advanced-usage/ota-updates).
- If this is blocked or awaiting review, mention that for visibility.
PRs not updated within 14 days after being marked stale may be closed.
close-issue-message: |
**Closing this issue due to extended inactivity.**
It has been 14 days since it was marked as stale without further updates.
If the problem persists:
- Reopen this issue, or open a new one with **reproduction steps**, **logs**, **environment**, and **JetKVM version**.
- Confirm behavior with the current build: [OTA / Updates](https://jetkvm.com/docs/advanced-usage/ota-updates).
close-pr-message: |
**Closing this pull request due to extended inactivity.**
It has been 14 days since it was marked as stale with no updates or commits.
If the changes are still relevant:
- Reopen this PR or submit a refreshed PR rebased on the latest code.
- Confirm that it builds and works with the current build: [OTA / Updates](https://jetkvm.com/docs/advanced-usage/ota-updates).
# ── SAFETY / ROLLOUT ────────────────────────────────────────────────
# DRY-RUN: log what would happen, but do NOT write labels/comments/close.
debug-only: true
# Print a summary of how many items were staled/closed (or would be, in dry-run).
enable-statistics: true
# Limit GitHub API operations per run (gentle start for large repos).
# Increase later (e.g., 2001000) once youre confident with behavior.
operations-per-run: 50
# ── LABELS ───────────────────────────────────────────────────────────
# Names of the labels applied when staling items. Defaults shown for clarity.
stale-issue-label: 'Stale'
stale-pr-label: 'Stale'
-34
View File
@@ -1,34 +0,0 @@
---
name: ui-lint
on:
push:
paths:
- "ui/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/ui-lint.yml"
permissions:
contents: read
jobs:
ui-lint:
name: UI Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "npm"
cache-dependency-path: "**/package-lock.json"
- name: Install dependencies
run: |
cd ui
npm ci
- name: Lint UI
run: |
cd ui
npm run lint