mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 13:35:12 +09:00
Issue #101 shipped because release.yml went straight from `build` to `push` with nothing in between. The image was missing scripts/, so every containerised panel 404'd its own enrollment URL, while the entire test suite stayed green -- pytest runs against the source tree, where the file always exists. Only booting the artifact catches that class of bug. scripts/test/smoke-docker-image.sh builds (or takes) an image, asserts the files the panel reads at request time are present, boots it, and requests every route that serves a file off disk. release.yml now builds amd64, runs it, and only then pushes multi-arch (layers are cached, so the push reuses the build). release-smoke.yml gets the same job on dev and PRs, and its path filters now include Dockerfile, .dockerignore and scripts/ -- none of which used to trigger it. scripts/test/verify-agent-release-chain.sh covers the other half, which unit tests structurally cannot: they stub curl, so they only ever prove the installer is self-consistent, never that the URL it builds resolves to a real file. This one reads the coordinates back out of the script, asks GitHub, downloads the archive, verifies the checksum and confirms the tarball entry name the installer moves. It runs nightly, and is also the tripwire for the reverse case -- the agent repo changing its release naming and breaking the panel from the other side of the repo split. Both are plain scripts so the same check runs locally: bash scripts/test/smoke-docker-image.sh bash scripts/test/verify-agent-release-chain.sh Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
277 lines
8.7 KiB
YAML
277 lines
8.7 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- 'v*'
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: 'Version to release (e.g., 1.6.24)'
|
|
required: true
|
|
type: string
|
|
prerelease:
|
|
description: 'Mark as pre-release'
|
|
type: boolean
|
|
default: false
|
|
|
|
concurrency:
|
|
group: release-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
env:
|
|
DOCKER_IMAGE: jhd3197/serverkit
|
|
|
|
jobs:
|
|
ci-gate:
|
|
name: CI Gate
|
|
uses: ./.github/workflows/backend-ci.yml
|
|
|
|
version:
|
|
name: Resolve Version
|
|
runs-on: ubuntu-latest
|
|
needs: ci-gate
|
|
outputs:
|
|
version: ${{ steps.version.outputs.version }}
|
|
tag: ${{ steps.version.outputs.tag }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Get version
|
|
id: version
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
VERSION="${{ github.event.inputs.version }}"
|
|
elif [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref_type }}" = "tag" ]; then
|
|
VERSION="${GITHUB_REF#refs/tags/v}"
|
|
else
|
|
VERSION=$(cat VERSION | tr -d '[:space:]')
|
|
fi
|
|
TAG="v$VERSION"
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
echo "Releasing ServerKit version: $VERSION"
|
|
|
|
- name: Create and push tag
|
|
if: github.event_name == 'push' && github.ref_type != 'tag'
|
|
run: |
|
|
TAG="${{ steps.version.outputs.tag }}"
|
|
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
|
echo "Tag $TAG already exists, skipping"
|
|
else
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git tag -a "$TAG" -m "Release $TAG"
|
|
git push origin "$TAG"
|
|
fi
|
|
|
|
build-release:
|
|
name: Build Release Tarball
|
|
runs-on: ${{ matrix.runner }}
|
|
needs: version
|
|
strategy:
|
|
fail-fast: true
|
|
matrix:
|
|
include:
|
|
- runner: ubuntu-latest
|
|
arch: amd64
|
|
- runner: ubuntu-24.04-arm
|
|
arch: arm64
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Install build dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y python3-venv python3-pip rsync
|
|
|
|
- name: Build release tarball
|
|
env:
|
|
BUILD_ARCH: ${{ matrix.arch }}
|
|
run: bash scripts/build-release.sh
|
|
|
|
- name: Upload release artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: serverkit-release-${{ matrix.arch }}
|
|
path: |
|
|
serverkit-*.tar.gz
|
|
checksums.txt
|
|
if-no-files-found: error
|
|
|
|
build-docker:
|
|
name: Build Docker Image
|
|
runs-on: ubuntu-latest
|
|
needs: version
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
continue-on-error: true
|
|
|
|
# Build amd64 first and boot it before anything is published. Issue #101
|
|
# shipped because this job went straight from `build` to `push`: the image
|
|
# was missing scripts/, so /api/v1/servers/install.sh 404'd in every
|
|
# container while the whole test suite stayed green (pytest runs against
|
|
# the source tree, where the file always exists). Only booting the artifact
|
|
# catches that. The layers are cached, so the multi-arch push below reuses
|
|
# this build rather than repeating it.
|
|
- name: Build amd64 image for smoke test
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64
|
|
push: false
|
|
load: true
|
|
tags: serverkit:smoke
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
build-args: |
|
|
VERSION=${{ needs.version.outputs.version }}
|
|
BUILD_TIME=${{ github.event.repository.updated_at }}
|
|
GIT_COMMIT=${{ github.sha }}
|
|
|
|
- name: Smoke test the built image
|
|
run: SKIP_BUILD=1 bash scripts/test/smoke-docker-image.sh serverkit:smoke
|
|
|
|
- name: Build and push Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64,linux/arm64
|
|
push: ${{ secrets.DOCKERHUB_USERNAME != '' }}
|
|
cache-from: type=gha
|
|
tags: |
|
|
${{ env.DOCKER_IMAGE }}:latest
|
|
${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.version }}
|
|
build-args: |
|
|
VERSION=${{ needs.version.outputs.version }}
|
|
BUILD_TIME=${{ github.event.repository.updated_at }}
|
|
GIT_COMMIT=${{ github.sha }}
|
|
|
|
release:
|
|
name: Create Release
|
|
runs-on: ubuntu-latest
|
|
needs: [version, build-docker, build-release]
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download release artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: release-artifacts
|
|
pattern: serverkit-release-*
|
|
merge-multiple: true
|
|
|
|
- name: Assemble release files
|
|
run: |
|
|
mkdir -p release
|
|
cp VERSION release/VERSION
|
|
cp docker-compose.yml release/docker-compose.yml
|
|
cp Dockerfile release/Dockerfile
|
|
mv release-artifacts/serverkit-*.tar.gz release/ 2>/dev/null || true
|
|
mv release-artifacts/checksums.txt release/checksums.txt 2>/dev/null || true
|
|
cd release
|
|
sha256sum serverkit-*.tar.gz >> checksums.txt
|
|
sort -u checksums.txt -o checksums.txt
|
|
cat checksums.txt
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ needs.version.outputs.tag }}
|
|
name: ServerKit ${{ needs.version.outputs.tag }}
|
|
draft: false
|
|
prerelease: ${{ github.event.inputs.prerelease == 'true' }}
|
|
files: |
|
|
release/*
|
|
body: |
|
|
## ServerKit ${{ needs.version.outputs.tag }}
|
|
|
|
ServerKit is a server control panel for managing web applications, databases, Docker containers, and security on VPS/dedicated servers.
|
|
|
|
### Docker
|
|
|
|
```bash
|
|
docker pull ${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.version }}
|
|
docker pull ${{ env.DOCKER_IMAGE }}:latest
|
|
```
|
|
|
|
### One-line installer
|
|
|
|
```bash
|
|
curl -fsSL https://serverkit.ai/install.sh | bash
|
|
```
|
|
|
|
### Quick Start
|
|
|
|
```bash
|
|
git clone https://github.com/${{ github.repository }}.git
|
|
cd ServerKit
|
|
docker compose up -d
|
|
```
|
|
|
|
Default credentials: `admin` / `admin`
|
|
|
|
### What's New
|
|
|
|
See [CHANGELOG](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details.
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
summary:
|
|
name: Release Summary
|
|
runs-on: ubuntu-latest
|
|
needs: [version, release]
|
|
|
|
steps:
|
|
- name: Create summary
|
|
run: |
|
|
echo "## ServerKit Release Summary" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Version:** ${{ needs.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### Docker" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Tag | Image |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|-----|-------|" >> $GITHUB_STEP_SUMMARY
|
|
echo "| latest | ${{ env.DOCKER_IMAGE }}:latest |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| ${{ needs.version.outputs.version }} | ${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.version }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### Release" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "Tarballs: serverkit-${{ needs.version.outputs.tag }}-linux-amd64.tar.gz, serverkit-${{ needs.version.outputs.tag }}-linux-arm64.tar.gz" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "Release created at: https://github.com/${{ github.repository }}/releases/tag/${{ needs.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
|