Skip to content

feat: add CI/CD workflow for testing, building, and deploying Docker#8

Merged
DanielPopoola merged 5 commits into
masterfrom
go-version
Apr 12, 2026
Merged

feat: add CI/CD workflow for testing, building, and deploying Docker#8
DanielPopoola merged 5 commits into
masterfrom
go-version

Conversation

@DanielPopoola
Copy link
Copy Markdown
Owner

@DanielPopoola DanielPopoola commented Apr 12, 2026

PR message:

CI/CD Pipeline

Adds a three-stage GitHub Actions pipeline that runs on every push to master.

Stages

Test — runs the linter via golangci-lint then the full test suite with a 180s timeout to accommodate testcontainers spin-up time.

Build — only runs if tests pass. Builds the Docker image and pushes it to GitHub Container Registry (ghcr.io) tagged with both the commit SHA (sha-<hash>) and latest. The SHA tag means every push is traceable to an exact commit, and latest is what the deploy step pulls.

Deploy — only runs if build passes. SSHes into the VPS, writes the environment file from a secret, pulls the new image, and restarts only the app container without touching Postgres or Redis.

What doesn't change

Postgres and Redis on the VPS are unaffected by deploys — --no-deps ensures only the app container is restarted.


Summary by CodeRabbit

  • Chores
    • Added an automated CI/CD pipeline that runs tests, lints, builds container images, and deploys releases to the server to streamline delivery and reduce manual steps.
    • Updated payment configuration: the webhook secret is no longer required or loaded, while the payment secret key and base URL remain mandatory for operation.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
.github/workflows/deploy.yml (1)

37-38: The image output is defined but not consumed.

The deploy job uses docker compose pull app which references the image from docker-compose.yml, not from this output. If this output is intended for future use, note that steps.meta.outputs.tags contains multiple newline-separated tags which may need parsing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 37 - 38, The outputs.image entry
currently exposes steps.meta.outputs.tags but is never used by the deploy job
(which runs docker compose pull app and reads images from docker-compose.yml);
either remove outputs.image or wire it up: if you intend to pass the image tags
from steps.meta.outputs.tags into deployment, update the deploy job to consume
the output (outputs.image) or set an environment/argument that docker compose
uses, and if using steps.meta.outputs.tags remember it can contain multiple
newline-separated tags so parse/select the desired tag before passing it along
(reference outputs.image, steps.meta.outputs.tags, the deploy job and docker
compose pull app to locate the code to change).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/deploy.yml:
- Around line 86-87: The comment claiming "zero downtime" is inaccurate for the
command `docker compose up -d --no-deps app` because with a single replica the
old container is stopped before the new one starts; either change the comment to
something accurate (e.g., "restart app container (may cause brief outage)") or
implement a true zero-downtime strategy: run multiple replicas behind a load
balancer and perform rolling updates (or use docker swarm/docker stack with
deploy.update_config, or switch to Kubernetes/blue-green deployment), ensure
healthchecks are defined so new instances are only routed after healthy, and
adjust the deployment command/process accordingly.
- Around line 80-81: The current step uses echo "${{ secrets.ENV_FILE }}" > .env
which can break if the secret contains shell metacharacters; replace this with a
safer write method such as a heredoc or printf that preserves the raw secret (or
store a base64-encoded secret and decode it on the runner), e.g. change the
action step that writes the ENV_FILE secret to use a heredoc/printf or base64
decode instead of the direct echo to ensure special characters like $, `, ! are
handled correctly.
- Around line 22-25: The workflow step named "Run linter" currently sets the
golangci-lint action input "version: latest"; change this to a pinned, specific
golangci-lint release (e.g., a concrete semver tag) to ensure reproducible CI.
Update the "Run linter" step that uses golangci/golangci-lint-action@v6 so the
"version" input is a fixed version string instead of "latest" and commit the
updated workflow.

---

Nitpick comments:
In @.github/workflows/deploy.yml:
- Around line 37-38: The outputs.image entry currently exposes
steps.meta.outputs.tags but is never used by the deploy job (which runs docker
compose pull app and reads images from docker-compose.yml); either remove
outputs.image or wire it up: if you intend to pass the image tags from
steps.meta.outputs.tags into deployment, update the deploy job to consume the
output (outputs.image) or set an environment/argument that docker compose uses,
and if using steps.meta.outputs.tags remember it can contain multiple
newline-separated tags so parse/select the desired tag before passing it along
(reference outputs.image, steps.meta.outputs.tags, the deploy job and docker
compose pull app to locate the code to change).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 41581000-75cf-44a9-972e-c18ce2390334

📥 Commits

Reviewing files that changed from the base of the PR and between ae4fbe2 and e329e01.

📒 Files selected for processing (2)
  • .github/workflows/deploy.yml
  • internal/config/config.go

Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
.github/workflows/deploy.yml (2)

86-87: ⚠️ Potential issue | 🟡 Minor

Update the downtime comment to match actual behavior.

For a single replica, docker compose up -d --no-deps app may cause a brief interruption.

Comment-only correction
-            # Restart with zero downtime
+            # Restart app container (brief downtime expected)
             docker compose up -d --no-deps app
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 86 - 87, The comment "Restart with
zero downtime" is inaccurate for the command docker compose up -d --no-deps app
because with a single replica it can cause a brief interruption; update the
comment above the docker compose up -d --no-deps app line to state that this
attempts a zero-downtime restart for multi-replica setups but may cause brief
downtime for single-replica deployments (or alternatively change wording to
"Attempt zero-downtime restart; may cause brief interruption on single
replica").

80-81: ⚠️ Potential issue | 🟡 Minor

Write .env using a safer method than direct echo.

Direct echo can mangle multiline/special-character secrets.

Safer write pattern
-            echo "${{ secrets.ENV_FILE }}" > .env
+            cat > .env << 'EOF'
+            ${{ secrets.ENV_FILE }}
+            EOF
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 80 - 81, The current step writes
the secret to .env using echo which can mangle newlines and special characters;
replace the echo usage (the step that writes ".env") with a safer write that
preserves multiline content and special characters—for example use a
printf-based write or a quoted heredoc approach to write the value of the
ENV_FILE secret into .env so newlines and special characters are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/deploy.yml:
- Around line 77-85: The deploy script currently continues after failures (e.g.,
if `docker compose pull app` fails) which can lead to deploying a stale image;
modify the script block that contains the commands (the block executing cd
~/fairqueue, echo "${{ secrets.ENV_FILE }}" > .env and docker compose pull app)
to enable fail-fast behavior by adding a shell safety line `set -euo pipefail`
at the very start of that script so any error (including failed pulls or
undefined variables) aborts the workflow immediately.
- Around line 74-77: The SSH step using appleboy/ssh-action lacks host key
verification; add the action's fingerprint input and set it to a repo secret
(e.g. secrets.VPS_SSH_FINGERPRINT) so the runner pins the server host key;
update the SSH step that contains host/username/key/script to include
fingerprint: ${{ secrets.VPS_SSH_FINGERPRINT }} (obtain the fingerprint from the
server with ssh-keygen as described and store it in the secret).
- Around line 3-6: Add a top-level GitHub Actions concurrency block immediately
after the existing on: block to serialize master branch deployments; create a
named concurrency group (e.g., "deploy-production" or "production-deploy-${{
github.ref }}") and set cancel-in-progress: false so in-flight jobs are queued
rather than cancelled. Update the workflow (.github/workflows/deploy.yml) to
include the concurrency key at top level (not inside jobs) so all pushes to
master are serialized and overlapping deploy jobs cannot run concurrently.

---

Duplicate comments:
In @.github/workflows/deploy.yml:
- Around line 86-87: The comment "Restart with zero downtime" is inaccurate for
the command docker compose up -d --no-deps app because with a single replica it
can cause a brief interruption; update the comment above the docker compose up
-d --no-deps app line to state that this attempts a zero-downtime restart for
multi-replica setups but may cause brief downtime for single-replica deployments
(or alternatively change wording to "Attempt zero-downtime restart; may cause
brief interruption on single replica").
- Around line 80-81: The current step writes the secret to .env using echo which
can mangle newlines and special characters; replace the echo usage (the step
that writes ".env") with a safer write that preserves multiline content and
special characters—for example use a printf-based write or a quoted heredoc
approach to write the value of the ENV_FILE secret into .env so newlines and
special characters are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b1f5be1-f24d-43f4-a49f-1a7a14871fa1

📥 Commits

Reviewing files that changed from the base of the PR and between e329e01 and 0281524.

📒 Files selected for processing (1)
  • .github/workflows/deploy.yml

Comment on lines +3 to +6
on:
push:
branches: [master]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/deploy.yml | head -100

Repository: DanielPopoola/fairqueue

Length of output: 2635


Add workflow concurrency control to prevent overlapping production deployments.

Multiple rapid pushes to master will trigger concurrent deploy jobs. Since each deployment independently pulls the latest image and restarts the container, parallel executions can cause race conditions and out-of-order state updates on the VPS.

Suggested concurrency block
 on:
   push:
     branches: [master]
 
+concurrency:
+  group: fairqueue-master-cicd
+  cancel-in-progress: false
+
 env:
   REGISTRY: ghcr.io
   IMAGE_NAME: ${{ github.repository }}

Apply at the top level (after the on: block) to serialize all master branch deployments. The cancel-in-progress: false setting ensures in-flight deployments are queued rather than cancelled, which is appropriate for production.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
push:
branches: [master]
on:
push:
branches: [master]
concurrency:
group: fairqueue-master-cicd
cancel-in-progress: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy.yml around lines 3 - 6, Add a top-level GitHub
Actions concurrency block immediately after the existing on: block to serialize
master branch deployments; create a named concurrency group (e.g.,
"deploy-production" or "production-deploy-${{ github.ref }}") and set
cancel-in-progress: false so in-flight jobs are queued rather than cancelled.
Update the workflow (.github/workflows/deploy.yml) to include the concurrency
key at top level (not inside jobs) so all pushes to master are serialized and
overlapping deploy jobs cannot run concurrently.

Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/deploy.yml
@DanielPopoola DanielPopoola merged commit ab87f67 into master Apr 12, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant