Skip to content

Commit beee405

Browse files
committed
ci: set up workflow
1 parent 4d3525e commit beee405

File tree

5 files changed

+368
-80
lines changed

5 files changed

+368
-80
lines changed

.github/workflows/ci.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
lint:
11+
name: Lint
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout repository
15+
uses: actions/checkout@v4
16+
17+
- name: Setup pnpm
18+
uses: pnpm/action-setup@v4
19+
with:
20+
version: 9
21+
22+
- name: Setup Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: "20"
26+
cache: "pnpm"
27+
28+
- name: Install dependencies
29+
run: pnpm install --frozen-lockfile
30+
31+
- name: Run lint
32+
run: pnpm lint
33+
34+
- name: Build packages
35+
run: pnpm build

.github/workflows/deploy.yml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Deploy to Cloud Run
2+
3+
on:
4+
workflow_run:
5+
workflows: ["CI"]
6+
types:
7+
- completed
8+
branches: [main]
9+
workflow_dispatch:
10+
11+
env:
12+
REGION: europe-west4
13+
SERVICE_NAME: cityjson-spec-mcp
14+
GAR_LOCATION: europe-west4
15+
GAR_REPOSITORY: cityjson-spec-mcp
16+
17+
jobs:
18+
build-and-push:
19+
name: Build and Push Docker Image
20+
runs-on: ubuntu-latest
21+
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
22+
permissions:
23+
contents: read
24+
packages: write
25+
id-token: write
26+
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
submodules: recursive
32+
33+
- name: Set up Docker Buildx
34+
uses: docker/setup-buildx-action@v3
35+
36+
- name: Google Auth
37+
id: auth
38+
uses: google-github-actions/auth@v2
39+
with:
40+
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
41+
project_id: ${{ secrets.PROJECT_ID }}
42+
43+
- name: Set up Cloud SDK
44+
uses: google-github-actions/setup-gcloud@v2
45+
46+
- name: Configure Docker for Artifact Registry
47+
run: gcloud auth configure-docker ${{ env.GAR_LOCATION }}-docker.pkg.dev
48+
49+
- name: Build and push container
50+
run: |-
51+
# Build the image
52+
docker build -t "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }}/${{ env.SERVICE_NAME }}:${{ github.sha }}" .
53+
54+
# Tag as latest
55+
docker tag "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }}/${{ env.SERVICE_NAME }}:${{ github.sha }}" "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }}/${{ env.SERVICE_NAME }}:latest"
56+
57+
# Push both tags
58+
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }}/${{ env.SERVICE_NAME }}:${{ github.sha }}"
59+
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }}/${{ env.SERVICE_NAME }}:latest"
60+
61+
- name: Verify image push
62+
run: |-
63+
echo "Verifying image was pushed successfully..."
64+
gcloud artifacts docker images list ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }} --include-tags --filter="tags:latest"
65+
66+
deploy:
67+
name: Deploy to Cloud Run
68+
needs: build-and-push
69+
runs-on: ubuntu-latest
70+
permissions:
71+
contents: read
72+
id-token: write
73+
74+
steps:
75+
- name: Checkout
76+
uses: actions/checkout@v4
77+
78+
- name: Google Auth
79+
id: auth
80+
uses: google-github-actions/auth@v2
81+
with:
82+
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
83+
project_id: ${{ secrets.PROJECT_ID }}
84+
85+
- name: Set up Cloud SDK
86+
uses: google-github-actions/setup-gcloud@v2
87+
88+
- name: Deploy to Cloud Run
89+
id: deploy
90+
uses: google-github-actions/deploy-cloudrun@v2
91+
with:
92+
service: ${{ env.SERVICE_NAME }}
93+
region: ${{ env.REGION }}
94+
image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ secrets.PROJECT_ID }}/${{ env.GAR_REPOSITORY }}/${{ env.SERVICE_NAME }}:latest
95+
flags: |
96+
--port=8080
97+
--min-instances=0
98+
--max-instances=3
99+
--cpu=1
100+
--memory=256Mi
101+
--timeout=300
102+
--allow-unauthenticated
103+
104+
- name: Show deployed URL
105+
run: echo "Deployed to ${{ steps.deploy.outputs.url }}"

.github/workflows/publish.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Publish to npm
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
inputs:
8+
dry_run:
9+
description: "Dry run (don't actually publish)"
10+
required: false
11+
default: false
12+
type: boolean
13+
14+
jobs:
15+
publish:
16+
name: Publish to npm
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read
20+
id-token: write
21+
22+
steps:
23+
- name: Checkout repository
24+
uses: actions/checkout@v4
25+
with:
26+
submodules: recursive
27+
28+
- name: Setup pnpm
29+
uses: pnpm/action-setup@v4
30+
with:
31+
version: 9
32+
33+
- name: Setup Node.js
34+
uses: actions/setup-node@v4
35+
with:
36+
node-version: "24"
37+
cache: "pnpm"
38+
registry-url: "https://registry.npmjs.org"
39+
40+
- name: Install dependencies
41+
run: pnpm install --frozen-lockfile
42+
43+
- name: Build packages
44+
run: pnpm build
45+
46+
- name: Copy specs to mcp-server package
47+
run: cp -r specs packages/mcp-server/
48+
49+
- name: Publish mcp-server to npm
50+
working-directory: packages/mcp-server
51+
run: |
52+
if [ "${{ inputs.dry_run }}" = "true" ]; then
53+
echo "Dry run - would publish:"
54+
npm pack --dry-run
55+
else
56+
npm publish --provenance --access public
57+
fi
58+
env:
59+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Dockerfile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Build stage
2+
FROM node:24-alpine AS builder
3+
4+
# Install pnpm
5+
RUN corepack enable && corepack prepare pnpm@9 --activate
6+
7+
WORKDIR /app
8+
9+
# Copy package files
10+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
11+
COPY packages/spec-converter/package.json ./packages/spec-converter/
12+
COPY packages/mcp-server/package.json ./packages/mcp-server/
13+
14+
# Install dependencies
15+
RUN pnpm install --frozen-lockfile
16+
17+
# Copy source files
18+
COPY tsconfig.base.json ./
19+
COPY biome.json ./
20+
COPY packages/spec-converter/ ./packages/spec-converter/
21+
COPY packages/mcp-server/ ./packages/mcp-server/
22+
23+
# Build all packages
24+
RUN pnpm build
25+
26+
# Runtime stage
27+
FROM node:24-alpine AS runtime
28+
29+
WORKDIR /app
30+
31+
# Copy built files and specs
32+
COPY --from=builder /app/packages/mcp-server/dist ./packages/mcp-server/dist
33+
COPY --from=builder /app/packages/mcp-server/package.json ./packages/mcp-server/
34+
COPY --from=builder /app/node_modules ./node_modules
35+
COPY specs ./specs
36+
37+
# Set environment variables
38+
ENV TRANSPORT=http
39+
ENV PORT=8080
40+
ENV CITYJSON_SPECS_PATH=/app/specs
41+
42+
EXPOSE 8080
43+
44+
# Run the MCP server
45+
CMD ["node", "packages/mcp-server/dist/index.js"]

0 commit comments

Comments
 (0)