diff --git a/.gitea/workflows/release-image.yml b/.gitea/workflows/release-image.yml new file mode 100644 index 00000000..7e68d2e1 --- /dev/null +++ b/.gitea/workflows/release-image.yml @@ -0,0 +1,96 @@ +name: Release Image + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to release, for example v0.1.140' + required: true + type: string + +jobs: + image: + runs-on: linux_amd64 + env: + GITEA_BASE_URL: http://git.jianshixingqiu.com + GITEA_API_URL: http://git.jianshixingqiu.com/api/v1 + GITEA_OWNER: kgod + GITEA_REPO: sub2api + IMAGE_NAME: git.jianshixingqiu.com/kgod/sub2api + steps: + - name: Checkout + env: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} + run: | + set -eu + rm -rf .git + git init + git remote add origin "http://kgod:${RELEASE_TOKEN}@git.jianshixingqiu.com/kgod/sub2api.git" + if [ -n "${{ inputs.tag }}" ]; then + git fetch --depth 1 origin "refs/tags/${{ inputs.tag }}" + else + git fetch --depth 1 origin "$GITHUB_REF" + fi + git checkout --force FETCH_HEAD + + - name: Prepare metadata + run: | + set -eu + if [ -n "${{ inputs.tag }}" ]; then + TAG="${{ inputs.tag }}" + else + TAG="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}" + fi + VERSION="${TAG#v}" + COMMIT="$(git rev-parse --short=12 HEAD)" + BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + + echo "TAG=${TAG}" >> "$GITHUB_ENV" + echo "VERSION=${VERSION}" >> "$GITHUB_ENV" + echo "COMMIT=${COMMIT}" >> "$GITHUB_ENV" + echo "BUILD_DATE=${BUILD_DATE}" >> "$GITHUB_ENV" + + - name: Login to Gitea Container Registry + env: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} + run: | + set -eu + echo "$RELEASE_TOKEN" | docker login git.jianshixingqiu.com -u kgod --password-stdin + + - name: Build image + run: | + set -eu + docker build \ + -f Dockerfile.gitea \ + --build-arg VERSION="$VERSION" \ + --build-arg COMMIT="$COMMIT" \ + --build-arg BUILD_DATE="$BUILD_DATE" \ + --label "org.opencontainers.image.version=$VERSION" \ + --label "org.opencontainers.image.revision=$COMMIT" \ + --label "org.opencontainers.image.source=$GITEA_BASE_URL/$GITEA_OWNER/$GITEA_REPO" \ + -t "$IMAGE_NAME:$VERSION" \ + -t "$IMAGE_NAME:latest" \ + . + + - name: Push image + run: | + set -eu + docker push "$IMAGE_NAME:$VERSION" + docker push "$IMAGE_NAME:latest" + + - name: Create Gitea release + env: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} + run: | + set -eu + BODY="Docker image: ${IMAGE_NAME}:${VERSION}" + PAYLOAD=$(printf '{"tag_name":"%s","target_commitish":"%s","name":"Sub2API %s","body":"%s","draft":false,"prerelease":false}' "$TAG" "$(git rev-parse HEAD)" "$VERSION" "$BODY") + curl -fsS \ + -X POST \ + -H "Authorization: token ${RELEASE_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "$PAYLOAD" \ + "$GITEA_API_URL/repos/$GITEA_OWNER/$GITEA_REPO/releases" || true diff --git a/Dockerfile.gitea b/Dockerfile.gitea new file mode 100644 index 00000000..04919071 --- /dev/null +++ b/Dockerfile.gitea @@ -0,0 +1,86 @@ +# syntax=docker/dockerfile:1 + +ARG NODE_IMAGE=node:20-alpine +ARG GO_IMAGE=golang:1.26.3-alpine +ARG ALPINE_IMAGE=alpine:3.21 +ARG POSTGRES_IMAGE=postgres:18-alpine + +FROM ${NODE_IMAGE} AS frontend +WORKDIR /src + +RUN corepack enable + +COPY frontend/package.json frontend/pnpm-lock.yaml ./frontend/ +WORKDIR /src/frontend +RUN pnpm install --frozen-lockfile + +WORKDIR /src +COPY frontend ./frontend +COPY backend/internal/web ./backend/internal/web +RUN cd frontend && pnpm run build + +FROM ${GO_IMAGE} AS backend-builder +RUN apk add --no-cache ca-certificates git +WORKDIR /src + +COPY backend/go.mod backend/go.sum ./backend/ +RUN cd backend && go mod download + +COPY backend ./backend +COPY --from=frontend /src/backend/internal/web/dist ./backend/internal/web/dist + +ARG VERSION=0.0.0-dev +ARG COMMIT=unknown +ARG BUILD_DATE=unknown + +RUN cd backend && \ + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ + -tags=embed \ + -ldflags="-s -w -X main.Version=${VERSION} -X main.Commit=${COMMIT} -X main.Date=${BUILD_DATE} -X main.BuildType=release" \ + -o /out/sub2api \ + ./cmd/server + +FROM ${POSTGRES_IMAGE} AS pg-client + +FROM ${ALPINE_IMAGE} + +LABEL maintainer="Wei-Shaw " +LABEL description="Sub2API - AI API Gateway Platform" +LABEL org.opencontainers.image.source="http://git.jianshixingqiu.com/kgod/sub2api" + +RUN apk add --no-cache \ + ca-certificates \ + tzdata \ + curl \ + su-exec \ + libpq \ + zstd-libs \ + lz4-libs \ + krb5-libs \ + libldap \ + libedit \ + && rm -rf /var/cache/apk/* + +COPY --from=pg-client /usr/local/bin/pg_dump /usr/local/bin/pg_dump +COPY --from=pg-client /usr/local/bin/psql /usr/local/bin/psql +COPY --from=pg-client /usr/local/lib/libpq.so.5* /usr/local/lib/ + +RUN addgroup -g 1000 sub2api && \ + adduser -u 1000 -G sub2api -s /bin/sh -D sub2api + +WORKDIR /app + +COPY --from=backend-builder /out/sub2api /app/sub2api +COPY deploy/docker-entrypoint.sh /app/docker-entrypoint.sh + +RUN mkdir -p /app/data && \ + chown -R sub2api:sub2api /app && \ + chmod +x /app/docker-entrypoint.sh + +EXPOSE 8080 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -f http://localhost:${SERVER_PORT:-8080}/health || exit 1 + +ENTRYPOINT ["/app/docker-entrypoint.sh"] +CMD ["/app/sub2api"]