fix(quick-create): remove daemon CLI version gate #15
Workflow file for this run
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: Release | |
| on: | |
| push: | |
| tags: | |
| # GitHub Actions uses glob patterns here, not regex. Match versioned | |
| # tags broadly at the trigger layer, then enforce strict semver below. | |
| - "v*.*.*" | |
| - "!v*-dirty*" | |
| permissions: | |
| contents: write | |
| packages: write | |
| jobs: | |
| verify: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag_name: ${{ steps.release_meta.outputs.tag_name }} | |
| is_stable: ${{ steps.release_meta.outputs.is_stable }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate tag name | |
| id: release_meta | |
| shell: bash | |
| run: | | |
| tag="${GITHUB_REF_NAME}" | |
| echo "Triggered by tag: $tag" | |
| if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then | |
| echo "::error::Release tags must look like vX.Y.Z or vX.Y.Z-suffix; got '$tag'." | |
| exit 1 | |
| fi | |
| if [[ "$tag" == *-dirty* ]]; then | |
| echo "::error::Refusing to release from dirty tag '$tag'." | |
| exit 1 | |
| fi | |
| echo "tag_name=$tag" >> "$GITHUB_OUTPUT" | |
| if [[ "$tag" == *-* ]]; then | |
| echo "is_stable=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is_stable=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: server/go.mod | |
| cache-dependency-path: server/go.sum | |
| - name: Run tests | |
| run: cd server && go test -race ./... | |
| release: | |
| needs: verify | |
| # Only run on the canonical upstream repo. Forks don't have the | |
| # HOMEBREW_TAP_GITHUB_TOKEN secret and should not be publishing to | |
| # `multica-ai/homebrew-tap` anyway. Without this guard, every fork's | |
| # tag push fails this job (401 against the upstream tap), which makes | |
| # downstream CI go red without affecting the actual artifact pipeline. | |
| if: github.repository_owner == 'multica-ai' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: server/go.mod | |
| cache-dependency-path: server/go.sum | |
| - name: Run GoReleaser | |
| uses: goreleaser/goreleaser-action@v6 | |
| with: | |
| version: "~> v2" | |
| args: release --clean | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} | |
| # Multi-arch images are built natively per platform on dedicated runners | |
| # (amd64 on ubuntu-latest, arm64 on ubuntu-24.04-arm) and merged into a | |
| # manifest list. This avoids QEMU emulation, which was making the Next.js | |
| # arm64 build run for 30+ minutes per release. | |
| docker-backend-build: | |
| needs: verify | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runs-on: ubuntu-latest | |
| - platform: linux/arm64 | |
| runs-on: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runs-on }} | |
| steps: | |
| - name: Prepare | |
| run: | | |
| platform=${{ matrix.platform }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV" | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Compute backend image labels | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/multica-backend | |
| labels: | | |
| org.opencontainers.image.title=Multica Backend | |
| org.opencontainers.image.description=Multica self-hosted backend | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: Dockerfile | |
| pull: true | |
| platforms: ${{ matrix.platform }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=release-backend-${{ env.PLATFORM_PAIR }} | |
| cache-to: type=gha,mode=max,scope=release-backend-${{ env.PLATFORM_PAIR }} | |
| build-args: | | |
| VERSION=${{ needs.verify.outputs.tag_name }} | |
| COMMIT=${{ github.sha }} | |
| outputs: type=image,name=ghcr.io/${{ github.repository_owner }}/multica-backend,push-by-digest=true,name-canonical=true,push=true | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests-backend-${{ env.PLATFORM_PAIR }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| docker-backend-merge: | |
| needs: [verify, docker-backend-build] | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: release-docker-backend-${{ github.ref }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-backend-* | |
| merge-multiple: true | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Compute backend image tags | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/multica-backend | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=latest,enable=${{ needs.verify.outputs.is_stable == 'true' }} | |
| type=raw,value=${{ needs.verify.outputs.tag_name }} | |
| type=sha,prefix=sha- | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create manifest list and push | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf 'ghcr.io/${{ github.repository_owner }}/multica-backend@sha256:%s ' *) | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect \ | |
| ghcr.io/${{ github.repository_owner }}/multica-backend:${{ steps.meta.outputs.version }} | |
| docker-web-build: | |
| needs: verify | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runs-on: ubuntu-latest | |
| - platform: linux/arm64 | |
| runs-on: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runs-on }} | |
| steps: | |
| - name: Prepare | |
| run: | | |
| platform=${{ matrix.platform }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV" | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Compute web image labels | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/multica-web | |
| labels: | | |
| org.opencontainers.image.title=Multica Web | |
| org.opencontainers.image.description=Multica self-hosted web frontend | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: Dockerfile.web | |
| pull: true | |
| platforms: ${{ matrix.platform }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=release-web-${{ env.PLATFORM_PAIR }} | |
| cache-to: type=gha,mode=max,scope=release-web-${{ env.PLATFORM_PAIR }} | |
| build-args: | | |
| REMOTE_API_URL=http://backend:8080 | |
| NEXT_PUBLIC_APP_VERSION=${{ needs.verify.outputs.tag_name }} | |
| outputs: type=image,name=ghcr.io/${{ github.repository_owner }}/multica-web,push-by-digest=true,name-canonical=true,push=true | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests-web-${{ env.PLATFORM_PAIR }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| docker-web-merge: | |
| needs: [verify, docker-web-build] | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: release-docker-web-${{ github.ref }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-web-* | |
| merge-multiple: true | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Compute web image tags | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/multica-web | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=latest,enable=${{ needs.verify.outputs.is_stable == 'true' }} | |
| type=raw,value=${{ needs.verify.outputs.tag_name }} | |
| type=sha,prefix=sha- | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create manifest list and push | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf 'ghcr.io/${{ github.repository_owner }}/multica-web@sha256:%s ' *) | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect \ | |
| ghcr.io/${{ github.repository_owner }}/multica-web:${{ steps.meta.outputs.version }} | |
| helm-chart: | |
| needs: [verify, docker-backend-merge, docker-web-merge] | |
| if: github.repository_owner == 'multica-ai' | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: release-helm-chart-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CHART_DIR: deploy/helm/multica | |
| OCI_REGISTRY: oci://ghcr.io/${{ github.repository_owner }}/charts | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Helm | |
| uses: azure/setup-helm@v4 | |
| - name: Sync chart metadata with release tag | |
| env: | |
| TAG_NAME: ${{ needs.verify.outputs.tag_name }} | |
| run: | | |
| chart_version="${TAG_NAME#v}" | |
| sed -i -E "s/^version:.*/version: ${chart_version}/" "$CHART_DIR/Chart.yaml" | |
| sed -i -E "s/^appVersion:.*/appVersion: \"${TAG_NAME}\"/" "$CHART_DIR/Chart.yaml" | |
| echo "CHART_VERSION=${chart_version}" >> "$GITHUB_ENV" | |
| - name: Lint chart | |
| run: helm lint "$CHART_DIR" | |
| - name: Package chart | |
| run: helm package "$CHART_DIR" --destination .chart-packages | |
| - name: Login to GHCR | |
| run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username "${{ github.actor }}" --password-stdin | |
| - name: Push chart to GHCR | |
| run: helm push ".chart-packages/multica-${CHART_VERSION}.tgz" "$OCI_REGISTRY" | |
| - name: Verify published chart | |
| run: helm show chart "$OCI_REGISTRY/multica" --version "$CHART_VERSION" | |
| # Build the Desktop installers for Linux and Windows and upload them to | |
| # the GitHub Release that the `release` job above just published. macOS | |
| # Desktop continues to ship via the manual `release-desktop` skill so it | |
| # can be signed + notarized with Apple Developer credentials that are | |
| # not (yet) wired into CI. | |
| desktop: | |
| needs: release | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: linux | |
| - os: windows-latest | |
| target: win | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install rpmbuild (Linux) | |
| if: matrix.target == 'linux' | |
| run: sudo apt-get update && sudo apt-get install -y rpm | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: server/go.mod | |
| cache-dependency-path: server/go.sum | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Package Desktop installers (${{ matrix.target }}) | |
| working-directory: apps/desktop | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # electron-builder's GitHub publisher reads this: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Disable code signing on Linux/Windows for now — the public | |
| # release is unsigned for these platforms, the CLI carries the | |
| # trust boundary. Set CSC_LINK in repo secrets to enable | |
| # Windows signing later. | |
| CSC_IDENTITY_AUTO_DISCOVERY: "false" | |
| run: node scripts/package.mjs --${{ matrix.target }} --x64 --arm64 --publish always |