Add Gitea Actions CI and release workflows and deployment assets
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2e7cb8171f
commit
ffd76b5e8c
12 files changed
+414
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
# The image only packages the binaries that deploy/build.sh already built.
|
||||||
|
*
|
||||||
|
!dist/bin
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GOPRIVATE: git.veillax.com
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
# Go fetches the other sharks modules straight from this server. This is harmless
|
||||||
|
# for public repositories and is what makes private ones work.
|
||||||
|
- 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: Formatting
|
||||||
|
run: |
|
||||||
|
unformatted=$(gofmt -l .)
|
||||||
|
if [ -n "$unformatted" ]; then
|
||||||
|
echo "These files need gofmt:"
|
||||||
|
echo "$unformatted"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Shell scripts parse
|
||||||
|
run: |
|
||||||
|
for f in deploy/*.sh; do sh -n "$f"; done
|
||||||
|
|
||||||
|
- name: Vet
|
||||||
|
run: go vet ./...
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: go test ./...
|
||||||
|
|
||||||
|
# Catches platform-specific breakage before a release is tagged.
|
||||||
|
- name: Every release platform compiles
|
||||||
|
run: |
|
||||||
|
for t in linux/amd64 linux/arm64 linux/arm windows/amd64 darwin/amd64 darwin/arm64; do
|
||||||
|
echo "building for $t"
|
||||||
|
GOOS=${t%/*} GOARCH=${t#*/} GOARM=7 CGO_ENABLED=0 go build -o /dev/null ./cmd/bamboo
|
||||||
|
done
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
# Push a tag such as v0.2.0 to build and publish a release:
|
||||||
|
# git tag -a v0.2.0 -m "bamboo v0.2.0" && git push origin v0.2.0
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ['v*']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GOPRIVATE: git.veillax.com
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # release notes come from the history since the previous tag
|
||||||
|
|
||||||
|
- 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 ./...
|
||||||
|
|
||||||
|
- name: Build release archives
|
||||||
|
run: sh deploy/build.sh "${GITHUB_REF_NAME}"
|
||||||
|
|
||||||
|
# Optional secret RELEASE_TOKEN: an access token that can write releases, for
|
||||||
|
# servers where the automatic job token can't.
|
||||||
|
- name: Publish the release
|
||||||
|
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/bamboo"
|
||||||
|
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 .
|
||||||
@@ -2,3 +2,4 @@ bin/
|
|||||||
*-data/
|
*-data/
|
||||||
.env
|
.env
|
||||||
wg.key
|
wg.key
|
||||||
|
dist/
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
# Packages the binaries deploy/build.sh already built (dist/bin/linux_<arch>/bamboo),
|
||||||
|
# so the arm64 image needs no emulation. Build it with: sh deploy/build.sh && docker buildx build .
|
||||||
|
FROM --platform=$BUILDPLATFORM alpine:3.22 AS prep
|
||||||
|
RUN apk add --no-cache ca-certificates \
|
||||||
|
&& mkdir /data && chown 65532:65532 /data
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
ARG TARGETARCH
|
||||||
|
LABEL org.opencontainers.image.title="Bamboo" \
|
||||||
|
org.opencontainers.image.description="Site agent: connects a private network to the edge over WireGuard" \
|
||||||
|
org.opencontainers.image.source="https://git.veillax.com/Veillax/bamboo" \
|
||||||
|
org.opencontainers.image.licenses="AGPL-3.0-only"
|
||||||
|
COPY --from=prep /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
|
COPY --from=prep --chown=65532:65532 /data /data
|
||||||
|
COPY dist/bin/linux_${TARGETARCH}/bamboo /bamboo
|
||||||
|
USER 65532:65532
|
||||||
|
ENV BAMBOO_DATA=/data
|
||||||
|
VOLUME ["/data"]
|
||||||
|
ENTRYPOINT ["/bamboo"]
|
||||||
@@ -30,6 +30,40 @@ Settings and secrets can live in a `.env` file instead of the command line; see
|
|||||||
- **Docker discovery:** with `-docker`, lists running containers (and their ports and networks) so you can pick one as a target in the dashboard.
|
- **Docker discovery:** with `-docker`, lists running containers (and their ports and networks) so you can pick one as a target in the dashboard.
|
||||||
- **Mail relay:** for a mail egress configured in the dashboard, opens a small SMTP relay on this machine (default `127.0.0.1:2525`). Point your mail server at it (Postfix: `relayhost = [127.0.0.1]:2525`) and each outgoing message leaves from the edge's public IP, so reverse DNS, SPF and your HELO name line up. Supports `AUTH PLAIN/LOGIN`, requires a password if it listens beyond `127.0.0.1`, relays one destination domain per transaction (extra domains get `452` so your server resends them separately), and passes your server's queue and retries through unchanged. 50 MB message limit.
|
- **Mail relay:** for a mail egress configured in the dashboard, opens a small SMTP relay on this machine (default `127.0.0.1:2525`). Point your mail server at it (Postfix: `relayhost = [127.0.0.1]:2525`) and each outgoing message leaves from the edge's public IP, so reverse DNS, SPF and your HELO name line up. Supports `AUTH PLAIN/LOGIN`, requires a password if it listens beyond `127.0.0.1`, relays one destination domain per transaction (extra domains get `452` so your server resends them separately), and passes your server's queue and retries through unchanged. 50 MB message limit.
|
||||||
|
|
||||||
|
## Deploying
|
||||||
|
|
||||||
|
Releases are built by Gitea Actions. Pushing a tag such as `v0.2.0` runs `.gitea/workflows/release.yml`, which tests the code, builds Bamboo for Linux (amd64, arm64, armv7), Windows (amd64) and macOS (amd64, arm64), publishes the archives with a `SHA256SUMS` file on the Releases page, and pushes a multi-architecture container image to this server's registry (`git.veillax.com/veillax/bamboo`). Every push and pull request runs `.gitea/workflows/ci.yml`: formatting, vet, tests, and a check that every release platform still compiles.
|
||||||
|
|
||||||
|
**On a Linux server (systemd)**
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -LO https://git.veillax.com/Veillax/bamboo/releases/download/v0.1.0/bamboo_v0.1.0_linux_amd64.tar.gz
|
||||||
|
curl -LO https://git.veillax.com/Veillax/bamboo/releases/download/v0.1.0/SHA256SUMS
|
||||||
|
sha256sum -c --ignore-missing SHA256SUMS
|
||||||
|
tar xzf bamboo_v0.1.0_linux_amd64.tar.gz && cd bamboo_v0.1.0_linux_amd64
|
||||||
|
sudo ./install.sh # installs the binary and a hardened systemd service
|
||||||
|
sudoedit /etc/bamboo/bamboo.env # your settings and secrets
|
||||||
|
sudo systemctl start bamboo
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `linux_arm64` or `linux_arm` for Raspberry Pi and other ARM machines. To upgrade, repeat the same steps: your settings and data are kept. `sudo ./install.sh --uninstall` removes the service and binary but leaves `/etc/bamboo` and `/var/lib/bamboo` alone. `bamboo -version` tells you which build is running.
|
||||||
|
|
||||||
|
**With Docker**
|
||||||
|
|
||||||
|
```
|
||||||
|
cp .env.example .env # fill it in
|
||||||
|
docker compose -f deploy/docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
The image is `git.veillax.com/veillax/bamboo:<version>` (and `:latest` for full releases). The compose file is in the repository and inside each Linux archive.
|
||||||
|
|
||||||
|
**Setting up the build (once)**
|
||||||
|
|
||||||
|
- A Gitea Actions runner with the label `ubuntu-latest`, and Docker on it if you want the container image.
|
||||||
|
- Nothing else is required: the workflows use the automatic job token. If your server doesn't let that token publish releases or packages, add the secrets `RELEASE_TOKEN` and `REGISTRY_TOKEN` (access tokens with release and package write permission) and optionally the variable `REGISTRY_USER`.
|
||||||
|
- To skip the container image, set the repository variable `PUBLISH_DOCKER` to `false`.
|
||||||
|
- Build locally with `sh deploy/build.sh` (archives in `dist/`).
|
||||||
|
|
||||||
## Build and test
|
## Build and test
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import (
|
|||||||
"git.veillax.com/Veillax/reef/dotenv"
|
"git.veillax.com/Veillax/reef/dotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// version is set at build time (deploy/build.sh).
|
||||||
|
var version = "dev"
|
||||||
|
|
||||||
func env(k, def string) string {
|
func env(k, def string) string {
|
||||||
if v := os.Getenv(k); v != "" {
|
if v := os.Getenv(k); v != "" {
|
||||||
return v
|
return v
|
||||||
@@ -31,11 +34,17 @@ func main() {
|
|||||||
data := flag.String("data", env("BAMBOO_DATA", "./bamboo-data"), "directory for this agent's WireGuard key")
|
data := flag.String("data", env("BAMBOO_DATA", "./bamboo-data"), "directory for this agent's WireGuard key")
|
||||||
dockerOn := flag.Bool("docker", os.Getenv("BAMBOO_DOCKER") == "1", "report local Docker containers so they can be picked as targets in the UI")
|
dockerOn := flag.Bool("docker", os.Getenv("BAMBOO_DOCKER") == "1", "report local Docker containers so they can be picked as targets in the UI")
|
||||||
flag.String("env", ".env", "file to read secrets and settings from")
|
flag.String("env", ".env", "file to read secrets and settings from")
|
||||||
|
showVersion := flag.Bool("version", false, "print the version and exit")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
if *showVersion {
|
||||||
|
os.Stdout.WriteString("bamboo " + version + "\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
if *hh == "" || *token == "" {
|
if *hh == "" || *token == "" {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
log.Printf("bamboo %s starting", version)
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||||
defer stop()
|
defer stop()
|
||||||
b, err := bamboo.New(bamboo.Config{Hammerhead: strings.TrimRight(*hh, "/"), Token: *token, DataDir: *data, Docker: *dockerOn})
|
b, err := bamboo.New(bamboo.Config{Hammerhead: strings.TrimRight(*hh, "/"), Token: *token, DataDir: *data, Docker: *dockerOn})
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Bamboo: site agent that connects a private network to the edge
|
||||||
|
Documentation=https://git.veillax.com/Veillax/bamboo
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=bamboo
|
||||||
|
Group=bamboo
|
||||||
|
EnvironmentFile=-/etc/bamboo/bamboo.env
|
||||||
|
ExecStart=/usr/local/bin/bamboo -data /var/lib/bamboo
|
||||||
|
WorkingDirectory=/var/lib/bamboo
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
# It makes outbound connections only, so it needs no privileges at all.
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=/var/lib/bamboo
|
||||||
|
ProtectHome=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
|
||||||
|
# To list this machine's Docker containers (BAMBOO_DOCKER=1), let the service read
|
||||||
|
# the Docker socket: sudo usermod -aG docker bamboo then restart it.
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Builds bamboo for every release platform and packs the archives into dist/.
|
||||||
|
#
|
||||||
|
# deploy/build.sh [version] version defaults to `git describe`
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# dist/bin/<os>_<arch>/bamboo the raw binaries (the Docker image uses the linux ones)
|
||||||
|
# dist/bamboo_<version>_<os>_<arch>.tar.gz or .zip
|
||||||
|
# dist/SHA256SUMS
|
||||||
|
#
|
||||||
|
# Set TARGETS="linux/amd64 linux/arm64" to build fewer platforms.
|
||||||
|
set -eu
|
||||||
|
NAME=bamboo
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
VERSION=${1:-$(git describe --tags --always 2>/dev/null || echo dev)}
|
||||||
|
TARGETS=${TARGETS:-"linux/amd64 linux/arm64 linux/arm windows/amd64 darwin/amd64 darwin/arm64"}
|
||||||
|
|
||||||
|
rm -rf dist
|
||||||
|
mkdir -p dist/bin dist/stage
|
||||||
|
for t in $TARGETS; do
|
||||||
|
os=${t%/*}
|
||||||
|
arch=${t#*/}
|
||||||
|
ext=""
|
||||||
|
[ "$os" = windows ] && ext=".exe"
|
||||||
|
out="dist/bin/${os}_${arch}"
|
||||||
|
mkdir -p "$out"
|
||||||
|
echo "building $NAME $VERSION for $os/$arch"
|
||||||
|
CGO_ENABLED=0 GOOS=$os GOARCH=$arch GOARM=7 \
|
||||||
|
go build -trimpath -ldflags "-s -w -X main.version=$VERSION" -o "$out/$NAME$ext" "./cmd/$NAME"
|
||||||
|
|
||||||
|
pkg="${NAME}_${VERSION}_${os}_${arch}"
|
||||||
|
stage="dist/stage/$pkg"
|
||||||
|
mkdir -p "$stage"
|
||||||
|
cp "$out/$NAME$ext" "$stage/"
|
||||||
|
for f in LICENSE README.md .env.example; do
|
||||||
|
[ -f "$f" ] && cp "$f" "$stage/"
|
||||||
|
done
|
||||||
|
if [ "$os" = linux ]; then
|
||||||
|
cp deploy/install.sh "deploy/$NAME.service" deploy/docker-compose.yml "$stage/"
|
||||||
|
chmod +x "$stage/install.sh"
|
||||||
|
fi
|
||||||
|
if [ "$os" = windows ] && command -v zip >/dev/null 2>&1; then
|
||||||
|
(cd dist/stage && zip -qr "../$pkg.zip" "$pkg")
|
||||||
|
else
|
||||||
|
tar -C dist/stage -czf "dist/$pkg.tar.gz" "$pkg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
rm -rf dist/stage
|
||||||
|
(cd dist && sha256sum $(ls | grep -E '\.(tar\.gz|zip)$') > SHA256SUMS)
|
||||||
|
echo "done: $(ls dist | grep -cE '\.(tar\.gz|zip)$') archives in dist/"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Run Bamboo with Docker inside your home or private network:
|
||||||
|
# cp .env.example .env (then set BAMBOO_HAMMERHEAD and BAMBOO_TOKEN)
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# Bamboo only makes outbound connections, so nothing needs opening. Host networking
|
||||||
|
# lets it reach services on this machine (127.0.0.1) as well as the rest of your LAN;
|
||||||
|
# switch it off if your targets are all on other machines.
|
||||||
|
services:
|
||||||
|
bamboo:
|
||||||
|
image: git.veillax.com/veillax/bamboo:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- bamboo-data:/data
|
||||||
|
# To list this machine's Docker containers as targets (BAMBOO_DOCKER=1), share the
|
||||||
|
# socket and let the container's user read it (find the group id: getent group docker):
|
||||||
|
# - /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
# group_add:
|
||||||
|
# - "999"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
bamboo-data:
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Installs bamboo as a systemd service from the files in this folder.
|
||||||
|
#
|
||||||
|
# sudo ./install.sh install or upgrade (your settings and data are kept)
|
||||||
|
# sudo ./install.sh --start the same, then start (or restart) the service
|
||||||
|
# sudo ./install.sh --uninstall remove the service and binary (keeps the settings and data)
|
||||||
|
#
|
||||||
|
# Files: /usr/local/bin/bamboo, /etc/systemd/system/bamboo.service,
|
||||||
|
# /etc/bamboo/bamboo.env (your settings and secrets), /var/lib/bamboo (data).
|
||||||
|
# Set DESTDIR=/some/dir to stage everything there without touching the system.
|
||||||
|
set -eu
|
||||||
|
NAME=bamboo
|
||||||
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
ROOT=${DESTDIR:-}
|
||||||
|
BIN=$ROOT/usr/local/bin/$NAME
|
||||||
|
UNIT=$ROOT/etc/systemd/system/$NAME.service
|
||||||
|
CONF=$ROOT/etc/$NAME
|
||||||
|
ENVFILE=$CONF/$NAME.env
|
||||||
|
DATA=$ROOT/var/lib/$NAME
|
||||||
|
|
||||||
|
say() { printf '%s\n' "$*"; }
|
||||||
|
real() { [ -z "${DESTDIR:-}" ]; } # are we touching the real system?
|
||||||
|
|
||||||
|
if real; then
|
||||||
|
[ "$(id -u)" = 0 ] || { say "Run this as root: sudo $0 $*"; exit 1; }
|
||||||
|
command -v systemctl > /dev/null 2>&1 || { say "systemd wasn't found. Run $NAME directly (see the README) or use Docker."; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${1:-}" = "--uninstall" ]; then
|
||||||
|
if real; then
|
||||||
|
systemctl disable --now "$NAME" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
rm -f "$UNIT" "$BIN"
|
||||||
|
if real; then
|
||||||
|
systemctl daemon-reload || true
|
||||||
|
fi
|
||||||
|
say "Removed $NAME. Left in place: $CONF and $DATA (delete them yourself if you want them gone)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -f "$HERE/$NAME" ] || { say "Can't find the $NAME binary next to this script."; exit 1; }
|
||||||
|
|
||||||
|
if real && ! id "$NAME" > /dev/null 2>&1; then
|
||||||
|
useradd --system --home-dir "/var/lib/$NAME" --shell /usr/sbin/nologin "$NAME"
|
||||||
|
say "Created the system user '$NAME'."
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$ROOT/usr/local/bin" "$ROOT/etc/systemd/system" "$CONF" "$DATA"
|
||||||
|
install -m 0755 "$HERE/$NAME" "$BIN.new"
|
||||||
|
mv -f "$BIN.new" "$BIN" # atomic, so upgrading a running service is safe
|
||||||
|
install -m 0644 "$HERE/$NAME.service" "$UNIT"
|
||||||
|
if [ ! -f "$ENVFILE" ]; then
|
||||||
|
install -m 0600 "$HERE/.env.example" "$ENVFILE"
|
||||||
|
say "Created $ENVFILE. Edit it before starting."
|
||||||
|
fi
|
||||||
|
if real; then
|
||||||
|
chown -R "$NAME:$NAME" "$DATA"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if real; then
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable "$NAME" > /dev/null 2>&1
|
||||||
|
if [ "${1:-}" = "--start" ] || systemctl is-active --quiet "$NAME"; then
|
||||||
|
systemctl restart "$NAME"
|
||||||
|
say "$NAME is running."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
say "Installed $("$BIN" -version 2> /dev/null || echo "$NAME")."
|
||||||
|
say "Next:"
|
||||||
|
say " 1. edit $ENVFILE"
|
||||||
|
say " 2. systemctl start $NAME (or run this again with --start)"
|
||||||
|
say " 3. journalctl -u $NAME -f to watch it"
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Creates (or updates) the Gitea release for a tag and uploads what deploy/build.sh made.
|
||||||
|
#
|
||||||
|
# TOKEN=<access token that can write releases> deploy/publish-release.sh v0.2.0
|
||||||
|
#
|
||||||
|
# In Gitea Actions GITHUB_SERVER_URL and GITHUB_REPOSITORY are already set. Safe to
|
||||||
|
# re-run: an existing release is reused and assets with the same name are replaced.
|
||||||
|
set -eu
|
||||||
|
TAG=${1:?usage: publish-release.sh <tag>}
|
||||||
|
: "${TOKEN:?set TOKEN to a Gitea access token that can write releases}"
|
||||||
|
SERVER=${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-https://git.veillax.com}}
|
||||||
|
REPO=${GITHUB_REPOSITORY:-Veillax/bamboo}
|
||||||
|
API="$SERVER/api/v1/repos/$REPO"
|
||||||
|
AUTH="Authorization: token $TOKEN"
|
||||||
|
|
||||||
|
# a JSON helper without needing jq: any python will do
|
||||||
|
PY=python3
|
||||||
|
python3 -c 'pass' > /dev/null 2>&1 || PY=python
|
||||||
|
json() { "$PY" -c "$1"; }
|
||||||
|
|
||||||
|
# release notes: the commit subjects since the previous tag
|
||||||
|
prev=$(git describe --tags --abbrev=0 "$TAG^" 2>/dev/null || true)
|
||||||
|
if [ -n "$prev" ]; then
|
||||||
|
notes=$(git log --pretty='format:- %s' "$prev..$TAG")
|
||||||
|
else
|
||||||
|
notes=$(git log --pretty='format:- %s' "$TAG")
|
||||||
|
fi
|
||||||
|
prerelease=false
|
||||||
|
case "$TAG" in *-*) prerelease=true ;; esac
|
||||||
|
|
||||||
|
body=$(NOTES="$notes" TAG="$TAG" PRE="$prerelease" json '
|
||||||
|
import json, os
|
||||||
|
print(json.dumps({"tag_name": os.environ["TAG"], "name": os.environ["TAG"], "body": os.environ["NOTES"],
|
||||||
|
"draft": False, "prerelease": os.environ["PRE"] == "true"}))')
|
||||||
|
|
||||||
|
# reuse the release when a failed job is re-run
|
||||||
|
id=$(curl -fsS -H "$AUTH" "$API/releases/tags/$TAG" 2>/dev/null | json 'import sys, json; print(json.load(sys.stdin)["id"])' 2>/dev/null || true)
|
||||||
|
if [ -z "$id" ]; then
|
||||||
|
echo "creating release $TAG"
|
||||||
|
id=$(curl -fsS -X POST -H "$AUTH" -H 'Content-Type: application/json' -d "$body" "$API/releases" | json 'import sys, json; print(json.load(sys.stdin)["id"])')
|
||||||
|
else
|
||||||
|
echo "release $TAG already exists (id $id): replacing its files"
|
||||||
|
fi
|
||||||
|
|
||||||
|
existing=$(curl -fsS -H "$AUTH" "$API/releases/$id/assets" | json 'import sys, json
|
||||||
|
for a in json.load(sys.stdin):
|
||||||
|
print(a["id"], a["name"])')
|
||||||
|
|
||||||
|
for f in dist/*.tar.gz dist/*.zip dist/SHA256SUMS; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
name=$(basename "$f")
|
||||||
|
echo "$existing" | while read -r aid aname; do
|
||||||
|
if [ "$aname" = "$name" ]; then
|
||||||
|
curl -fsS -X DELETE -H "$AUTH" "$API/releases/$id/assets/$aid" > /dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "uploading $name"
|
||||||
|
curl -fsS -X POST -H "$AUTH" -F "attachment=@$f" "$API/releases/$id/assets?name=$name" > /dev/null
|
||||||
|
done
|
||||||
|
echo "published $SERVER/$REPO/releases/tag/$TAG"
|
||||||
Reference in new issue
Block a user