diff options
Diffstat (limited to '.github/workflows/build.yml')
| -rw-r--r-- | .github/workflows/build.yml | 312 | +165 −147 |
1 files changed, 165 insertions, 147 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e1bd0e..27a4e8f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,6 @@ -# SPDX-FileCopyrightText: 2026 Nikolay Govorov +# Copyright (c) 2026 Nikolay Govorov # SPDX-License-Identifier: AGPL-3.0-or-later -# NOTE: Don't extend it; keep the logic in the Taskfile. -# We're using GitHub Actions as a temporary solution -# until Mirum can handle its own maintenance. - name: Build on: @@ -15,179 +11,201 @@ on: branches: [main] jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + with: + go-version-file: go.mod + + - name: Check licenses + uses: fsfe/reuse-action@676e2d560c9a403aa252096d99fcab3e1132b0f5 # v6.0.0 + + - name: Check formatting + run: test -z "$(gofmt -l .)" + + - name: Vet + run: go vet ./... + build: - name: Build and publish Nightly + name: Build runs-on: ubuntu-latest - concurrency: - group: >- - package-publish-mirum-${{ github.ref == 'refs/heads/main' && 'nightly' - || startsWith(github.ref, 'refs/tags/v') && 'stable' || github.ref }} - cancel-in-progress: false - permissions: - contents: write + outputs: + channel: ${{ steps.version.outputs.channel }} + version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: - fetch-depth: 0 + go-version-file: go.mod - - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3 + - name: Install tools + run: | + echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list + sudo apt update && sudo apt install nfpm + sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0 with: - version: 2026.7.5 - experimental: true - install: false + passphrase: ${{ secrets.GPG_PASSPHRASE }} + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} - - name: Install dependencies - run: mise bootstrap --locked --yes --update + - name: Determine version + id: version + run: | + if [[ "$GITHUB_REF" == refs/tags/v* ]]; then + echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT" + echo "channel=stable" >> "$GITHUB_OUTPUT" + else + echo "version=$(cat VERSION)~nightly.$(git log -1 --format=%ct)" >> "$GITHUB_OUTPUT" + echo "channel=nightly" >> "$GITHUB_OUTPUT" + fi - name: Build and package - run: task package GIT_REF=${{ github.ref }} GPG_KEY_ID=${{ vars.GPG_KEY_ID }} + run: | + printf '%s' "$GPG_PRIVATE_KEY" > /tmp/private.asc + chmod 600 /tmp/private.asc + export SIGNING_PRIVATE_KEY="/tmp/private.asc" + task package VERSION=${{ steps.version.outputs.version }} + rm -f /tmp/private.asc env: + GPG_KEY_ID: ${{ vars.GPG_KEY_ID }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - APK_PRIVATE_KEY: ${{ secrets.APK_PRIVATE_KEY }} - PACKAGE_KEY_VERSION: ${{ vars.PACKAGE_KEY_VERSION }} + NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - - name: Lint - run: task lint - - - name: Tests - run: task test - - - name: Upload container binaries - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: - name: container-binaries - path: | - build/mirum-server-linux-amd64 - build/mirum-server-linux-arm64 - build/mirum-worker-linux-amd64 - build/mirum-worker-linux-arm64 - if-no-files-found: error - - - name: Publish - if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - . build/dist/build.env - task publish:release CHANNEL=$CHANNEL VERSION=$VERSION - mise run publish -- \ - --service mirum \ - --channel "$CHANNEL" \ - --input build/dist \ - deb rpm apk - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - GPG_KEY_ID: ${{ vars.GPG_KEY_ID }} - APK_PRIVATE_KEY: ${{ secrets.APK_PRIVATE_KEY }} - PACKAGE_KEY_VERSION: ${{ vars.PACKAGE_KEY_VERSION }} - S3_BUCKET: ${{ vars.S3_BUCKET }} - S3_ENDPOINT: ${{ vars.S3_ENDPOINT }} - S3_PUBLIC_URL: ${{ vars.S3_PUBLIC_URL }} - S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} - S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} - - oci: - name: OCI artifacts - needs: [build] + name: packages + path: build/dist/* + + publish: + name: Publish runs-on: ubuntu-latest + needs: [lint, build] + if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') permissions: - contents: read - packages: write + contents: write steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3 - with: - version: 2026.7.5 - experimental: true - install: false + - name: Install tools + run: | + sudo apt-get update + sudo apt-get install -y apt-utils rclone createrepo-c - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: - name: container-binaries - path: .container - - - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 + name: packages + path: dist - - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 + # Configure GPG keys + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0 + with: + passphrase: ${{ secrets.GPG_PASSPHRASE }} + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + - name: Update nightly tag + if: needs.build.outputs.channel == 'nightly' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -f nightly + git push origin --force tag nightly - - name: Determine artifact version - id: artifact - shell: bash + - name: Delete old nightly assets + if: needs.build.outputs.channel == 'nightly' run: | - base_version=$(cat VERSION) - if [[ "$GITHUB_REF" == refs/heads/main ]]; then - version="$base_version-nightly.$(git log -1 --format=%ct)" - elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then - version="${GITHUB_REF_NAME#v}" - if [[ "$version" != "$base_version" ]]; then - echo "Tag version $version does not match VERSION $base_version" >&2 - exit 1 - fi - else - version="$base_version-pr.$GITHUB_RUN_NUMBER" - fi - echo "version=$version" >> "$GITHUB_OUTPUT" + for asset in $(gh release view nightly --json assets --jq '.assets[].name' 2>/dev/null || true); do + gh release delete-asset nightly "$asset" --yes + done + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Log in to GHCR - if: github.event_name != 'pull_request' - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4 + - name: Create GitHub Release + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Log Helm in to GHCR - if: github.event_name != 'pull_request' + name: ${{ needs.build.outputs.channel == 'stable' && needs.build.outputs.version || 'nightly' }} + tag_name: ${{ needs.build.outputs.channel == 'stable' && format('v{0}', needs.build.outputs.version) || 'nightly' }} + prerelease: ${{ needs.build.outputs.channel == 'nightly' }} + files: dist/* + body: | + **Build**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} env: - GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Update APT/RPM repos on S3 + - name: Configure rclone + run: | + mkdir -p ~/.config/rclone + cat > ~/.config/rclone/rclone.conf << EOF + [s3] + type = s3 + provider = ${{ vars.S3_PROVIDER || 'Other' }} + access_key_id = ${{ secrets.S3_ACCESS_KEY_ID }} + secret_access_key = ${{ secrets.S3_SECRET_ACCESS_KEY }} + region = ${{ vars.S3_REGION }} + endpoint = ${{ vars.S3_ENDPOINT }} + EOF + + - name: Upload static files run: | - printf '%s' "$GHCR_TOKEN" | mise x helm@4.1.1 -- \ - helm registry login ghcr.io --username "$GITHUB_ACTOR" --password-stdin + gpg --export --armor "${{ vars.GPG_KEY_ID }}" > public.gpg + rclone copyto public.gpg "s3:${{ vars.S3_BUCKET }}/public.gpg" + rclone copyto pkg/index.html "s3:${{ vars.S3_BUCKET }}/index.html" + rclone copyto pkg/404.html "s3:${{ vars.S3_BUCKET }}/404.html" - - name: Build and publish OCI artifacts - shell: bash + - name: Create APT repository run: | - version="${{ steps.artifact.outputs.version }}" - image_output=() - chart_output=() + CHANNEL=${{ needs.build.outputs.channel }} - if [[ "${{ github.event_name }}" != pull_request ]]; then - image_output+=(--push) - chart_output+=(--push "oci://ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/charts") - fi + mkdir -p apt-repo + rclone copy "s3:${{ vars.S3_BUCKET }}/apt/" apt-repo/ - for service in server worker; do - image="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/mirum-$service" - tags=( - --tag "$image:sha-$GITHUB_SHA" - --tag "$image:$version" - ) - labels=( - --label "org.opencontainers.image.revision=$GITHUB_SHA" - --label "org.opencontainers.image.source=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" - --label "org.opencontainers.image.version=$version" - ) - - if [[ "$GITHUB_REF" == refs/heads/main ]]; then - tags+=(--tag "$image:nightly") - elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then - tags+=(--tag "$image:latest") - fi - - mise run container -- \ - --context . \ - --file "cmd/mirum-$service/Dockerfile" \ - --platform linux/amd64,linux/arm64 \ - --cache-scope "mirum-$service" \ - "${tags[@]}" "${labels[@]}" "${image_output[@]}" + mkdir -p /tmp/apt-cache + for ch in stable nightly; do + mkdir -p apt-repo/pool/$ch + for arch in amd64 arm64 riscv64 ppc64le; do + mkdir -p apt-repo/dists/$ch/main/binary-$arch + done done + cp dist/*.deb apt-repo/pool/$CHANNEL/ + + cd apt-repo + apt-ftparchive generate "${{ github.workspace }}/pkg/apt-ftparchive.conf" + apt-ftparchive \ + -o APT::FTPArchive::Release::Codename=$CHANNEL \ + -o APT::FTPArchive::Release::Components=main \ + -o APT::FTPArchive::Release::Architectures="amd64 arm64 riscv64 ppc64le" \ + release dists/$CHANNEL/ > dists/$CHANNEL/Release + gpg --default-key="${{ vars.GPG_KEY_ID }}" --batch --yes -abs -o dists/$CHANNEL/Release.gpg dists/$CHANNEL/Release + gpg --default-key="${{ vars.GPG_KEY_ID }}" --batch --yes --clearsign -o dists/$CHANNEL/InRelease dists/$CHANNEL/Release + cd .. + + rclone copy apt-repo/ "s3:${{ vars.S3_BUCKET }}/apt/" --progress + + - name: Create RPM repository + run: | + CHANNEL=${{ needs.build.outputs.channel }} + + mkdir -p rpm-repo + rclone copy "s3:${{ vars.S3_BUCKET }}/rpm/$CHANNEL/" rpm-repo/ + + cp dist/*.rpm rpm-repo/ + + createrepo_c --update rpm-repo/ + gpg --default-key="${{ vars.GPG_KEY_ID }}" --batch --yes --detach-sign --armor rpm-repo/repodata/repomd.xml + + cat > rpm-repo/mirum-${CHANNEL}.repo << EOF + [mirum-${CHANNEL}] + name=Mirum ${CHANNEL} + gpgkey=${{ vars.S3_PUBLIC_URL }}/public.gpg + baseurl=${{ vars.S3_PUBLIC_URL }}/rpm/${CHANNEL}/ + enabled=1 + gpgcheck=1 + EOF - mise run chart -- \ - --chart charts/mirum \ - --version "$version" \ - --app-version "$version" \ - "${chart_output[@]}" + rclone copy rpm-repo/ "s3:${{ vars.S3_BUCKET }}/rpm/$CHANNEL/" --progress |
