diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c332a342..60abff1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,48 +6,14 @@ on: - "v*.*.*" jobs: - build-docker-image: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout code - uses: actions/checkout@v3 - - name: Docker metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ghcr.io/${{ github.repository }} - tags: | - type=semver,pattern={{version}},prefix=v - type=semver,pattern={{major}}.{{minor}},prefix=v - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: "Login to GitHub Container Registry" - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{github.repository_owner}} - password: ${{secrets.GITHUB_TOKEN}} - - name: Build and push - uses: docker/build-push-action@v4 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - build-binaries: + build: runs-on: ubuntu-latest permissions: contents: write + packages: write + attestations: write + id-token: write steps: - name: Checkout code uses: actions/checkout@v3 @@ -57,14 +23,70 @@ jobs: node-version: 22 cache: "npm" cache-dependency-path: frontend/package-lock.json + - uses: actions/setup-go@v5 + with: + go-version-file: 'backend/go.mod' + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set DOCKER_IMAGE_NAME + run: | + # Lowercase REPO_OWNER which is required for containers + REPO_OWNER=${{ github.repository_owner }} + DOCKER_IMAGE_NAME="ghcr.io/${REPO_OWNER,,}/pocket-id" + echo "DOCKER_IMAGE_NAME=${DOCKER_IMAGE_NAME}" >>${GITHUB_ENV} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{github.repository_owner}} + password: ${{secrets.GITHUB_TOKEN}} + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKER_IMAGE_NAME }} + tags: | + type=semver,pattern={{version}},prefix=v + type=semver,pattern={{major}}.{{minor}},prefix=v + - name: Install frontend dependencies working-directory: frontend run: npm ci - name: Build frontend working-directory: frontend run: npm run build + - name: Build binaries run: sh scripts/development/build-binaries.sh + + - name: Build and push container image + uses: docker/build-push-action@v4 + id: container-build-push + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + file: Dockerfile-prebuilt + + - name: Binary attestation + uses: actions/attest-build-provenance@v2 + with: + subject-path: 'backend/.bin/pocket-id-**' + + - name: Container image attestation + uses: actions/attest-build-provenance@v2 + with: + subject-name: '${{ env.DOCKER_IMAGE_NAME }}' + subject-digest: ${{ steps.container-build-push.digest }} + push-to-registry: true + - name: Upload binaries to release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -72,7 +94,7 @@ jobs: publish-release: runs-on: ubuntu-latest - needs: [build-docker-image, build-binaries] + needs: [build] permissions: contents: write env: diff --git a/Dockerfile b/Dockerfile index fc8fe23c..03c5f4eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,5 @@ +# This file uses multi-stage builds to build the application from source, including the front-end + # Tags passed to "go build" ARG BUILD_TAGS="" @@ -26,7 +28,8 @@ RUN VERSION=$(cat /build/.version) \ GOOS=linux \ go build \ -tags "${BUILD_TAGS}" \ - -ldflags="-X github.com/pocket-id/pocket-id/backend/internal/common.Version=${VERSION}" \ + -ldflags="-X github.com/pocket-id/pocket-id/backend/internal/common.Version=${VERSION} -buildid=${VERSION}" \ + -trimpath \ -o /build/pocket-id-backend \ . diff --git a/Dockerfile-prebuilt b/Dockerfile-prebuilt new file mode 100644 index 00000000..90bb78fd --- /dev/null +++ b/Dockerfile-prebuilt @@ -0,0 +1,20 @@ +# This Dockerfile embeds a pre-built binary for the given Linux architecture +# Binaries must be built using ./scripts/development/build-binaries.sh first + +FROM alpine + +# TARGETARCH can be "amd64" or "arm64" +ARG TARGETARCH="" + +WORKDIR /app + +RUN apk add --no-cache curl su-exec + +COPY ./backend/.bin/pocket-id-linux-${TARGETARCH} /app/pocket-id +COPY ./scripts/docker /app/docker + +EXPOSE 1411 +ENV APP_ENV=production + +ENTRYPOINT ["/app/docker/entrypoint.sh"] +CMD ["/app/pocket-id"] diff --git a/scripts/development/build-binaries.sh b/scripts/development/build-binaries.sh old mode 100644 new mode 100755 index 98220053..c64e4ecf --- a/scripts/development/build-binaries.sh +++ b/scripts/development/build-binaries.sh @@ -8,7 +8,8 @@ build_platform() { os=$2 arch=$3 arm_version=${4:-""} - pocket_id_version=$(cat ../.version) + # "sed" is used to remove leading or trailing whitespace characters + pocket_id_version=$(cat ../.version | sed 's/^\s*\|\s*$//g') # Set the binary extension to exe for Windows binary_ext="" @@ -21,14 +22,14 @@ build_platform() { printf "Building %s/%s%s" "$os" "$arch" "$([ -n "$arm_version" ] && echo " GOARM=$arm_version" || echo "")... " # Build environment variables - env_vars="GOOS=${os} GOARCH=${arch}" + env_vars="CGO_ENABLED=0 GOOS=${os} GOARCH=${arch}" if [ -n "$arm_version" ]; then env_vars="${env_vars} GOARM=${arm_version}" fi # Build the binary eval "${env_vars} go build \ - -ldflags='-X github.com/pocket-id/pocket-id/backend/internal/common.Version=${pocket_id_version}' \ + -ldflags='-X github.com/pocket-id/pocket-id/backend/internal/common.Version=${pocket_id_version} -buildid ${pocket_id_version}' \ -o \"${output_dir}\" \ -trimpath \ ./cmd" diff --git a/scripts/development/create-release.sh b/scripts/development/create-release.sh old mode 100644 new mode 100755 diff --git a/scripts/development/deploy-development-image.sh b/scripts/development/deploy-development-image.sh old mode 100644 new mode 100755 diff --git a/scripts/docker/entrypoint.sh b/scripts/docker/entrypoint.sh old mode 100644 new mode 100755