DevOps

Building a resilient CI/CD pipeline on GitHub Actions

15 May 2024 · 5 min read · SmartCG

A pipeline on GitHub Actions with security checks, zero-downtime deploys and logs delivered to Telegram.

Why a pipeline at all

Manual deploys are pure human factor: someone forgets a migration, someone copies the wrong .env, someone deploys on Friday evening and finds out on Monday. CI/CD (Continuous Integration and Continuous Deployment) automates checks, tests and delivery, so a release stops depending on who is awake at the time.

How our pipeline is structured

We split the work into two files: ci.yml runs on every push and pull request, and cd.yml runs only after CI is green on the main branch. That separation is what keeps a broken build from ever reaching a server.

CI: checks

  • Security audit: npm audit with a fail threshold for high-severity issues.
  • Build check: the project must compile — TypeScript errors fail the run.
  • Linter: ESLint with the same config developers use locally.

CD: deploy

When CI passes, deployment starts:

  1. Connect to the server over SSH (via appleboy/ssh-action).
  2. Generate .env files from GitHub Secrets — never from a file in the repository.
  3. Build the Docker images (docker compose build).
  4. Restart the containers (docker compose up -d) with a health check before traffic returns.

Notifications in Telegram

We added a step that, when a pipeline fails, collects the last 100 log lines and sends them as a file to Telegram. A developer learns the cause without opening GitHub, and the team sees immediately that a release did not go out — which matters more than the error text itself.

Services involved

Read next

Releases still depend on manual steps and nervous deploys?

We show where your release process breaks: pipeline, rollback, production environment, diagnostics or the operational discipline after deployment.