Skip to main content

Command Palette

Search for a command to run...

GitHub Actions in Action

Published
5 min read
GitHub Actions in Action
S

💻 Sahil learns, codes, and automates, documenting his journey every step of the way. 🚀

In the world of DevOps and modern software development, automation is everything. Whether you're building, testing, or deploying your application, having a streamlined CI/CD (Continuous Integration/Continuous Deployment) pipeline can save time, reduce errors, and keep your development process running smoothly. That’s where GitHub Actions steps in.

GitHub Actions is a powerful CI/CD tool built right into GitHub, allowing you to automate tasks directly from your repository. With a few lines of YAML, you can set up workflows that automatically run tests, build your code, deploy applications, or even trigger custom scripts when certain events occur—like pushing code, opening a pull request, or publishing a release.

In this blog, I’ll walk you through the basics of GitHub Actions using a simple Go web server project as an example. We’ll write a basic workflow that runs unit tests on every push to the repository. Whether you're new to DevOps or just exploring automation on GitHub, this post will help you get started with hands-on, real-world examples.


What is CI/CD?

CI/CD stands for Continuous Integration and Continuous Deployment (or Continuous Delivery). It’s a set of practices that help software development teams deliver code changes more frequently and reliably. Let’s break it down:

🔁 Continuous Integration (CI)

  • Every time a developer pushes code to a shared repository (like GitHub), it automatically gets tested and built.

  • This helps catch bugs early, avoids "it works on my machine" problems, and ensures the new code doesn't break the existing functionality.

  • Think of CI as your automated code checker that runs the moment you make changes.

📦 Continuous Deployment / Delivery (CD)

  • Continuous Delivery: After your code is tested and built, it’s ready to be deployed manually or automatically to staging or production environments.

  • Continuous Deployment: Takes it a step further by automatically deploying every successful change to production without human intervention.

  • CD helps you release faster, more frequently, and with confidence, because every step is tested and automated.

Why Does CI/CD Matter?

  • Reduces manual work

  • Catches issues early

  • Makes the development cycle faster and safer

  • Encourages small, incremental changes (which are easier to manage and review)


Core Components of GitHub Actions 🧩

GitHub Actions works by defining workflows that are triggered by events in your GitHub repository.

  1. Workflow:

    A workflow is an automated process that runs one or more jobs. It’s defined in a YAML file and stored in the .github/workflows/ directory of your repository.

    Example:
    A workflow might run tests every time you push code or deploy your app when a pull request is merged.

  2. Event

    An event is what triggers a workflow.

    Common examples:

    • push: when code is pushed to a branch

    • pull_request: when a pull request is opened or updated

    • schedule: run at specific times (like a cron job)

    • workflow_dispatch: manually triggered by a button on GitHub

  1. Job

    A job is a set of steps that run in the same virtual environment (runner). Jobs are isolated by default but can be made dependent on each other.

    Example: A workflow might have one job to run tests and another job to deploy the app

  2. Step

    Each job is made up of multiple steps. A step is either a command or an action.

    Example steps:

     - name: Check out the code
       uses: actions/checkout@v3
    
     - name: Run tests
       run: go test ./...
    
  3. Action

    An action is a reusable piece of code packaged for GitHub Actions. You can use actions created by others (like actions/checkout) or create your own.

    Actions like plugins that handle common tasks: setting up a language, caching dependencies, uploading artifacts, etc.

  4. Runner

    A runner is the server (virtual machine or container) that executes your jobs. GitHub provides hosted runners (like Ubuntu, Windows, or macOS), or you can use your own (called self-hosted runners).


🧪 Sample Go Project

Before we dive into creating a GitHub Actions workflow, let’s quickly understand the project we’ll be working with.

We have a simple Go web server with a single route (/) that responds with a message:

// main.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", handler)
    log.Println("Listening on :8081")
    log.Fatal(http.ListenAndServe(":8081", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hey there, I am mastering GitHub Actions!\n")
}

And a basic test for that handler:

// main_test.go
package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHandler(t *testing.T) {
    req := httptest.NewRequest("GET", "/", nil)
    w := httptest.NewRecorder()

    handler(w, req)

    if w.Code != http.StatusOK {
        t.Errorf("Expected status code 200, got %d", w.Code)
    }

    expectedBody := "Hey there, I am mastering GitHub Actions!\n"
    if w.Body.String() != expectedBody {
        t.Errorf("Expected body %q, got %q", expectedBody, w.Body.String())
    }
}

This project is perfect for learning GitHub Actions because:

  • It’s small and easy to understand

  • It has a simple unit test

  • We can run tests automatically on every push using a CI workflow

Now, let’s create a workflow that runs this test every time we push code to GitHub.


Creating and Running the Workflows

// basic-workflow.yaml

name: Go CI

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

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

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

    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.23.1'  

    - name: Build the Go app
      run: go build -v ./...

    - name: Run tests
      run: go test -v ./...

🔍 What this does:

  • Triggers on push and pull_request events targeting the main branch.

  • Checks out your code using actions/checkout.

  • Sets up Go using the specified version.

  • go build -v ./...: Compiles all Go packages in your project. If there are any syntax or compile-time errors, the workflow will fail here before running tests.

  • -v flag (in both build and test): Makes output verbose, showing files and test names for better visibility in GitHub Actions logs.