CI / Build & Test (push) Successful in 2m46s
Split host.js (435 lines) into host/{paths,logger,startup,message-router}.js.
Split holesail-manager.js (698 lines) into holesail-manager/{state,settings,
connections,port-allocator,servers,virtual-hosts,service-tunnels,index}.js.
Top-level host.js and holesail-manager.js become thin shims so index.mjs
requires no changes. Deleted dev scratch file test-cp.mjs.
Updated CI with 12 new node --check lines for all sub-modules.
Updated docs/ARCHITECTURE.md with per-file tables for host/ and
holesail-manager/ sub-modules.
No functionality changed. No new dependencies.
242 lines
9.8 KiB
YAML
242 lines
9.8 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
|
|
jobs:
|
|
ci:
|
|
name: Build & Test
|
|
runs-on: ssh
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
token: ${{ secrets.RELEASE_TOKEN }}
|
|
|
|
- name: Check toolchain versions
|
|
run: |
|
|
node --version
|
|
npm --version
|
|
bare --version 2>/dev/null || echo "bare not in PATH (ok)"
|
|
|
|
- name: Install root dependencies
|
|
run: npm install
|
|
|
|
- name: Install native-host dependencies
|
|
run: npm install
|
|
working-directory: native-host
|
|
|
|
- name: Lint — syntax check extension
|
|
run: |
|
|
node --check extension/background.js
|
|
node --check extension/background/logs.js
|
|
node --check extension/background/state.js
|
|
node --check extension/background/proxy.js
|
|
node --check extension/background/native-messaging.js
|
|
node --check extension/background/tab-lifecycle.js
|
|
node --check extension/background/message-router.js
|
|
node --check extension/dashboard/data/tlds.js
|
|
node --check extension/dashboard/data/hostname-validator.js
|
|
node --check extension/dashboard/core/utils.js
|
|
node --check extension/dashboard/core/state.js
|
|
node --check extension/dashboard/core/messaging.js
|
|
node --check extension/dashboard/core/navigation.js
|
|
node --check extension/dashboard/core/init.js
|
|
node --check extension/dashboard/ui/toast.js
|
|
node --check extension/dashboard/ui/modal.js
|
|
node --check extension/dashboard/ui/state-tag.js
|
|
node --check extension/dashboard/pages/overview.js
|
|
node --check extension/dashboard/pages/virtual-hosts.js
|
|
node --check extension/dashboard/pages/servers.js
|
|
node --check extension/dashboard/pages/service-tunnels.js
|
|
node --check extension/dashboard/pages/proxy-ca.js
|
|
node --check extension/dashboard/pages/backups.js
|
|
node --check extension/dashboard/pages/settings.js
|
|
node --check extension/dashboard/pages/ssh.js
|
|
node --check extension/dashboard/pages/rdp.js
|
|
node --check extension/dashboard/pages/logs.js
|
|
node --check extension/dashboard/refresh.js
|
|
node --check extension/dashboard/events.js
|
|
|
|
- name: Lint — syntax check native host
|
|
run: |
|
|
node --check native-host/host.js
|
|
node --check native-host/holesail-manager.js
|
|
node --check native-host/ssh-manager.js
|
|
node --check native-host/rdp-manager.js
|
|
node --check native-host/backup-manager.js
|
|
node --check native-host/certificate-authority.js
|
|
node --check native-host/https-proxy.js
|
|
node --check native-host/connect-proxy.js
|
|
node --check native-host/messenger.js
|
|
node --check native-host/host/paths.js
|
|
node --check native-host/host/logger.js
|
|
node --check native-host/host/startup.js
|
|
node --check native-host/host/message-router.js
|
|
node --check native-host/holesail-manager/state.js
|
|
node --check native-host/holesail-manager/settings.js
|
|
node --check native-host/holesail-manager/connections.js
|
|
node --check native-host/holesail-manager/port-allocator.js
|
|
node --check native-host/holesail-manager/servers.js
|
|
node --check native-host/holesail-manager/virtual-hosts.js
|
|
node --check native-host/holesail-manager/service-tunnels.js
|
|
node --check native-host/holesail-manager/index.js
|
|
|
|
- name: Lint — syntax check build scripts
|
|
run: |
|
|
node --check scripts/build-distributable.js
|
|
node --check scripts/pack-extension.js
|
|
node --check scripts/build-host.js
|
|
|
|
- name: Pack extension
|
|
run: npm run pack
|
|
|
|
- name: Build all platform binaries
|
|
run: node scripts/build-distributable.js --all --package
|
|
|
|
- name: Smoke test — run native binary for current platform
|
|
run: |
|
|
PLAT=$(node -e "process.stdout.write(process.platform)")
|
|
ARCH=$(node -e "process.stdout.write(process.arch === 'arm64' ? 'arm64' : 'x64')")
|
|
HOST="${PLAT}-${ARCH}"
|
|
echo "Runner platform: $HOST"
|
|
|
|
BIN=""
|
|
for candidate in \
|
|
"releases/${HOST}/holesail-browser-host" \
|
|
"releases/${HOST}/holesail-browser-host.exe"; do
|
|
if [ -f "$candidate" ]; then
|
|
BIN="$candidate"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -z "$BIN" ]; then
|
|
echo "No binary found for $HOST — listing releases/:"
|
|
find releases/ -type f | sort
|
|
echo "SKIP: no runnable binary for this platform"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Testing binary: $BIN"
|
|
chmod +x "$BIN"
|
|
OUTPUT=$(timeout 6 "$BIN" 2>&1 || true)
|
|
echo "$OUTPUT"
|
|
|
|
if echo "$OUTPUT" | grep -q "\[holesail-browser-host\] ready"; then
|
|
echo "PASS: binary started successfully"
|
|
else
|
|
echo "FAIL: binary did not print ready signal"
|
|
exit 1
|
|
fi
|
|
|
|
if echo "$OUTPUT" | grep -qi "not available"; then
|
|
echo "WARN: one or more optional modules unavailable (non-fatal):"
|
|
echo "$OUTPUT" | grep -i "not available"
|
|
fi
|
|
|
|
echo "PASS: smoke test complete"
|
|
|
|
- name: Generate checksums
|
|
run: |
|
|
cd releases
|
|
find . -name "*.zip" -o -name "*.xpi" | sort | xargs sha256sum > SHA256SUMS.txt
|
|
cat SHA256SUMS.txt
|
|
|
|
- name: List artifacts
|
|
run: |
|
|
echo "=== All release artifacts ==="
|
|
find releases/ -type f | sort
|
|
echo ""
|
|
find releases/ -type f -exec ls -lh {} \; | awk '{print $5, $9}'
|
|
|
|
- name: Publish rolling release
|
|
if: github.event_name == 'push'
|
|
run: |
|
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
|
TAG="latest-main"
|
|
TITLE="Latest build (main @ ${SHORT_SHA})"
|
|
COMMIT_MSG=$(echo "${{ github.event.head_commit.message }}" | sed '/^Made-with:/d' | sed '/^$/d' | head -1)
|
|
BODY="Automated build from \`main\` branch.\n\n**Commit:** \`${{ github.sha }}\`\n**Message:** ${COMMIT_MSG}\n\nThis release is updated on every push to main and always contains the latest artifacts."
|
|
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
|
AUTH="Authorization: token ${{ secrets.RELEASE_TOKEN }}"
|
|
|
|
# Force-move the git tag using git directly.
|
|
# Set remote URL with token so we can push.
|
|
REPO_URL=$(git remote get-url origin | sed 's|https://|https://x-token:${{ secrets.RELEASE_TOKEN }}@|')
|
|
git remote set-url origin "${REPO_URL}"
|
|
git config user.email "ci@holesail-browser"
|
|
git config user.name "CI"
|
|
git tag -f "${TAG}" "${{ github.sha }}"
|
|
git push origin "refs/tags/${TAG}" --force
|
|
echo "Tag ${TAG} force-pushed to ${{ github.sha }}"
|
|
|
|
# Get existing release by tag (if any)
|
|
EXISTING=$(curl -s -H "$AUTH" "${API}/releases/tags/${TAG}")
|
|
RELEASE_ID=$(echo "$EXISTING" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{try{const r=JSON.parse(d);console.log(r.id||'')}catch{console.log('')}})")
|
|
echo "Existing release ID: $RELEASE_ID"
|
|
|
|
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "null" ] && [ "$RELEASE_ID" != "" ]; then
|
|
# Update the existing release title, body and target commit
|
|
curl -s -X PATCH \
|
|
-H "$AUTH" -H "Content-Type: application/json" \
|
|
"${API}/releases/${RELEASE_ID}" \
|
|
-d "{
|
|
\"name\": \"${TITLE}\",
|
|
\"body\": \"${BODY}\",
|
|
\"prerelease\": true,
|
|
\"target_commitish\": \"${{ github.sha }}\"
|
|
}"
|
|
echo "Updated release ${RELEASE_ID}"
|
|
|
|
# Delete all existing assets so we can re-upload fresh ones
|
|
ASSETS=$(curl -s -H "$AUTH" "${API}/releases/${RELEASE_ID}/assets")
|
|
echo "$ASSETS" | node -e "
|
|
let d='';
|
|
process.stdin.on('data',c=>d+=c).on('end',()=>{
|
|
try {
|
|
const assets = JSON.parse(d);
|
|
if (Array.isArray(assets)) assets.forEach(a => console.log(a.id));
|
|
} catch(_) {}
|
|
})" | while read ASSET_ID; do
|
|
[ -z "$ASSET_ID" ] && continue
|
|
echo "Deleting asset $ASSET_ID..."
|
|
curl -s -X DELETE -H "$AUTH" "${API}/releases/${RELEASE_ID}/assets/${ASSET_ID}"
|
|
done
|
|
else
|
|
# Create a brand new release
|
|
RELEASE_ID=$(curl -s -X POST \
|
|
-H "$AUTH" -H "Content-Type: application/json" \
|
|
"${API}/releases" \
|
|
-d "{
|
|
\"tag_name\": \"${TAG}\",
|
|
\"name\": \"${TITLE}\",
|
|
\"body\": \"${BODY}\",
|
|
\"prerelease\": true,
|
|
\"target_commitish\": \"${{ github.sha }}\"
|
|
}" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{try{console.log(JSON.parse(d).id)}catch{console.log('')}})")
|
|
echo "Created release ${RELEASE_ID}"
|
|
fi
|
|
|
|
# Upload all fresh artifacts
|
|
for FILE in releases/*.zip releases/*.xpi releases/SHA256SUMS.txt; do
|
|
[ -f "$FILE" ] || continue
|
|
NAME=$(basename "$FILE")
|
|
echo "Uploading $NAME..."
|
|
curl -s -X POST \
|
|
-H "$AUTH" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
"${API}/releases/${RELEASE_ID}/assets?name=${NAME}" \
|
|
--data-binary "@${FILE}"
|
|
echo ""
|
|
done
|
|
|
|
echo "Done — release ${TAG} updated to ${{ github.sha }}"
|