CI: build and publish every package from Woodpecker
Pushes to main run the tests. The Deploy button publishes the Windows, RPM, deb and F-Droid packages to the same NAS directories a dev machine uses, with the same keys, then runs update-repo.sh, so public URLs don't change. Builds run on Debian 12, in an image defined in ci/builder, so the Linux packages now need glibc 2.36 instead of Fedora 44's 2.43.
This commit is contained in:
23
.woodpecker/builder.yaml
Normal file
23
.woodpecker/builder.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
# Build and push the image the other pipelines run in, from ci/builder.
|
||||
#
|
||||
# Trigger: open any pipeline for this repo in Woodpecker, click "Deploy", and
|
||||
# set the deploy target to `builder`.
|
||||
|
||||
when:
|
||||
- event: deployment
|
||||
evaluate: 'CI_PIPELINE_DEPLOY_TARGET == "builder"'
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: woodpeckerci/plugin-docker-buildx:6.1.1
|
||||
settings:
|
||||
registry: registry.apps.millslan.net
|
||||
repo: registry.apps.millslan.net/garrettmills/mtgc-builder
|
||||
tags: latest
|
||||
platforms: linux/amd64
|
||||
context: ci/builder
|
||||
dockerfile: ci/builder/Dockerfile
|
||||
username:
|
||||
from_secret: registry_username
|
||||
password:
|
||||
from_secret: registry_password
|
||||
42
.woodpecker/check.yaml
Normal file
42
.woodpecker/check.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
# Test every push to main. Its pipeline is also the one to click "Deploy" on;
|
||||
# see release.yaml.
|
||||
|
||||
when:
|
||||
- event: push
|
||||
branch: main
|
||||
|
||||
steps:
|
||||
- name: prepare
|
||||
image: alpine:3.22
|
||||
volumes:
|
||||
- mtgc-ci-cache:/cache
|
||||
commands:
|
||||
- chown -R 1000:1000 /woodpecker
|
||||
- chown 1000:1000 /cache
|
||||
|
||||
- name: test
|
||||
image: registry.apps.millslan.net/garrettmills/mtgc-builder:latest
|
||||
pull: true
|
||||
volumes:
|
||||
- mtgc-ci-cache:/cache
|
||||
environment:
|
||||
HOME: /cache/home
|
||||
CARGO_HOME: /cache/cargo
|
||||
CARGO_TARGET_DIR: /cache/target-test
|
||||
CARGO_BUILD_JOBS: "4"
|
||||
backend_options:
|
||||
kubernetes:
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
resources:
|
||||
requests:
|
||||
cpu: "4"
|
||||
memory: 6Gi
|
||||
limits:
|
||||
memory: 12Gi
|
||||
commands:
|
||||
- mkdir -p "$HOME"
|
||||
- npm ci
|
||||
- npm run build
|
||||
- cargo test --locked -p mtgc-core -p mtgc -p mtgc-server
|
||||
103
.woodpecker/release.yaml
Normal file
103
.woodpecker/release.yaml
Normal file
@@ -0,0 +1,103 @@
|
||||
# Build the release packages and publish them.
|
||||
#
|
||||
# Trigger: open a pipeline for this repo in Woodpecker, click "Deploy", and set
|
||||
# the deploy target to `all`, `windows`, `rpm`, `deb` or `fdroid`.
|
||||
#
|
||||
# These are steps in one workflow, not a workflow per target: Woodpecker drops a
|
||||
# workflow whose dependency was filtered out, and the cache volume is
|
||||
# ReadWriteOnce. Each target also runs after a failure, so one bad target doesn't
|
||||
# hold back the rest, and the pipeline still ends up red.
|
||||
#
|
||||
# The volumes are defined in the platform repo (src/apps/woodpecker), and this
|
||||
# repo must be marked Trusted → Volumes in Woodpecker to mount them.
|
||||
|
||||
when:
|
||||
- event: deployment
|
||||
evaluate: 'CI_PIPELINE_DEPLOY_TARGET != "builder"'
|
||||
|
||||
# The version is the commit count, and the default clone fetches a single commit.
|
||||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
partial: false
|
||||
depth: 0
|
||||
|
||||
variables:
|
||||
- &builder
|
||||
image: registry.apps.millslan.net/garrettmills/mtgc-builder:latest
|
||||
pull: true
|
||||
backend_options:
|
||||
kubernetes:
|
||||
# The owner of the release directories on the NAS.
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
resources:
|
||||
requests:
|
||||
cpu: "4"
|
||||
memory: 6Gi
|
||||
limits:
|
||||
memory: 12Gi
|
||||
- &publish
|
||||
volumes:
|
||||
- mtgc-release:/nfs/hal9000/mtgc
|
||||
- mtgc-ci-cache:/cache
|
||||
environment:
|
||||
HOME: /cache/home
|
||||
CARGO_HOME: /cache/cargo
|
||||
CARGO_BUILD_JOBS: "4"
|
||||
GRADLE_OPTS: -Dorg.gradle.daemon=false
|
||||
|
||||
steps:
|
||||
- name: prepare
|
||||
image: alpine:3.22
|
||||
volumes:
|
||||
- mtgc-ci-cache:/cache
|
||||
commands:
|
||||
- chown -R 1000:1000 /woodpecker
|
||||
- chown 1000:1000 /cache
|
||||
|
||||
- name: windows
|
||||
<<: [*builder, *publish]
|
||||
commands:
|
||||
- scripts/ci-publish.sh windows
|
||||
when:
|
||||
- status: [success, failure]
|
||||
evaluate: 'CI_PIPELINE_DEPLOY_TARGET in ["all", "windows"]'
|
||||
|
||||
- name: rpm
|
||||
<<: [*builder, *publish]
|
||||
commands:
|
||||
- scripts/ci-publish.sh rpm
|
||||
when:
|
||||
- status: [success, failure]
|
||||
evaluate: 'CI_PIPELINE_DEPLOY_TARGET in ["all", "rpm"]'
|
||||
|
||||
- name: deb
|
||||
<<: [*builder, *publish]
|
||||
commands:
|
||||
- scripts/ci-publish.sh deb
|
||||
when:
|
||||
- status: [success, failure]
|
||||
evaluate: 'CI_PIPELINE_DEPLOY_TARGET in ["all", "deb"]'
|
||||
|
||||
- name: fdroid
|
||||
<<: [*builder, *publish]
|
||||
commands:
|
||||
- scripts/ci-publish.sh fdroid
|
||||
when:
|
||||
- status: [success, failure]
|
||||
evaluate: 'CI_PIPELINE_DEPLOY_TARGET in ["all", "fdroid"]'
|
||||
|
||||
# update-repo.sh finds ../static/mtgc, so this mounts it there.
|
||||
- name: update-repo
|
||||
<<: *builder
|
||||
volumes:
|
||||
- mtgc-release:/nfs/hal9000/mtgc
|
||||
- mtgc-public:/nfs/hal9000/static/mtgc
|
||||
commands:
|
||||
- cd /nfs/hal9000/mtgc
|
||||
- ./update-repo.sh
|
||||
when:
|
||||
- status: [success, failure]
|
||||
43
README.md
43
README.md
@@ -136,8 +136,9 @@ From then on, `sudo dnf upgrade` picks up new releases.
|
||||
trust a new key before it takes another update.
|
||||
- Versions work as on Android: `0.1.<commits on HEAD>`, see
|
||||
[Distributing to phones](#distributing-to-phones-f-droid).
|
||||
- The RPM is built against this machine's libraries, so it installs on this
|
||||
Fedora release and newer.
|
||||
- The RPM is built against the build machine's libraries, so it needs at least
|
||||
that machine's glibc. Built by [CI](#publishing-from-ci), that's glibc 2.36;
|
||||
built on Fedora 44, it's Fedora 44 and newer.
|
||||
|
||||
### Distributing to Debian/Ubuntu (apt repo)
|
||||
|
||||
@@ -186,9 +187,10 @@ From then on, `sudo apt upgrade` picks up new releases.
|
||||
- Versions are the same as the RPM's. A build published with `--allow-dirty`
|
||||
gets a `~dirty` suffix, which apt sorts below the clean build of the same
|
||||
version.
|
||||
- The `.deb` is built against this machine's libraries, so it needs a distro
|
||||
with at least this Fedora's glibc (2.43 on Fedora 44). Older Debian and
|
||||
Ubuntu releases can't install it.
|
||||
- The `.deb` is built against the build machine's libraries, so it needs a
|
||||
distro with at least that machine's glibc. Built by
|
||||
[CI](#publishing-from-ci), that's glibc 2.36: Debian 12 and Ubuntu 24.04 or
|
||||
newer. Built on Fedora 44, it's glibc 2.43, which they can't install.
|
||||
|
||||
### Distributing to Windows
|
||||
|
||||
@@ -229,6 +231,37 @@ installed app in place.
|
||||
- Versions work as on Android: `0.1.<commits on HEAD>`, see
|
||||
[Distributing to phones](#distributing-to-phones-f-droid).
|
||||
|
||||
### Publishing from CI
|
||||
|
||||
Woodpecker can do all of the above, through the same scripts. Every push to
|
||||
`main` runs the tests (`.woodpecker/check.yaml`). To publish, open a pipeline,
|
||||
click **Deploy**, and set the deploy target:
|
||||
|
||||
| Target | What it does |
|
||||
|---|---|
|
||||
| `all` | Publishes every package below |
|
||||
| `windows`, `rpm`, `deb`, `fdroid` | Publishes just that package |
|
||||
| `builder` | Rebuilds the image the pipelines run in, from `ci/builder` |
|
||||
|
||||
`all` doesn't include `builder`. Rebuild the image after changing its
|
||||
Dockerfile, and before the first run of anything else.
|
||||
|
||||
- **It publishes to the same place you do.** The pipeline mounts the release
|
||||
directory and its keys from the NAS at `/nfs/hal9000/mtgc`, then runs that
|
||||
directory's `update-repo.sh` to copy the public files out, so CI and a dev
|
||||
machine can each publish the next release. `scripts/ci-publish.sh` sets up
|
||||
what a fresh container lacks and runs the publish script.
|
||||
- A target that fails doesn't stop the others, but the pipeline ends up red.
|
||||
Restarting it is safe: targets that already have this version are skipped.
|
||||
- The volumes are defined in the platform repo (`src/apps/woodpecker`). This
|
||||
repo must be marked **Trusted → Volumes** in Woodpecker to mount them, and
|
||||
needs the `registry_username` and `registry_password` secrets to push the
|
||||
image.
|
||||
- `sdk_path` in the F-Droid repo's `config.yml` must be `$ANDROID_HOME`, as the
|
||||
SDK is somewhere else on each machine.
|
||||
- Builds are cached on the `mtgc-ci-cache` volume. It's safe to delete anything
|
||||
on it; the next build just takes longer.
|
||||
|
||||
## Using it
|
||||
|
||||
- **Add Cards** — type a name (typos OK); ↑/↓ then Enter adds a copy.
|
||||
|
||||
99
ci/builder/Dockerfile
Normal file
99
ci/builder/Dockerfile
Normal file
@@ -0,0 +1,99 @@
|
||||
# The image every step in .woodpecker runs in. It builds the desktop app, the
|
||||
# Windows installer and the Android APK, and holds the tools that publish them.
|
||||
#
|
||||
# Build it in Woodpecker: open a pipeline, click "Deploy", and set the deploy
|
||||
# target to `builder`. Or locally:
|
||||
#
|
||||
# podman build -t mtgc-builder ci/builder
|
||||
#
|
||||
# Debian 12 on purpose: a Linux binary needs at least the glibc it was built
|
||||
# against, so the oldest libraries we can build on reach the most machines.
|
||||
# Versions match a working dev machine; bump them here, not in the scripts.
|
||||
|
||||
FROM debian:bookworm
|
||||
|
||||
ENV RUST_VERSION=1.97.1 \
|
||||
TAURI_CLI_VERSION=2.11.4 \
|
||||
CARGO_XWIN_VERSION=0.23.1 \
|
||||
NODE_VERSION=22.14.0 \
|
||||
REPREPRO_VERSION=5.4.4 \
|
||||
REPREPRO_SHA256=5b028f79183659d441d1b340deb88341a7f29335ae7370eff4b3c094fbe90bc4 \
|
||||
FDROIDSERVER_VERSION=2.4.5 \
|
||||
CMDLINE_TOOLS_BUILD=13114758 \
|
||||
NDK_VERSION=28.2.13676358 \
|
||||
ANDROID_PLATFORM=android-36 \
|
||||
ANDROID_BUILD_TOOLS=36.0.0
|
||||
|
||||
ENV RUSTUP_HOME=/opt/rustup \
|
||||
CARGO_HOME=/opt/cargo \
|
||||
ANDROID_HOME=/opt/android-sdk \
|
||||
PATH=/opt/cargo/bin:/opt/node/bin:/opt/android-sdk/cmdline-tools/latest/bin:/usr/lib/llvm-14/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
# System packages. The first group builds the app, then Windows, then the
|
||||
# package repos and Android. libgpgme and below only build reprepro.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential ca-certificates curl file git pkg-config unzip xz-utils \
|
||||
libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev libssl-dev \
|
||||
clang lld llvm nsis \
|
||||
createrepo-c dpkg-dev gnupg rpm \
|
||||
openjdk-17-jdk-headless python3-venv \
|
||||
automake libarchive-dev libbz2-dev libdb-dev libgpgme-dev liblzma-dev libzstd-dev zlib1g-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# reprepro: bookworm's 5.3 can't read a repo that keeps several versions of a
|
||||
# package, which deb-publish.sh's `Limit:` makes, so use the dev machine's.
|
||||
RUN curl -fsSL -o /tmp/reprepro.tar.gz \
|
||||
"https://salsa.debian.org/debian/reprepro/-/archive/reprepro-$REPREPRO_VERSION/reprepro-reprepro-$REPREPRO_VERSION.tar.gz" \
|
||||
&& echo "$REPREPRO_SHA256 /tmp/reprepro.tar.gz" | sha256sum -c - \
|
||||
&& mkdir /tmp/reprepro \
|
||||
&& tar xzf /tmp/reprepro.tar.gz -C /tmp/reprepro --strip-components=1 \
|
||||
&& cd /tmp/reprepro \
|
||||
&& autoreconf -fi \
|
||||
&& ./configure --with-libbz2 --with-liblzma --with-libarchive \
|
||||
&& make -j"$(nproc)" install \
|
||||
&& rm -rf /tmp/reprepro /tmp/reprepro.tar.gz
|
||||
|
||||
# Rust
|
||||
RUN curl -fsSL -o /tmp/rustup-init https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init \
|
||||
&& chmod +x /tmp/rustup-init \
|
||||
&& /tmp/rustup-init -y --no-modify-path --profile minimal --default-toolchain "$RUST_VERSION" \
|
||||
--target x86_64-pc-windows-msvc \
|
||||
--target aarch64-linux-android \
|
||||
--target armv7-linux-androideabi \
|
||||
--target i686-linux-android \
|
||||
--target x86_64-linux-android \
|
||||
&& rm /tmp/rustup-init \
|
||||
&& cargo install --locked tauri-cli --version "$TAURI_CLI_VERSION" \
|
||||
&& cargo install --locked cargo-xwin --version "$CARGO_XWIN_VERSION" \
|
||||
&& rm -rf /opt/cargo/registry /opt/cargo/git
|
||||
|
||||
# Node
|
||||
RUN mkdir /opt/node \
|
||||
&& curl -fsSL "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
|
||||
| tar xJ -C /opt/node --strip-components=1
|
||||
|
||||
# Android SDK and NDK
|
||||
RUN mkdir -p /opt/android-sdk/cmdline-tools \
|
||||
&& curl -fsSL -o /tmp/cmdline-tools.zip \
|
||||
"https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_TOOLS_BUILD}_latest.zip" \
|
||||
&& unzip -q /tmp/cmdline-tools.zip -d /tmp/cmdline-tools \
|
||||
&& mv /tmp/cmdline-tools/cmdline-tools /opt/android-sdk/cmdline-tools/latest \
|
||||
&& rm -rf /tmp/cmdline-tools /tmp/cmdline-tools.zip \
|
||||
&& (yes || true) | sdkmanager --licenses >/dev/null \
|
||||
&& sdkmanager --install \
|
||||
"platforms;$ANDROID_PLATFORM" \
|
||||
"build-tools;$ANDROID_BUILD_TOOLS" \
|
||||
"platform-tools" \
|
||||
"ndk;$NDK_VERSION" >/dev/null
|
||||
|
||||
# fdroidserver
|
||||
RUN python3 -m venv /opt/fdroidserver \
|
||||
&& /opt/fdroidserver/bin/pip install --no-cache-dir "fdroidserver==$FDROIDSERVER_VERSION" \
|
||||
&& ln -s /opt/fdroidserver/bin/fdroid /usr/local/bin/fdroid
|
||||
|
||||
# Steps run as uid 1000, the owner of the release directories on the NAS. It
|
||||
# gets an account because keytool and Gradle ask who they're running as, and
|
||||
# the SDK because Gradle may add a build-tools package it wants.
|
||||
RUN useradd --uid 1000 --create-home builder \
|
||||
&& chown -R 1000:1000 /opt/android-sdk
|
||||
95
scripts/ci-publish.sh
Executable file
95
scripts/ci-publish.sh
Executable file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# ci-publish.sh — publish one target from a Woodpecker step in .woodpecker/release.yaml.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/ci-publish.sh windows|rpm|deb|fdroid
|
||||
#
|
||||
# Does what a fresh container lacks and a dev machine already has, then runs that
|
||||
# target's publish script. The repos and keys are the same directories a dev
|
||||
# machine publishes to, mounted at the same path, so either can publish next.
|
||||
#
|
||||
# Environment:
|
||||
# MTGC_RELEASE_DIR the mounted release directory (default /nfs/hal9000/mtgc)
|
||||
# MTGC_CI_CACHE the build cache volume (default /cache)
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
sed -n '3,14p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
||||
err() { printf '\033[1;31m[err]\033[0m %s\n' "$*" >&2; }
|
||||
|
||||
RELEASE_DIR="${MTGC_RELEASE_DIR:-/nfs/hal9000/mtgc}"
|
||||
CACHE="${MTGC_CI_CACHE:-/cache}"
|
||||
|
||||
[ $# -eq 1 ] || usage 1
|
||||
case "$1" in
|
||||
windows) subdir=win ;;
|
||||
rpm) subdir=rpm ;;
|
||||
deb) subdir=deb ;;
|
||||
fdroid) subdir=repo ;;
|
||||
-h | --help) usage ;;
|
||||
*) usage 1 ;;
|
||||
esac
|
||||
target="$1"
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$repo_root"
|
||||
|
||||
# --- 1. Checks --------------------------------------------------------------
|
||||
#
|
||||
# The version is the commit count, so a shallow clone would call this release
|
||||
# 0.1.1. The publish script would refuse that, but not with a helpful message.
|
||||
|
||||
if [ "$(git rev-parse --is-shallow-repository)" != false ]; then
|
||||
err "this is a shallow clone; the commit count needs the full history"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- 2. Build directories ---------------------------------------------------
|
||||
#
|
||||
# The publish scripts name target/ directly, so link it rather than setting
|
||||
# CARGO_TARGET_DIR. It lives on the cache volume, which outlasts the pipeline
|
||||
# and has the room: the workspace volume is 10G.
|
||||
|
||||
mkdir -p "$CACHE/target" "$HOME"
|
||||
ln -sfn "$CACHE/target" target
|
||||
|
||||
cargo fetch --locked
|
||||
if [ ! -d node_modules ]; then
|
||||
npm ci
|
||||
fi
|
||||
|
||||
# --- 3. Keys ----------------------------------------------------------------
|
||||
#
|
||||
# gpg wants its home to be private, and the agent wants a socket there; neither
|
||||
# works on the NFS copy. /tmp goes away with the step's pod.
|
||||
|
||||
case "$target" in
|
||||
rpm | deb)
|
||||
gnupg="$(mktemp -d)"
|
||||
cp -r "$RELEASE_DIR/keys/gnupg/." "$gnupg/"
|
||||
chmod -R go-rwx "$gnupg"
|
||||
export MTGC_RPM_GNUPGHOME="$gnupg" MTGC_DEB_GNUPGHOME="$gnupg"
|
||||
;;
|
||||
fdroid)
|
||||
source scripts/android-env.sh >/dev/null
|
||||
android="src-tauri/gen/android"
|
||||
# RustPlugin reads the SDK and NDK from here; a clone doesn't have it.
|
||||
printf 'sdk.dir=%s\nndk.dir=%s\n' "$ANDROID_HOME" "$NDK_HOME" >"$android/local.properties"
|
||||
(
|
||||
umask 077
|
||||
sed "s|^storeFile=.*|storeFile=$RELEASE_DIR/keys/android-release.jks|" \
|
||||
"$RELEASE_DIR/keys/keystore.properties" >"$android/keystore.properties"
|
||||
)
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- 4. Publish -------------------------------------------------------------
|
||||
|
||||
info "publishing $target to $RELEASE_DIR/$subdir"
|
||||
exec "scripts/$target-publish.sh" --skip-published "$RELEASE_DIR/$subdir"
|
||||
@@ -13,6 +13,7 @@
|
||||
# --init-key generate the package signing key (once, ever; skip it if
|
||||
# rpm-publish.sh already made one, the two share it)
|
||||
# --allow-dirty publish uncommitted changes; the version gets a ~dirty suffix
|
||||
# --skip-published finish without error if the repo already has this version
|
||||
#
|
||||
# Environment:
|
||||
# MTGC_DEB_DIR repo directory, if not given as an argument
|
||||
@@ -27,7 +28,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
sed -n '3,26p' "$0" | sed 's/^# \{0,1\}//'
|
||||
sed -n '3,27p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
@@ -42,11 +43,13 @@ KEEP=3 # versions kept in the repo, so a bad release can be downgraded from
|
||||
|
||||
init_key=false
|
||||
allow_dirty=false
|
||||
skip_published=false
|
||||
dir="${MTGC_DEB_DIR:-}"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--init-key) init_key=true ;;
|
||||
--allow-dirty) allow_dirty=true ;;
|
||||
--skip-published) skip_published=true ;;
|
||||
-h | --help) usage ;;
|
||||
-*) usage 1 ;;
|
||||
*) dir="$1" ;;
|
||||
@@ -141,7 +144,9 @@ EOF
|
||||
sed 's/^$/./; s/^/ /' "$dir/$PACKAGE.asc"
|
||||
} >"$dir/$PACKAGE.sources"
|
||||
|
||||
# A landing page for whoever opens the repo's address in a browser.
|
||||
# A landing page for whoever opens the repo's address in a browser. The package
|
||||
# needs at least the glibc it's built against, so that depends on the build host.
|
||||
glibc="$(ldd --version | awk 'NR == 1 { print $NF }')"
|
||||
cat >"$dir/README.html" <<EOF
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
@@ -173,8 +178,8 @@ sudo apt update && sudo apt install $PACKAGE</code></pre>
|
||||
<p>From then on, <code>sudo apt upgrade</code> picks up new releases.</p>
|
||||
|
||||
<h2>Requirements</h2>
|
||||
<p>A 64-bit x86 system with glibc 2.43 or newer (check with <code>ldd --version</code>).
|
||||
Older releases, such as Ubuntu 24.04 and Debian 13, can't install it.</p>
|
||||
<p>A 64-bit x86 system with glibc $glibc or newer (check with <code>ldd --version</code>).
|
||||
Older releases can't install it.</p>
|
||||
|
||||
<h2>Uninstall</h2>
|
||||
<pre><code>sudo apt remove $PACKAGE
|
||||
@@ -208,6 +213,10 @@ while read -r version; do
|
||||
[ "$patch" -gt "$newest" ] && newest="$patch"
|
||||
done < <(repo_ list "$SUITE" "$PACKAGE" 2>/dev/null | awk '{ print $NF }')
|
||||
if [ "$release_count" -le "$newest" ]; then
|
||||
if $skip_published; then
|
||||
info "version $release_version is already published; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
err "version $release_version is not newer than the repo's x.y.$newest; commit something first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# Options:
|
||||
# --init-keystore generate the app signing key (once, ever) and keystore.properties
|
||||
# --allow-dirty publish uncommitted changes; the version gets a -dirty suffix
|
||||
# --skip-published finish without error if the repo already has this version
|
||||
#
|
||||
# Environment:
|
||||
# MTGC_FDROID_DIR repo directory, if not given as an argument
|
||||
@@ -26,7 +27,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
sed -n '3,24p' "$0" | sed 's/^# \{0,1\}//'
|
||||
sed -n '3,25p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
@@ -40,11 +41,13 @@ APP_KEY_ALIAS="mtgc"
|
||||
|
||||
init_keystore=false
|
||||
allow_dirty=false
|
||||
skip_published=false
|
||||
dir="${MTGC_FDROID_DIR:-}"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--init-keystore) init_keystore=true ;;
|
||||
--allow-dirty) allow_dirty=true ;;
|
||||
--skip-published) skip_published=true ;;
|
||||
-h | --help) usage ;;
|
||||
-*) usage 1 ;;
|
||||
*) dir="$1" ;;
|
||||
@@ -187,6 +190,10 @@ for apk in "$dir"/repo/"${APP_ID}"_*.apk "$dir"/archive/"${APP_ID}"_*.apk; do
|
||||
[ "$code" -gt "$newest" ] && newest="$code"
|
||||
done
|
||||
if [ "$version_code" -le "$newest" ]; then
|
||||
if $skip_published; then
|
||||
info "versionCode $version_code is already published; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
err "versionCode $version_code is not newer than $newest, already in the repo; commit something first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# Options:
|
||||
# --init-key generate the package signing key (once, ever)
|
||||
# --allow-dirty publish uncommitted changes; the RPM release becomes 0.dirty
|
||||
# --skip-published finish without error if the repo already has this version
|
||||
#
|
||||
# Environment:
|
||||
# MTGC_RPM_DIR repo directory, if not given as an argument
|
||||
@@ -26,7 +27,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
sed -n '3,25p' "$0" | sed 's/^# \{0,1\}//'
|
||||
sed -n '3,26p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
@@ -40,11 +41,13 @@ KEEP=3 # versions kept in the repo, so a bad release can be downgraded from
|
||||
|
||||
init_key=false
|
||||
allow_dirty=false
|
||||
skip_published=false
|
||||
dir="${MTGC_RPM_DIR:-}"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--init-key) init_key=true ;;
|
||||
--allow-dirty) allow_dirty=true ;;
|
||||
--skip-published) skip_published=true ;;
|
||||
-h | --help) usage ;;
|
||||
-*) usage 1 ;;
|
||||
*) dir="$1" ;;
|
||||
@@ -142,6 +145,10 @@ for rpm_file in "$dir/$PACKAGE"-*.rpm; do
|
||||
[ "$patch" -gt "$newest" ] && newest="$patch"
|
||||
done
|
||||
if [ "$release_count" -le "$newest" ]; then
|
||||
if $skip_published; then
|
||||
info "version $release_version is already published; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
err "version $release_version is not newer than the repo's x.y.$newest; commit something first"
|
||||
exit 1
|
||||
fi
|
||||
@@ -159,7 +166,9 @@ if [ -z "$built" ]; then
|
||||
err "the build produced no RPM under $outputs"
|
||||
exit 1
|
||||
fi
|
||||
rpmsign --addsign --define "_gpg_path $GNUPGHOME" --define "_gpg_name $fpr" "$built" >/dev/null
|
||||
# Debian's rpm looks for gpg2, which only Fedora has, so name the gpg in use.
|
||||
rpmsign --addsign --define "__gpg $(command -v gpg)" --define "_gpg_path $GNUPGHOME" \
|
||||
--define "_gpg_name $fpr" "$built" >/dev/null
|
||||
|
||||
# --- 7. Publish -------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#
|
||||
# Options:
|
||||
# --allow-dirty publish uncommitted changes; the file name gets a -dirty suffix
|
||||
# --skip-published finish without error if the repo already has this version
|
||||
#
|
||||
# Environment:
|
||||
# MTGC_WINDOWS_DIR downloads directory, if not given as an argument
|
||||
@@ -23,7 +24,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
sed -n '3,22p' "$0" | sed 's/^# \{0,1\}//'
|
||||
sed -n '3,23p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
@@ -37,10 +38,12 @@ LATEST="$PACKAGE-latest-x64-setup.exe"
|
||||
KEEP=3 # versions kept in the folder, so a bad release can be rolled back
|
||||
|
||||
allow_dirty=false
|
||||
skip_published=false
|
||||
dir="${MTGC_WINDOWS_DIR:-}"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--allow-dirty) allow_dirty=true ;;
|
||||
--skip-published) skip_published=true ;;
|
||||
-h | --help) usage ;;
|
||||
-*) usage 1 ;;
|
||||
*) dir="$1" ;;
|
||||
@@ -98,6 +101,10 @@ for exe in "$dir/${PACKAGE}"_*_x64-setup.exe; do
|
||||
[ "$patch" -gt "$newest" ] && newest="$patch"
|
||||
done
|
||||
if [ "$release_count" -le "$newest" ]; then
|
||||
if $skip_published; then
|
||||
info "version $release_version is already published; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
err "version $release_version is not newer than the folder's x.y.$newest; commit something first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user