Repository navigation
Rolling release #625
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Rolling release | |
| on: | |
| schedule: | |
| - cron: "0 0,12 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| force_rebuild: | |
| description: "Rebuild and replace assets even when the latest release is already at HEAD" | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: rolling-release | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| name: Build rolling release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| - name: Compute release metadata | |
| id: meta | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| FORCE_REBUILD: ${{ github.event_name == 'workflow_dispatch' && inputs.force_rebuild }} | |
| run: | | |
| set -euo pipefail | |
| latest_tag="$(gh release list --limit 100 --json tagName --jq '[.[].tagName | select(test("^r[0-9]+$"))] | sort_by(ltrimstr("r") | tonumber) | reverse | .[0] // ""')" | |
| if [[ -n "$latest_tag" ]]; then | |
| git fetch --force origin "refs/tags/${latest_tag}:refs/tags/${latest_tag}" || true | |
| fi | |
| release_has_expected_assets() { | |
| local tag="$1" | |
| local missing=0 | |
| local asset | |
| local expected_assets=( | |
| "koder-${tag}-linux-amd64" | |
| "koder-${tag}-linux-amd64.sha256" | |
| "koder-${tag}-linux-arm64" | |
| "koder-${tag}-linux-arm64.sha256" | |
| ) | |
| mapfile -t release_assets < <(gh release view "$tag" --json assets --jq '.assets[].name') | |
| for asset in "${expected_assets[@]}"; do | |
| if ! printf '%s\n' "${release_assets[@]}" | grep -Fxq "$asset"; then | |
| echo "Release ${tag} is missing ${asset}." | |
| missing=1 | |
| fi | |
| done | |
| return "$missing" | |
| } | |
| repair_release=false | |
| if [[ -n "$latest_tag" ]] && git rev-parse -q --verify "refs/tags/${latest_tag}" >/dev/null; then | |
| if [[ "$(git rev-parse HEAD)" == "$(git rev-parse "${latest_tag}")" ]]; then | |
| if [[ "${FORCE_REBUILD}" != "true" ]] && release_has_expected_assets "$latest_tag"; then | |
| echo "changed=false" >>"$GITHUB_OUTPUT" | |
| echo "No changes since ${latest_tag}, and all expected assets exist; skipping release." | |
| exit 0 | |
| fi | |
| repair_release=true | |
| tag="$latest_tag" | |
| changelog_range="${latest_tag}..HEAD" | |
| else | |
| tag="$(scripts/build-number)" | |
| changelog_range="${latest_tag}..HEAD" | |
| fi | |
| else | |
| tag="$(scripts/build-number)" | |
| changelog_range="HEAD" | |
| fi | |
| short_sha="$(git rev-parse --short=12 HEAD)" | |
| built_at="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" | |
| { | |
| echo "changed=true" | |
| echo "repair_release=${repair_release}" | |
| echo "tag=${tag}" | |
| echo "short_sha=${short_sha}" | |
| echo "built_at=${built_at}" | |
| } >>"$GITHUB_OUTPUT" | |
| { | |
| echo "## koder ${tag}" | |
| echo | |
| echo "Linux x64 and Linux ARM64 rolling release built from ${short_sha}." | |
| echo | |
| echo "### Changelog" | |
| echo | |
| if [[ "$repair_release" == "true" ]]; then | |
| echo "- Rebuilt release assets for ${short_sha}." | |
| else | |
| git log --no-merges --format='- %s (%h)' "$changelog_range" | |
| fi | |
| } > release-notes.md | |
| - name: Set up Java | |
| if: steps.meta.outputs.changed == 'true' | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "21" | |
| - name: Set up Android SDK | |
| if: steps.meta.outputs.changed == 'true' | |
| uses: android-actions/setup-android@v3 | |
| - name: Install Android SDK components | |
| if: steps.meta.outputs.changed == 'true' | |
| run: sdkmanager "platforms;android-36" "build-tools;37.0.0" | |
| - name: Install sandbox test dependency | |
| if: steps.meta.outputs.changed == 'true' | |
| run: | | |
| set -euo pipefail | |
| timeout 120 sudo apt-get install -y --no-install-recommends bubblewrap | |
| timeout 10 sudo sysctl -w kernel.unprivileged_userns_clone=1 || true | |
| timeout 10 sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true | |
| bwrap --version | |
| - name: Run tests | |
| if: steps.meta.outputs.changed == 'true' | |
| env: | |
| KODER_BWRAP_DISABLE_NET_UNSHARE: "1" | |
| run: | | |
| set -euo pipefail | |
| go test ./cmd/... ./internal/... | |
| clients/android/gradlew -p clients/android testDebugUnitTest lintDebug | |
| - name: Build signed official Android client | |
| if: steps.meta.outputs.changed == 'true' | |
| env: | |
| ANDROID_RELEASE_KEYSTORE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_BASE64 }} | |
| ANDROID_RELEASE_STORE_PASSWORD: ${{ secrets.ANDROID_RELEASE_STORE_PASSWORD }} | |
| ANDROID_RELEASE_KEY_ALIAS: ${{ secrets.ANDROID_RELEASE_KEY_ALIAS }} | |
| ANDROID_RELEASE_KEY_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEY_PASSWORD }} | |
| RELEASE_TAG: ${{ steps.meta.outputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| : "${ANDROID_RELEASE_KEYSTORE_BASE64:?missing ANDROID_RELEASE_KEYSTORE_BASE64 secret}" | |
| : "${ANDROID_RELEASE_STORE_PASSWORD:?missing ANDROID_RELEASE_STORE_PASSWORD secret}" | |
| : "${ANDROID_RELEASE_KEY_ALIAS:?missing ANDROID_RELEASE_KEY_ALIAS secret}" | |
| : "${ANDROID_RELEASE_KEY_PASSWORD:?missing ANDROID_RELEASE_KEY_PASSWORD secret}" | |
| signing_dir="$RUNNER_TEMP/koder-android-signing" | |
| mkdir -p "$signing_dir" | |
| chmod 700 "$signing_dir" | |
| printf '%s' "$ANDROID_RELEASE_KEYSTORE_BASE64" | base64 --decode >"$signing_dir/release.jks" | |
| chmod 600 "$signing_dir/release.jks" | |
| { | |
| echo "storeFile=$signing_dir/release.jks" | |
| echo "storePassword=$ANDROID_RELEASE_STORE_PASSWORD" | |
| echo "keyAlias=$ANDROID_RELEASE_KEY_ALIAS" | |
| echo "keyPassword=$ANDROID_RELEASE_KEY_PASSWORD" | |
| } >"$signing_dir/release.properties" | |
| chmod 600 "$signing_dir/release.properties" | |
| version_code=$((10#${RELEASE_TAG#r})) | |
| KODER_ANDROID_RELEASE_SIGNING_PROPERTIES="$signing_dir/release.properties" \ | |
| KODER_ANDROID_VERSION_CODE="$version_code" \ | |
| KODER_ANDROID_VERSION_NAME="$RELEASE_TAG" \ | |
| scripts/prepare-embedded-android release >/dev/null | |
| - name: Build Linux x64 artifact | |
| if: steps.meta.outputs.changed == 'true' | |
| env: | |
| VERSION: ${{ steps.meta.outputs.tag }} | |
| COMMIT: ${{ steps.meta.outputs.short_sha }} | |
| DIRTY: "false" | |
| BUILD_TIME: ${{ steps.meta.outputs.built_at }} | |
| KODER_EXTRA_LDFLAGS: "-s -w" | |
| GOOS: linux | |
| GOARCH: amd64 | |
| CGO_ENABLED: "0" | |
| KODER_EMBED_ANDROID: "0" | |
| run: | | |
| set -euo pipefail | |
| mkdir -p dist | |
| scripts/build-koder "dist/koder-${VERSION}-linux-amd64" | |
| (cd dist && sha256sum "koder-${VERSION}-linux-amd64" > "koder-${VERSION}-linux-amd64.sha256") | |
| - name: Build Linux ARM64 artifact | |
| if: steps.meta.outputs.changed == 'true' | |
| env: | |
| VERSION: ${{ steps.meta.outputs.tag }} | |
| COMMIT: ${{ steps.meta.outputs.short_sha }} | |
| DIRTY: "false" | |
| BUILD_TIME: ${{ steps.meta.outputs.built_at }} | |
| KODER_EXTRA_LDFLAGS: "-s -w" | |
| GOOS: linux | |
| GOARCH: arm64 | |
| CGO_ENABLED: "0" | |
| KODER_EMBED_ANDROID: "0" | |
| run: | | |
| set -euo pipefail | |
| mkdir -p dist | |
| scripts/build-koder "dist/koder-${VERSION}-linux-arm64" | |
| (cd dist && sha256sum "koder-${VERSION}-linux-arm64" > "koder-${VERSION}-linux-arm64.sha256") | |
| - name: Publish GitHub release | |
| if: steps.meta.outputs.changed == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ steps.meta.outputs.tag }} | |
| REPAIR_RELEASE: ${{ steps.meta.outputs.repair_release }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$REPAIR_RELEASE" == "true" ]]; then | |
| gh release upload "$TAG" \ | |
| "dist/koder-${TAG}-linux-amd64" \ | |
| "dist/koder-${TAG}-linux-amd64.sha256" \ | |
| "dist/koder-${TAG}-linux-arm64" \ | |
| "dist/koder-${TAG}-linux-arm64.sha256" \ | |
| --clobber | |
| gh release edit "$TAG" \ | |
| --title "$TAG" \ | |
| --notes-file release-notes.md | |
| else | |
| gh release create "$TAG" \ | |
| --target "$GITHUB_SHA" \ | |
| --title "$TAG" \ | |
| --notes-file release-notes.md \ | |
| "dist/koder-${TAG}-linux-amd64" \ | |
| "dist/koder-${TAG}-linux-amd64.sha256" \ | |
| "dist/koder-${TAG}-linux-arm64" \ | |
| "dist/koder-${TAG}-linux-arm64.sha256" | |
| fi |