.hearthforge-ci.toml
| 1 | # Steps run in file order, in one container, sharing /ci/build. |
| 2 | # Same image as the Containerfile's build stage, so the binary links against |
| 3 | # the glibc of the trixie runtime image. |
| 4 | |
| 5 | image = "docker.io/library/rust:1-trixie" |
| 6 | work_dir = "/ci/build" |
| 7 | clone_project_to = "/ci/build/project" |
| 8 | shell_setup = """ |
| 9 | set -euo pipefail |
| 10 | export CARGO_TARGET_DIR=/ci/cache/target |
| 11 | export ANDROID_HOME=/ci/cache/android-sdk |
| 12 | """ |
| 13 | |
| 14 | timeout = 3600 |
| 15 | memory_limit = "6g" |
| 16 | |
| 17 | # CARGO_TARGET_DIR must stay outside clone_project_to: the checkout is |
| 18 | # extracted over that directory. |
| 19 | cache = [ |
| 20 | { path = "/ci/cache/target", max_size = "16g" }, |
| 21 | { path = "/usr/local/cargo/registry", max_size = "4g" }, |
| 22 | # trunk downloads wasm-opt here. |
| 23 | { path = "/root/.cache/trunk", max_size = "1g" }, |
| 24 | { path = "/ci/cache/android-sdk", max_size = "3g" }, |
| 25 | { path = "/root/.gradle", max_size = "4g" }, |
| 26 | ] |
| 27 | |
| 28 | [on] |
| 29 | push = ["master"] |
| 30 | tag = true |
| 31 | |
| 32 | [variables] |
| 33 | |
| 34 | [variables.TRUNK_VERSION] |
| 35 | default = "0.21.14" |
| 36 | description = "Trunk release that builds the wasm frontend. Matches the Containerfile." |
| 37 | |
| 38 | [[steps]] |
| 39 | name = "setup" |
| 40 | timeout = 900 |
| 41 | run_sh = """ |
| 42 | apt-get update -qq && apt-get install -y -qq --no-install-recommends \ |
| 43 | openjdk-21-jdk-headless > /dev/null |
| 44 | |
| 45 | rustup component add rustfmt clippy |
| 46 | rustup target add wasm32-unknown-unknown |
| 47 | |
| 48 | url="https://github.com/trunk-rs/trunk/releases/download/v${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz" |
| 49 | curl -fsSL -o /tmp/trunk.tar.gz "$url" |
| 50 | curl -fsSL "$url.sha256" | awk '{print $1 " /tmp/trunk.tar.gz"}' | sha256sum -c - |
| 51 | tar xzf /tmp/trunk.tar.gz -C /usr/local/bin |
| 52 | rm -f /tmp/trunk.tar.gz |
| 53 | |
| 54 | # Only for the license files. Gradle installs the platform and build-tools |
| 55 | # that the app needs on its own. |
| 56 | if [ ! -x "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" ]; then |
| 57 | curl -fsSL -o /tmp/clt.zip \ |
| 58 | "https://dl.google.com/android/repository/commandlinetools-linux-15859902_latest.zip" |
| 59 | echo "040d3996a65543d22ec4bf73e4c37aa37a8d4af4 /tmp/clt.zip" | sha1sum -c - |
| 60 | unzip -q /tmp/clt.zip -d /tmp/clt |
| 61 | mkdir -p "$ANDROID_HOME/cmdline-tools" |
| 62 | mv /tmp/clt/cmdline-tools "$ANDROID_HOME/cmdline-tools/latest" |
| 63 | rm -r /tmp/clt /tmp/clt.zip |
| 64 | fi |
| 65 | (yes || true) | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --licenses > /dev/null |
| 66 | |
| 67 | trunk --version && cargo fmt --version && cargo clippy --version && java -version |
| 68 | """ |
| 69 | |
| 70 | # Reported, not gated: clippy findings change between toolchain versions. |
| 71 | [[steps]] |
| 72 | name = "lint" |
| 73 | warn_on_fail = true |
| 74 | run_sh = """ |
| 75 | cd project |
| 76 | cargo fmt --check |
| 77 | cargo clippy --workspace --all-targets -- -D warnings |
| 78 | """ |
| 79 | |
| 80 | [[steps]] |
| 81 | name = "test" |
| 82 | run_sh = "cd project && cargo test --workspace" |
| 83 | |
| 84 | [[steps]] |
| 85 | name = "build" |
| 86 | timeout = 2400 |
| 87 | run_sh = """ |
| 88 | cd project |
| 89 | (cd web && trunk build --release) |
| 90 | cargo build --locked --release -p server |
| 91 | """ |
| 92 | |
| 93 | [[steps]] |
| 94 | name = "android" |
| 95 | timeout = 1800 |
| 96 | run_sh = """ |
| 97 | cd project/android |
| 98 | ./gradlew --no-daemon testDebugUnitTest assembleDebug |
| 99 | cp app/build/outputs/apk/debug/app-debug.apk /ci/build/opentracker-debug.apk |
| 100 | """ |
| 101 | publish_file = ["/ci/build/opentracker-debug.apk"] |
| 102 | |
| 103 | # Needs the CI secrets ANDROID_KEYSTORE_BASE64 (base64 of a PKCS12 keystore) |
| 104 | # and ANDROID_KEYSTORE_PASSWORD. Releases must keep the same key: Android |
| 105 | # refuses an update signed with another key. |
| 106 | [[steps]] |
| 107 | name = "android-release" |
| 108 | run_if = 'test -n "${CI_COMMIT_TAG}"' |
| 109 | warn_on_fail = true |
| 110 | timeout = 1800 |
| 111 | run_sh = """ |
| 112 | if [ -z "${ANDROID_KEYSTORE_BASE64:-}" ] || [ -z "${ANDROID_KEYSTORE_PASSWORD:-}" ]; then |
| 113 | echo "WARNING: CI secrets ANDROID_KEYSTORE_BASE64 or ANDROID_KEYSTORE_PASSWORD missing. No signed release APK." |
| 114 | exit 1 |
| 115 | fi |
| 116 | export ANDROID_KEYSTORE=/tmp/release.p12 ANDROID_KEY_ALIAS=opentracker |
| 117 | printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > "$ANDROID_KEYSTORE" |
| 118 | cd project/android |
| 119 | ./gradlew --no-daemon assembleRelease |
| 120 | cp app/build/outputs/apk/release/app-release.apk /ci/build/opentracker-release.apk |
| 121 | """ |
| 122 | publish_file = ["/ci/build/opentracker-release.apk"] |
| 123 | |
| 124 | [[steps]] |
| 125 | name = "android-lint" |
| 126 | warn_on_fail = true |
| 127 | run_sh = "cd project/android && ./gradlew --no-daemon lintDebug" |
| 128 | |
| 129 | # Packages what the build step made via the Containerfile's prebuilt stage. |
| 130 | # build_image builds it in a VM on the server and pushes it to this repo's |
| 131 | # registry. A branch run pushes the short sha and "edge". A tag run pushes |
| 132 | # the short sha, the tag and "latest". Tags cannot depend on the trigger, so |
| 133 | # run_if picks one of two image steps. |
| 134 | [[steps]] |
| 135 | name = "image-files" |
| 136 | run_sh = """ |
| 137 | cd project |
| 138 | mkdir -p ci-bin |
| 139 | cp "${CARGO_TARGET_DIR}/release/otserver" ci-bin/otserver |
| 140 | cp -r web/dist ci-bin/web |
| 141 | """ |
| 142 | |
| 143 | [[steps]] |
| 144 | name = "image" |
| 145 | run_if = 'test -z "${CI_COMMIT_TAG}"' |
| 146 | timeout = 900 |
| 147 | [steps.build_image] |
| 148 | args = { BIN_STAGE = "prebuilt" } |
| 149 | tags = ["$CI_COMMIT_SHORT_SHA", "edge"] |
| 150 | |
| 151 | [[steps]] |
| 152 | name = "image-release" |
| 153 | run_if = 'test -n "${CI_COMMIT_TAG}"' |
| 154 | timeout = 900 |
| 155 | [steps.build_image] |
| 156 | args = { BIN_STAGE = "prebuilt" } |
| 157 | tags = ["$CI_COMMIT_SHORT_SHA", "$CI_COMMIT_TAG", "latest"] |
| 158 |