diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml new file mode 100644 index 0000000..7eefa86 --- /dev/null +++ b/.gitea/workflows/docker.yml @@ -0,0 +1,87 @@ +name: Docker + +# Publishes the container image (linux/amd64 and linux/arm64): +# push to main -> :edge and :sha- +# tag v1.2.3 -> :1.2.3, :1.2 and :latest (pre-releases like v1.2.3-rc1 get only :1.2.3-rc1) +# Run it by hand from the Actions tab to rebuild the current branch. +# +# Settings (all optional): +# secret REGISTRY_TOKEN access token with package write permission, if the job token can't push +# variable REGISTRY_USER user for that token (defaults to the person who triggered the run) +# variable MIRROR_IMAGE also push to another registry, e.g. ghcr.io/you/spinner or docker.io/you/spinner +# secret MIRROR_TOKEN and variable MIRROR_USER: login for that registry +# variable PUBLISH_DOCKER set to "false" to skip this workflow +on: + push: + branches: [main] + tags: ['v*'] + workflow_dispatch: + +jobs: + image: + if: ${{ vars.PUBLISH_DOCKER != 'false' }} + runs-on: ubuntu-latest + env: + GOPRIVATE: git.veillax.com + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Let Go fetch modules from this server + run: git config --global url."https://x-access-token:${{ secrets.GITHUB_TOKEN }}@git.veillax.com/".insteadOf "https://git.veillax.com/" + + - name: Test + run: | + go vet ./... + go test ./... + + # The Dockerfile packages these binaries, so the image needs no Go toolchain or emulation. + - name: Build the binaries + env: + TARGETS: linux/amd64 linux/arm64 + run: sh deploy/build.sh + + - name: Log in + env: + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN || secrets.GITHUB_TOKEN }} + REGISTRY_USER: ${{ vars.REGISTRY_USER || github.actor }} + MIRROR_IMAGE: ${{ vars.MIRROR_IMAGE }} + MIRROR_USER: ${{ vars.MIRROR_USER }} + MIRROR_TOKEN: ${{ secrets.MIRROR_TOKEN }} + run: | + host=${GITHUB_SERVER_URL#*://} + echo "$REGISTRY_TOKEN" | docker login "$host" -u "$REGISTRY_USER" --password-stdin + if [ -n "$MIRROR_IMAGE" ]; then + echo "$MIRROR_TOKEN" | docker login "${MIRROR_IMAGE%%/*}" -u "$MIRROR_USER" --password-stdin + fi + + - name: Build and push + env: + MIRROR_IMAGE: ${{ vars.MIRROR_IMAGE }} + run: | + host=${GITHUB_SERVER_URL#*://} + owner=$(echo "$GITHUB_REPOSITORY_OWNER" | tr 'A-Z' 'a-z') + images="$host/$owner/spinner" + [ -n "$MIRROR_IMAGE" ] && images="$images $MIRROR_IMAGE" + + if [ "$GITHUB_REF_TYPE" = tag ]; then + v=${GITHUB_REF_NAME#v} + tags="$v" + case "$v" in + *-*) ;; # pre-releases don't move :1.2 or :latest + *) tags="$tags ${v%.*} latest" ;; + esac + else + tags="edge sha-$(echo "$GITHUB_SHA" | cut -c1-7)" + fi + + args="" + for i in $images; do for t in $tags; do args="$args -t $i:$t"; done; done + docker buildx create --name spinner --driver docker-container --use >/dev/null 2>&1 || docker buildx use spinner + echo "pushing:$args" + docker buildx build --platform linux/amd64,linux/arm64 $args --push . diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 0c49365..ae9c491 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,6 +1,6 @@ name: Release -# Push a tag such as v0.2.0 to build and publish a release: +# Push a tag such as v0.2.0 to publish a release. The Docker workflow builds the image from the same tag: # git tag -a v0.2.0 -m "spinner v0.2.0" && git push origin v0.2.0 on: push: @@ -37,26 +37,3 @@ jobs: env: TOKEN: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }} run: sh deploy/publish-release.sh "${GITHUB_REF_NAME}" - - # Skipped when the repository variable PUBLISH_DOCKER is "false", or fails alone - # if this runner has no Docker: the release above is already published by then. - # Optional secret REGISTRY_TOKEN (and variable REGISTRY_USER): an access token - # with package write permission, for servers where the job token can't push. - - name: Build and push the container image - if: ${{ vars.PUBLISH_DOCKER != 'false' }} - env: - REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN || secrets.GITHUB_TOKEN }} - REGISTRY_USER: ${{ vars.REGISTRY_USER || github.actor }} - run: | - host=${GITHUB_SERVER_URL#*://} - owner=$(echo "$GITHUB_REPOSITORY_OWNER" | tr 'A-Z' 'a-z') - image="$host/$owner/spinner" - echo "$REGISTRY_TOKEN" | docker login "$host" -u "$REGISTRY_USER" --password-stdin - # a container-driver builder can build several architectures in one go - docker buildx create --name release --driver docker-container --use >/dev/null 2>&1 || docker buildx use release - tags="-t $image:$GITHUB_REF_NAME" - case "$GITHUB_REF_NAME" in - *-*) ;; # pre-releases (v1.0.0-rc1) don't move :latest - *) tags="$tags -t $image:latest" ;; - esac - docker buildx build --platform linux/amd64,linux/arm64 $tags --push . diff --git a/README.md b/README.md index 2a967ab..a8f87b1 100644 --- a/README.md +++ b/README.md @@ -48,24 +48,52 @@ All except `/` need `Authorization: Bearer `. ## Docker +The image is `git.veillax.com/veillax/spinner` for linux/amd64 and linux/arm64. It runs as a non-root user, keeps its config in the `/data` volume, and writes a starter `spinner.json` there on first start. The admin page on port 8080 is the quickest way to add servers; keep it private or behind HTTPS. + +| Tag | Meaning | +| --- | --- | +| `latest` | The newest release | +| `1.2.3`, `1.2` | An exact release, or the newest patch of a minor version | +| `edge` | The latest commit on `main` | +| `sha-` | One specific commit | + +Run it anywhere Docker runs: + ``` -cp .env.example .env # set SPINNER_ADMIN_TOKEN -docker compose -f deploy/docker-compose.yml up -d +docker run -d --name spinner --restart unless-stopped \ + -p 25565:25565 -p 127.0.0.1:8080:8080 \ + -e SPINNER_ADMIN_TOKEN=change-me \ + -v spinner-data:/data \ + git.veillax.com/veillax/spinner:latest ``` -The image is `git.veillax.com/veillax/spinner` (linux/amd64 and linux/arm64). It keeps its config in the `/data` volume and writes a starter `spinner.json` there on first start, so the admin page on port 8080 is the quickest way to add servers. Keep that port private or behind HTTPS. +Or with Compose: `cp .env.example .env`, set `SPINNER_ADMIN_TOKEN`, then `docker compose -f deploy/docker-compose.yml up -d`. Backends on the Docker host are reachable at `host.docker.internal` (add `--add-host host.docker.internal:host-gateway` on Linux), or put Spinner and the Minecraft containers on one Docker network and use their container names. + +If the registry is private, run `docker login git.veillax.com` first. ## Releases -Push a tag to build archives, publish a release and push the image: +Push a tag to publish a release and its image: ``` git tag -a v0.1.0 -m "spinner v0.1.0" && git push origin v0.1.0 ``` -`.gitea/workflows/release.yml` runs `deploy/build.sh`, uploads the archives with `deploy/publish-release.sh`, then builds and pushes the image. Set the repository variable `PUBLISH_DOCKER` to `false` to skip the image. If the job token cannot write releases or packages, add the secrets `RELEASE_TOKEN` and `REGISTRY_TOKEN` (and the variable `REGISTRY_USER`). +Two workflows run on the tag: -To build by hand: `sh deploy/build.sh` puts binaries and archives in `dist/`, then `docker buildx build .` packages the linux binary. +* `.gitea/workflows/release.yml` builds archives with `deploy/build.sh` and uploads them with `deploy/publish-release.sh`. +* `.gitea/workflows/docker.yml` tests, builds both Linux binaries and pushes the image. It also pushes `edge` on every push to `main`, and can be run by hand from the Actions tab. + +Settings, all optional: + +| Name | Kind | Use | +| --- | --- | --- | +| `REGISTRY_TOKEN`, `REGISTRY_USER` | secret, variable | Token with package write permission, if the job token cannot push | +| `RELEASE_TOKEN` | secret | Token that can write releases, if the job token cannot | +| `MIRROR_IMAGE`, `MIRROR_USER`, `MIRROR_TOKEN` | variable, variable, secret | Also push to another registry, for example `ghcr.io/you/spinner` or `docker.io/you/spinner` | +| `PUBLISH_DOCKER` | variable | Set to `false` to skip the image | + +The runner needs Docker with buildx. To build by hand: `sh deploy/build.sh` puts binaries and archives in `dist/`, then `docker buildx build .` packages the linux binary for your platform. ## Not in v1