diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml new file mode 100644 index 0000000..b99448f --- /dev/null +++ b/.github/workflows/build-and-release.yml @@ -0,0 +1,140 @@ +name: Build and Release + +on: + push: + branches: + - main + tags: + - 'v*' + pull_request: + workflow_dispatch: + inputs: + tag_name: + description: 'Optional release tag when manually publishing, for example v1.0.0' + required: false + type: string + +env: + IMAGE_NAME: ghcr.io/smile-qwq/subtracker-api + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Prisma generate + run: npm run prisma:generate + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build + + - name: Archive web dist + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + run: | + cd apps/web/dist + zip -r ../../../subtracker-web-dist.zip . + + - name: Upload web artifact + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + uses: actions/upload-artifact@v4 + with: + name: subtracker-web-dist + path: subtracker-web-dist.zip + + release: + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + needs: build + permissions: + contents: write + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Prisma generate + run: npm run prisma:generate + + - name: Build shared package + run: npm run build -w packages/shared + + - name: Build web + run: npm run build -w apps/web + + - name: Archive web dist + run: | + cd apps/web/dist + zip -r ../../../subtracker-web-dist.zip . + + - name: Resolve release tag + id: release_tag + shell: bash + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.tag_name }}" ]; then + echo "value=${{ github.event.inputs.tag_name }}" >> "$GITHUB_OUTPUT" + else + echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + fi + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=ref,event=tag + type=sha + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Create or update GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.release_tag.outputs.value }} + name: ${{ steps.release_tag.outputs.value }} + files: subtracker-web-dist.zip + generate_release_notes: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index e0f0c05..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: CI - -on: - push: - branches: - - main - pull_request: - -jobs: - build-and-check: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: npm - - - name: Install dependencies - run: npm ci - - - name: Prisma generate - run: npm run prisma:generate - - - name: Lint - run: npm run lint - - - name: Build - run: npm run build diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml deleted file mode 100644 index 817bd92..0000000 --- a/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Docker Publish - -on: - push: - branches: - - main - tags: - - 'v*' - workflow_dispatch: - -env: - IMAGE_NAME: ghcr.io/smile-qwq/subtracker-api - -jobs: - docker: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - 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: Extract Docker metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=ref,event=branch - type=ref,event=tag - type=sha - - - name: Build and push Docker image - uses: docker/build-push-action@v6 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index b62bd5f..c6740c4 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -119,10 +119,13 @@ npm run build -w apps/web ## 7. GitHub Actions 与镜像发布 -仓库已预置两个 workflow: +仓库已预置一个统一 workflow: -- `CI`:在 `main` 和 PR 上执行安装、Prisma Generate、Lint、Build -- `Docker Publish`:在 `main`、`v*` tag 或手动触发时发布 API 镜像到 GHCR +- `Build and Release` + - 在 `main` 和 PR 上执行安装、Prisma Generate、Lint、Build + - 在 `v*` tag 或手动触发时,额外发布: + - API Docker 镜像到 GHCR + - 前端静态文件 `subtracker-web-dist.zip` 到 GitHub Release 默认镜像发布地址: @@ -130,6 +133,11 @@ npm run build -w apps/web ghcr.io/smile-qwq/subtracker-api ``` +前端静态文件发布方式: + +- Release asset:`subtracker-web-dist.zip` +- 可直接下载后解压到外部 Nginx 静态目录 + ## 8. 升级流程 当 API 镜像发布完成后,服务器只需: diff --git a/apps/api/package.json b/apps/api/package.json index bd28762..a36b944 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -1,6 +1,6 @@ { "name": "@subtracker/api", - "version": "0.1.0", + "version": "0.0.1", "private": true, "type": "module", "scripts": { @@ -17,7 +17,7 @@ "dependencies": { "@fastify/cors": "^10.0.2", "@prisma/client": "^6.6.0", - "@subtracker/shared": "0.1.0", + "@subtracker/shared": "0.0.1", "dayjs": "^1.11.13", "fastify": "^5.2.2", "node-cron": "^4.0.5", diff --git a/apps/web/package.json b/apps/web/package.json index 6c76c18..aede9bb 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@subtracker/web", - "version": "0.1.0", + "version": "0.0.1", "private": true, "type": "module", "scripts": { @@ -11,7 +11,7 @@ "lint": "vue-tsc --noEmit" }, "dependencies": { - "@subtracker/shared": "0.1.0", + "@subtracker/shared": "0.0.1", "@tanstack/vue-query": "^5.74.9", "@vicons/ionicons5": "^0.13.0", "@vueuse/core": "^13.0.0", diff --git a/package-lock.json b/package-lock.json index cc09c4e..2007a2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "subtracker", - "version": "0.1.0", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "subtracker", - "version": "0.1.0", + "version": "0.0.1", "workspaces": [ "apps/*", "packages/*" @@ -18,11 +18,11 @@ }, "apps/api": { "name": "@subtracker/api", - "version": "0.1.0", + "version": "0.0.1", "dependencies": { "@fastify/cors": "^10.0.2", "@prisma/client": "^6.6.0", - "@subtracker/shared": "0.1.0", + "@subtracker/shared": "0.0.1", "dayjs": "^1.11.13", "fastify": "^5.2.2", "node-cron": "^4.0.5", @@ -42,9 +42,9 @@ }, "apps/web": { "name": "@subtracker/web", - "version": "0.1.0", + "version": "0.0.1", "dependencies": { - "@subtracker/shared": "0.1.0", + "@subtracker/shared": "0.0.1", "@tanstack/vue-query": "^5.74.9", "@vicons/ionicons5": "^0.13.0", "@vueuse/core": "^13.0.0", @@ -6318,7 +6318,7 @@ }, "packages/shared": { "name": "@subtracker/shared", - "version": "0.1.0", + "version": "0.0.1", "dependencies": { "zod": "^3.24.3" }, diff --git a/package.json b/package.json index 876867f..d13962e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "subtracker", - "version": "0.1.0", + "version": "0.0.1", "private": true, "description": "Subscription tracker with currency conversion, reminder webhooks, statistics and calendar.", "workspaces": [ diff --git a/packages/shared/package.json b/packages/shared/package.json index ece6f09..3883fbb 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@subtracker/shared", - "version": "0.1.0", + "version": "0.0.1", "private": true, "type": "module", "main": "src/index.ts",