-
Notifications
You must be signed in to change notification settings - Fork 6
chore: add docker workflow #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c80fbc2
d88f382
8998b92
631d5f4
b9cfdb0
1c00e5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| name: Build and Publish Docker Image | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| version: | ||
| description: "Version tag (e.g., 1.0.2)" | ||
| required: true | ||
| type: string | ||
|
|
||
| env: | ||
| IMAGE: sweetr/sweetr | ||
|
|
||
| jobs: | ||
| validate: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
|
|
||
| services: | ||
| postgres: | ||
| image: postgres:16 | ||
| env: | ||
| POSTGRES_USER: test | ||
| POSTGRES_PASSWORD: test | ||
| POSTGRES_DB: sweetr_test | ||
| ports: | ||
| - 5432:5432 | ||
| options: >- | ||
| --health-cmd pg_isready | ||
| --health-interval 10s | ||
| --health-timeout 5s | ||
| --health-retries 5 | ||
| dragonfly: | ||
| image: docker.dragonflydb.io/dragonflydb/dragonfly | ||
| ports: | ||
| - 6379:6379 | ||
| options: >- | ||
| --health-cmd "redis-cli ping" | ||
| --health-interval 10s | ||
| --health-timeout 5s | ||
| --health-retries 5 | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Build image | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| file: ./apps/api/Dockerfile | ||
| push: false | ||
| load: true | ||
| tags: ${{ env.IMAGE }}:test | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
|
|
||
| - name: Start container | ||
| run: | | ||
| docker run -d --name sweetr-api --network host \ | ||
| -e PORT=8000 \ | ||
| -e FRONTEND_URL=http://localhost:3000 \ | ||
| -e USE_SELF_SIGNED_SSL=false \ | ||
| -e JWT_SECRET=test-secret \ | ||
| -e DATABASE_URL=postgres://test:test@localhost:5432/sweetr_test \ | ||
| -e REDIS_CONNECTION_STRING=redis://localhost:6379 \ | ||
| -e GITHUB_CLIENT_SECRET=test \ | ||
| -e GITHUB_CLIENT_ID=test \ | ||
| -e GITHUB_APP_HANDLE=test \ | ||
| -e GITHUB_APP_ID=test \ | ||
| -e GITHUB_APP_PRIVATE_KEY=test \ | ||
| -e GITHUB_WEBHOOK_SECRET=test \ | ||
| ${{ env.IMAGE }}:test | ||
|
|
||
| - name: Wait for API to be ready | ||
| run: | | ||
| for i in $(seq 1 30); do | ||
| if curl -sf http://localhost:8000/health > /dev/null 2>&1; then | ||
| echo "API is healthy" | ||
| exit 0 | ||
| fi | ||
| echo "Waiting for API... (attempt $i/30)" | ||
| sleep 2 | ||
| done | ||
| echo "API failed to start. Container logs:" | ||
| docker logs sweetr-api | ||
| exit 1 | ||
|
|
||
| publish: | ||
| needs: validate | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Login to Docker Hub | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
|
|
||
| - name: Build and push | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| file: ./apps/api/Dockerfile | ||
| push: true | ||
| tags: | | ||
| ${{ env.IMAGE }}:${{ inputs.version }} | ||
| ${{ env.IMAGE }}:latest | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
|
Comment on lines
+93
to
+122
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Publish job rebuilds instead of reusing validated image. The |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import { Router } from "express"; | ||
|
|
||
| export const healthRouter = Router(); | ||
|
|
||
| healthRouter.get("/health", (_req, res) => { | ||
| res.status(200).json({ status: "ok" }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,53 +35,47 @@ export const env = envsafe({ | |
| }), | ||
| GITHUB_WEBHOOK_SECRET: str({ | ||
| desc: "The secret string used to sign GitHub webhooks", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| }), | ||
| GITHUB_APP_ID: str({ desc: "The application id" }), | ||
| GITHUB_APP_PRIVATE_KEY: str({ desc: "The application private key" }), | ||
| STRIPE_API_KEY: str({ | ||
| desc: "The secret API Key for Stripe access", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| default: "", | ||
| }), | ||
| STRIPE_WEBHOOK_SECRET: str({ | ||
| desc: "The secret string used to sign Stripe webhooks", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| default: "", | ||
| }), | ||
| SLACK_CLIENT_ID: str({ | ||
| desc: "The public Slack Client ID", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| default: "", | ||
| }), | ||
| SLACK_CLIENT_SECRET: str({ | ||
| desc: "The secret API Key for Slack access", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| default: "", | ||
| }), | ||
| SLACK_WEBHOOK_SECRET: str({ | ||
| desc: "The secret string used to sign Slack webhooks", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| default: "", | ||
| }), | ||
| SLACK_INSTALL_NOTIFICATION_WEBHOOK_URL: str({ | ||
| desc: "The URL to the Slack install notification webhook", | ||
| allowEmpty: true, | ||
| devDefault: "", | ||
| default: "", | ||
| }), | ||
|
Comment on lines
41
to
64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Search for Stripe client/SDK initialization
rg -nP --type=ts "stripe|STRIPE" --max-count=200 | head -100Repository: sweetr-dev/sweetr.dev Length of output: 3276 🏁 Script executed: # Search for Slack client/SDK initialization
rg -nP --type=ts "slack|SLACK" --max-count=200 | head -100Repository: sweetr-dev/sweetr.dev Length of output: 11198 🏁 Script executed: cat -n apps/api/src/lib/stripe.tsRepository: sweetr-dev/sweetr.dev Length of output: 407 🏁 Script executed: cat -n apps/api/src/app/integrations/slack/services/slack-integration.service.ts | head -120Repository: sweetr-dev/sweetr.dev Length of output: 4003 🏁 Script executed: cat -n apps/api/src/config/slack.config.tsRepository: sweetr-dev/sweetr.dev Length of output: 542 🏁 Script executed: cat -n apps/api/src/app/billing/stripe.router.tsRepository: sweetr-dev/sweetr.dev Length of output: 2179 🏁 Script executed: # Check if stripe client is instantiated conditionally anywhere
rg -n "getStripeClient" --type=ts -B 3 -A 3Repository: sweetr-dev/sweetr.dev Length of output: 6037 🏁 Script executed: # Find getSlackClient definition
rg -n "export.*getSlackClient" --type=ts -A 10 apps/api/src/app/integrations/slack/services/slack-client.service.tsRepository: sweetr-dev/sweetr.dev Length of output: 459 🏁 Script executed: # Check where getInstallUrl is called and if it has guards
rg -n "getInstallUrl" --type=ts -B 5 -A 5Repository: sweetr-dev/sweetr.dev Length of output: 3428 🏁 Script executed: # Check if Stripe is gated anywhere or if billing is feature-flagged
rg -n "STRIPE_API_KEY|getStripeClient" --type=ts -B 5 -A 5 | grep -E "(if|guard|feature|enabled|check)" -B 3 -A 3Repository: sweetr-dev/sweetr.dev Length of output: 1896 Add guards to Stripe and Slack initialization code before instantiating SDKs with potentially empty credentials. Stripe's 🤖 Prompt for AI Agents |
||
| JWT_SECRET: str({ desc: "The secret string used to sign JWT tokens" }), | ||
| SENTRY_DSN: str({ | ||
| desc: "The DSN to connect to Sentry project", | ||
| allowEmpty: true, | ||
| default: "", | ||
| }), | ||
| LOG_DRAIN: str({ | ||
| desc: "The secret string used to sign GitHub webhooks", | ||
| desc: "The stream to log to", | ||
| choices: ["logtail", "console"], | ||
| default: "logtail", | ||
| devDefault: "console", | ||
| default: "console", | ||
| }), | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| LOGTAIL_TOKEN: str({ | ||
| desc: "The source token to forward logs to LogTail", | ||
| default: "", | ||
| }), | ||
| LOGTAIL_TOKEN: str({ desc: "The source token to forward logs to LogTail" }), | ||
| USE_SELF_SIGNED_SSL: bool({ | ||
| desc: "Whether the server should use self-signed certificates generated by devcert (see npm run ssl:generate)", | ||
| default: false, | ||
|
|
@@ -95,13 +89,19 @@ export const env = envsafe({ | |
| devDefault: "/bullboard", | ||
| default: "", | ||
| }), | ||
| BULLBOARD_USERNAME: str({ desc: "The username to login to BullBoard." }), | ||
| BULLBOARD_PASSWORD: str({ desc: "The password to login to BullBoard." }), | ||
| BULLBOARD_USERNAME: str({ | ||
| desc: "The username to login to BullBoard.", | ||
| default: "", | ||
| }), | ||
| BULLBOARD_PASSWORD: str({ | ||
| desc: "The password to login to BullBoard.", | ||
| default: "", | ||
| }), | ||
| EMAIL_ENABLED: bool({ | ||
| desc: "Whether transactional emails are enabled", | ||
| default: false, | ||
| }), | ||
| RESEND_API_KEY: str({ desc: "The API Key for Resend.", allowEmpty: true }), | ||
| RESEND_API_KEY: str({ desc: "The API Key for Resend.", default: "" }), | ||
| APP_MODE: str({ | ||
| desc: "Whether the application is being self-hosted", | ||
| choices: ["self-hosted", "saas"], | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -166,5 +166,6 @@ Update .env to enable: | |
| SENTRY_DSN= | ||
|
|
||
| # LogTail | ||
| LOG_DRAIN=logtail | ||
| LOGTAIL_TOKEN= | ||
| ``` | ||
Uh oh!
There was an error while loading. Please reload this page.