Skip to main content

Echo Continuous Integration

Introduction

Continuous Integration (CI) is a software development practice where developers frequently merge their code changes into a central repository, followed by automated builds and tests. When working with Echo Framework applications, implementing CI helps ensure that your code remains reliable and bug-free as it evolves.

In this guide, we'll explore how to set up continuous integration for your Echo applications. You'll learn how to automate testing, build, and deployment processes using popular CI tools, helping you deliver high-quality Echo applications with confidence.

What is Continuous Integration?

Continuous Integration is a development practice that requires developers to integrate code into a shared repository several times a day. Each integration is verified by an automated build and automated tests to detect integration errors as quickly as possible.

For Echo applications, CI brings several benefits:

  • Early detection of bugs and issues
  • Consistent build and test processes
  • Faster feedback on code changes
  • Improved code quality and stability
  • More efficient team collaboration

Setting Up CI for Echo Applications

Prerequisites

Before setting up CI for your Echo application, you'll need:

  1. A version control system (like Git)
  2. A CI platform (GitHub Actions, GitLab CI, CircleCI, Jenkins, etc.)
  3. An Echo application with tests
  4. Basic understanding of YAML configuration files

GitHub Actions for Echo CI

Let's start with setting up GitHub Actions, a popular choice for CI/CD that's directly integrated with GitHub repositories.

Creating a Basic Workflow

Create a directory called .github/workflows in your project root and add a file named echo-ci.yml:

yaml
name: Echo CI

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

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18

- name: Install dependencies
run: go mod download

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

- name: Build
run: go build -v ./...

This basic workflow will:

  1. Trigger on every push to the main branch or when a pull request is opened against it
  2. Set up a Go environment
  3. Install your project dependencies
  4. Run all tests in your repository
  5. Build your Echo application

Adding Code Coverage

To improve your CI process, you can add code coverage reporting:

yaml
- name: Run tests with coverage
run: go test -coverprofile=coverage.out -covermode=atomic ./...

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.out

GitLab CI for Echo Applications

If you're using GitLab, create a .gitlab-ci.yml file in your project root:

yaml
image: golang:1.18

stages:
- test
- build
- deploy

variables:
GOPATH: $CI_PROJECT_DIR/.go

cache:
paths:
- .go/pkg/mod/

before_script:
- mkdir -p .go
- go mod download

test:
stage: test
script:
- go test -v ./...

build:
stage: build
script:
- go build -o echo-app
artifacts:
paths:
- echo-app

deploy-staging:
stage: deploy
script:
- echo "Deploying to staging server"
environment:
name: staging
only:
- main

This GitLab CI configuration will:

  1. Use a Go Docker image
  2. Define three stages: test, build, and deploy
  3. Cache Go modules for faster builds
  4. Run tests, build an executable, and perform a simulated deployment

Advanced CI: Testing Echo APIs

For Echo API projects, you'll want to include more comprehensive testing in your CI pipeline. Here's how to extend your GitHub Actions workflow:

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

- name: Set up integration test environment
run: |
docker-compose up -d database
go run cmd/migrate/main.go

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

- name: Run API tests
run: |
docker-compose up -d api
go run cmd/tests/api_test.go

Real-world Example: Complete Echo CI Pipeline

Let's look at a more comprehensive GitHub Actions configuration that includes multiple testing strategies, linting, and deployment:

yaml
name: Echo CI/CD Pipeline

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

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18

- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.45.2

test:
name: Test
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:13
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: echo_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18

- name: Install dependencies
run: go mod download

- name: Run migrations
run: |
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
migrate -path ./migrations -database "postgres://postgres:postgres@localhost:5432/echo_test?sslmode=disable" up

- name: Run tests with coverage
run: go test -coverprofile=coverage.out -covermode=atomic ./...

- name: Upload coverage report
uses: codecov/codecov-action@v3
with:
file: ./coverage.out

build:
name: Build
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18

- name: Build
run: go build -o echo-app ./cmd/api

- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: echo-app
path: echo-app

deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'

steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: echo-app

- name: Make executable
run: chmod +x ./echo-app

- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
mkdir -p ~/echo-app
pkill -f echo-app || true
nohup ~/echo-app/echo-app > ~/echo-app/app.log 2>&1 &

This comprehensive workflow:

  1. Runs linting to maintain code quality
  2. Sets up a Postgres database service for tests
  3. Runs migrations before testing
  4. Executes tests with coverage reporting
  5. Builds the application and saves it as an artifact
  6. Deploys the application to a production server (only from the main branch)

CI Best Practices for Echo Applications

When implementing CI for your Echo applications, follow these best practices:

  1. Test structure: Organize your tests logically (unit, integration, end-to-end)
  2. Fast feedback: Optimize your CI pipeline to run quickly
  3. Test coverage: Aim for high test coverage of your codebase
  4. Environment parity: Make your CI environment as close to production as possible
  5. Secure secrets: Never expose API keys or credentials in your CI configuration
  6. Artifact management: Store build artifacts securely
  7. Notifications: Configure notifications for failed builds
  8. Branch policies: Protect important branches with required status checks

Example: Testing an Echo Handler

Here's a simple Echo handler and its corresponding test that would run in your CI pipeline:

Handler (main.go):

go
package main

import (
"net/http"

"github.com/labstack/echo/v4"
)

func getUserHandler(c echo.Context) error {
id := c.Param("id")
return c.JSON(http.StatusOK, map[string]interface{}{
"id": id,
"name": "Sample User",
"email": "[email protected]",
})
}

func main() {
e := echo.New()
e.GET("/users/:id", getUserHandler)
e.Start(":8080")
}

Test (main_test.go):

go
package main

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

"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
)

func TestGetUserHandler(t *testing.T) {
// Setup
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetPath("/users/:id")
c.SetParamNames("id")
c.SetParamValues("123")

// Assertions
if assert.NoError(t, getUserHandler(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Contains(t, rec.Body.String(), "Sample User")
assert.Contains(t, rec.Body.String(), "123")
}
}

This test ensures that your handler returns the expected response with the correct status code and data. In your CI pipeline, this test would run automatically with every code change.

Integrating with Docker

For more complex applications, you might want to build and test Docker images:

yaml
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: yourorg/echo-app:latest

Your Dockerfile might look like this:

dockerfile
FROM golang:1.18-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN go build -o echo-app ./cmd/api

FROM alpine:3.16
WORKDIR /app
COPY --from=builder /app/echo-app .
COPY config ./config
EXPOSE 8080
CMD ["./echo-app"]

Summary

Continuous Integration is an essential practice for developing robust Echo applications. By automating your testing and build processes, you can catch issues early, maintain high code quality, and deploy with confidence.

In this guide, you learned how to:

  • Set up CI pipelines with GitHub Actions and GitLab CI
  • Configure automated testing for Echo applications
  • Implement code coverage reporting
  • Create comprehensive workflows that include linting, testing, building, and deploying
  • Follow best practices for Echo CI implementation

By implementing these CI practices, you'll improve your development workflow and deliver more reliable Echo applications.

Additional Resources

  1. GitHub Actions Documentation
  2. GitLab CI Documentation
  3. Echo Framework Testing Guide
  4. Go Testing Package Documentation
  5. Docker Multi-Stage Builds

Exercises

  1. Set up a basic GitHub Actions workflow for an existing Echo project
  2. Add code coverage reporting to your CI pipeline
  3. Create an integration test that uses a test database
  4. Configure your CI to build a Docker image for your Echo application
  5. Implement a multi-environment deployment workflow (dev, staging, production)


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)