feat(mcp-ui): next-step UX after register / install / on /connections… #334
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: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| rust: | |
| name: Rust Check & Test | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:18-alpine | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: think_watch_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| redis: | |
| image: redis:8-alpine | |
| ports: | |
| - 6379:6379 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| DATABASE_URL: postgres://postgres:postgres@localhost:5432/think_watch_test | |
| REDIS_URL: redis://localhost:6379 | |
| JWT_SECRET: ci-test-jwt-secret-not-for-production-use-00 | |
| ENCRYPTION_KEY: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-nextest | |
| # No standalone `cargo check` — clippy runs the borrow-checker | |
| # as a strict superset, so a separate check pass would just | |
| # rebuild the same artifacts twice. | |
| - name: Test | |
| run: cargo nextest run --workspace --lib --bins --tests | |
| - name: Clippy | |
| run: cargo clippy --workspace -- -D warnings | |
| - name: Format check | |
| run: cargo fmt --all -- --check | |
| frontend: | |
| name: Frontend Build | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: web | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| version: latest | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| cache-dependency-path: web/pnpm-lock.yaml | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: i18n parity | |
| run: pnpm check:i18n | |
| - name: Test | |
| run: pnpm test | |
| # `pnpm build` runs `tsc -b && vite build`. `tsc -b` (project | |
| # references) is stricter than `tsc --noEmit` — it catches | |
| # unused imports (TS6133) that --noEmit silently accepts — so | |
| # we rely on the build step for type checking. | |
| - name: Build | |
| run: pnpm build | |
| # --------------------------------------------------------------------------- | |
| # Docker Server: build each arch natively in parallel, then merge manifest | |
| # --------------------------------------------------------------------------- | |
| docker-server-build: | |
| name: Server Build (${{ matrix.platform }}) | |
| runs-on: ${{ matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} | |
| needs: [rust, frontend] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| permissions: | |
| contents: read | |
| packages: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| platform: [linux/amd64, linux/arm64] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set image prefix | |
| run: echo "IMAGE_PREFIX=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.IMAGE_PREFIX }}/think-watch-server | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/docker/Dockerfile.server | |
| platforms: ${{ matrix.platform }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| outputs: type=image,"name=${{ env.IMAGE_PREFIX }}/think-watch-server",push-by-digest=true,name-canonical=true,push=true | |
| cache-from: type=gha,scope=server-${{ matrix.platform }} | |
| cache-to: type=gha,scope=server-${{ matrix.platform }},mode=max | |
| - name: Export digest | |
| run: | | |
| mkdir -p ${{ runner.temp }}/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: server-digest-${{ strategy.job-index }} | |
| path: ${{ runner.temp }}/digests | |
| if-no-files-found: error | |
| retention-days: 1 | |
| docker-server-merge: | |
| name: Server Merge Manifest | |
| runs-on: ubuntu-latest | |
| needs: docker-server-build | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Set image prefix | |
| run: echo "IMAGE_PREFIX=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
| - name: Download digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: server-digest-* | |
| merge-multiple: true | |
| path: ${{ runner.temp }}/digests | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Create and push multi-arch manifest | |
| working-directory: ${{ runner.temp }}/digests | |
| run: | | |
| IMAGE="${IMAGE_PREFIX}/think-watch-server" | |
| docker buildx imagetools create \ | |
| -t "${IMAGE}:latest" \ | |
| -t "${IMAGE}:${{ github.sha }}" \ | |
| $(printf "${IMAGE}@sha256:%s " *) | |
| # --------------------------------------------------------------------------- | |
| # Docker Web: static files are arch-independent, single buildx with QEMU | |
| # --------------------------------------------------------------------------- | |
| docker-web: | |
| name: Web Build & Push | |
| runs-on: ubuntu-latest | |
| needs: [rust, frontend] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set image prefix | |
| run: echo "IMAGE_PREFIX=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build and push web image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/docker/Dockerfile.web | |
| push: true | |
| platforms: linux/amd64,linux/arm64 | |
| tags: | | |
| ${{ env.IMAGE_PREFIX }}/think-watch-web:latest | |
| ${{ env.IMAGE_PREFIX }}/think-watch-web:${{ github.sha }} | |
| cache-from: type=gha,scope=web | |
| cache-to: type=gha,scope=web,mode=max |