Escaping the Fear of Deploying Manually: Building a CI/CD Pipeline with GitHub Actions

Escaping the Fear of Deploying Manually: Building a CI/CD Pipeline with GitHub Actions

"Oh no, I forgot to run the tests..."

Just the other day, I felt that sudden wave of panic right before a release. Everything had worked perfectly in my local environment, and the build seemed successful. However, once the site went live, the logs were immediately flooded with unexpected runtime errors. I ended up caught in the worst possible loop: frantically fixing bugs and redeploying over and over again.

These kinds of "oops" moments become increasingly critical as a project grows in scale. Even for solo developers, lacking a system to catch human error can be mentally taxing. This realization led me to build a CI/CD pipeline using GitHub Actions to automate everything from testing and building to deployment.

To be honest, I initially struggled with the "how-to" of writing these workflows. A single misplaced indentation in a YAML file could trigger an error, and it took some time and research to figure out how to manage environment variables (Secrets) securely for deployment.

My goal was to create a configuration that was both simple and robust. Specifically, I designed a flow where pushing to the `main` branch triggers "Lint checks," "Unit tests," and "Build" processes; only if all of these pass does the system automatically proceed to deployment.

Below is the implementation example for my workflow (`.github/workflows/ci-cd.yml`).

name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test-and-build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Lint
        run: npm run lint

      - name: Run Tests
        run: npm test

      - name: Build project
        run: npm run build

  deploy:
    needs: test-and-build
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Deploy to Server
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
        run: |
          echo "Deploying with token..."
          # Insert actual deployment commands here (e.g., AWS S3 sync, SSH commands, etc.)

The most significant change after implementing this setup was the sense of "peace of mind" I felt after every push. If a test fails or a type error occurs during the build, I receive an immediate notification on GitHub. In other words, I can now catch "broken code" before it ever reaches production.

The `needs: test-and-build` declaration is particularly crucial here. By including this, I ensure that the subsequent deployment job will not trigger unless the testing and building phases are successful. Without this safeguard, there is a risk that the system might attempt to deploy even if the tests fail.

Additionally, I moved all sensitive information—such as API keys and SSH keys—into the `Secrets` section of the GitHub repository settings. Hardcoding these into the workflow file is out of the question; establishing a system to inject them securely as environment variables was another major hurdle in building this CI/CD pipeline.

Admittedly, there were moments where I wondered if I was over-engineering it. However, once you experience the benefits of automation, returning to manual processes feels like a step backward. By letting tools handle the repetitive tasks, engineers can focus on what truly matters: developing core logic.

As my projects become more complex, I plan to add further steps such as optimizing caching strategies and creating container images. I look forward to gradually evolving this into an even more robust pipeline.


🤖 Developer Blog & Resources

You can also find my personal blog and other content here: muttyan.com Blog

Amazon Prime Free Trial & Benefits Summary