Skip to content

Add comprehensive CI/CD: GitHub Actions for ghcr.io builds, release script, and Windows installer #9

@bryanchriswhite

Description

@bryanchriswhite

Summary

Implement a comprehensive CI/CD pipeline using GitHub Actions that includes:

  1. Automated Docker image builds and push to ghcr.io for all components
  2. A release script for semantic versioning with GPG-signed tags
  3. Windows installer build and release asset attachment

Background

Currently, CI/CD is minimal:

  • main.yml - Manual trigger only, builds backend image
  • oauth-broker.yml - Automated on main branch push, but no version tagging

Missing capabilities:

  • No automated builds for pinshare-ui Docker image
  • No semantic versioning or release automation
  • No Windows installer builds
  • No multi-architecture support (arm64)
  • No automated testing in CI

Deliverables

1. Enhanced GitHub Actions Workflows

A. build-backend.yml - Backend Docker Image Build

Triggers:

  • Push to main branch (paths: *.go, go.*, internal/**, Dockerfile)
  • Release published (for version-tagged images)
  • Manual workflow_dispatch

Features:

  • Multi-platform builds: linux/amd64, linux/arm64
  • Push to ghcr.io/episk-pos/pinshare-backend
  • Tags: latest (main), sha-<commit>, v<version> (releases)
  • Build cache for faster iterations
  • Build args for version injection

Example tags produced:

ghcr.io/episk-pos/pinshare-backend:latest
ghcr.io/episk-pos/pinshare-backend:main-abc1234
ghcr.io/episk-pos/pinshare-backend:v1.0.0

B. build-ui.yml - Frontend Docker Image Build

Triggers:

  • Push to main branch (paths: pinshare-ui/**)
  • Release published
  • Manual workflow_dispatch

Features:

  • Multi-stage Dockerfile (dev → builder → production nginx)
  • Push to ghcr.io/episk-pos/pinshare-ui
  • Same tagging strategy as backend
  • Artifact upload of dist/ folder for release assets

C. build-oauth.yml - OAuth Broker Build (enhance existing)

Enhancements:

  • Add multi-platform support (linux/amd64, linux/arm64)
  • Add version tagging on releases
  • Update action versions to latest

D. release.yml - Release Build Workflow

Triggers:

  • Release published on GitHub

Jobs:

  1. build-binaries - Cross-platform Go binaries

    • Matrix: linux/amd64, linux/arm64, windows/amd64, darwin/amd64, darwin/arm64
    • Outputs: pinshare-linux-amd64, pinshare-linux-arm64, pinshare-windows-amd64.exe, pinshare-darwin-amd64, pinshare-darwin-arm64
    • Upload as release assets
  2. build-windows-installer - Windows NSIS Installer

    • Build Windows binary
    • Package with NSIS (or WiX for MSI)
    • Include: executable, default config, README
    • Output: PinShare-Setup-v<version>.exe
    • Upload to release assets
  3. build-docker-images - Build and push all Docker images with version tags

    • Backend, UI, OAuth broker
    • Tag with release version

E. test.yml - Automated Testing

Triggers:

  • Pull requests to any branch
  • Push to main

Jobs:

  1. go-tests - Backend unit tests

    • go test ./...
    • Coverage report
  2. ui-tests - Frontend tests

    • npm run lint
    • Playwright E2E tests (optional, browser matrix)
  3. integration-tests - Docker compose integration tests

    • Spin up services with docker-compose
    • Run API smoke tests

2. Release Script (scripts/release.sh)

Adapt the lenr.academy release script for PinShare:

Features:

  • Semantic versioning: patch, minor, major, prerelease
  • Prerelease identifiers: alpha, beta, rc
  • GPG-signed annotated tags (required)
  • Clean working directory check
  • Branch validation (warn if not on main)
  • Version source of truth: git tags
  • Automatic GitHub pre-release creation
  • Version bump in relevant files (go.mod annotation, package.json in UI)

Usage:

./scripts/release.sh patch                    # 0.0.1 → 0.0.2
./scripts/release.sh minor                    # 0.0.1 → 0.1.0
./scripts/release.sh major                    # 0.0.1 → 1.0.0
./scripts/release.sh prerelease               # 0.0.1 → 0.0.2-alpha.0
./scripts/release.sh prerelease beta          # 0.0.1 → 0.0.2-beta.0

Release Flow:

Developer runs ./scripts/release.sh patch
        ↓
Script validates clean working directory
        ↓
Bumps version, creates GPG-signed tag
        ↓
Pushes to GitHub, creates pre-release
        ↓
GitHub Actions triggered (release.yml)
        ├─→ Build all binaries (Linux, Windows, macOS)
        ├─→ Build Windows installer
        ├─→ Build Docker images with version tags
        └─→ Attach all artifacts to release
        ↓
Manual QA on pre-release
        ↓
Uncheck "pre-release" to promote to stable

3. Windows Installer Build

Technology Options:

  1. NSIS (Nullsoft Scriptable Install System) - Recommended

    • Free, well-documented
    • Creates .exe installer
    • Supports custom install paths, shortcuts, uninstaller
    • GitHub Action: joncloud/makensis-action
  2. WiX Toolset - Alternative

    • Creates .msi installer
    • More complex but enterprise-friendly
    • GitHub Action: coderpatros/wix-toolset-action

Installer Contents:

  • pinshare.exe - Main executable
  • config.example.yaml - Example configuration
  • README.txt - Quick start guide
  • Start menu shortcuts
  • Uninstaller

NSIS Script Structure (scripts/installer.nsi):

!include "MUI2.nsh"

Name "PinShare"
OutFile "PinShare-Setup-${VERSION}.exe"
InstallDir "$PROGRAMFILES\PinShare"

Section "Install"
    SetOutPath $INSTDIR
    File "pinshare.exe"
    File "config.example.yaml"
    File "README.txt"
    
    CreateDirectory "$SMPROGRAMS\PinShare"
    CreateShortcut "$SMPROGRAMS\PinShare\PinShare.lnk" "$INSTDIR\pinshare.exe"
    CreateShortcut "$SMPROGRAMS\PinShare\Uninstall.lnk" "$INSTDIR\uninstall.exe"
    
    WriteUninstaller "$INSTDIR\uninstall.exe"
SectionEnd

Section "Uninstall"
    Delete "$INSTDIR\*.*"
    RMDir "$INSTDIR"
    Delete "$SMPROGRAMS\PinShare\*.*"
    RMDir "$SMPROGRAMS\PinShare"
SectionEnd

Implementation Tasks

Phase 1: Core CI/CD

  • Create build-backend.yml workflow with multi-arch support
  • Create build-ui.yml workflow
  • Enhance oauth-broker.yml with version tagging
  • Create test.yml for automated testing

Phase 2: Release Automation

  • Create scripts/release.sh adapted from lenr.academy
  • Create release.yml workflow for release builds
  • Add version injection to Go builds (ldflags)
  • Document release process in RELEASE.md

Phase 3: Windows Installer

  • Create NSIS installer script (scripts/installer.nsi)
  • Add Windows installer job to release.yml
  • Test installer on Windows
  • Sign installer (optional, requires code signing cert)

Phase 4: Documentation & Polish

  • Create DEPLOYMENT.md documenting CI/CD pipeline
  • Add badges to README (build status, latest release)
  • Create CONTRIBUTING.md with release guidelines

Required GitHub Secrets

Secret Purpose
GITHUB_TOKEN Auto-provided, used for ghcr.io and releases

Note: GITHUB_TOKEN is automatically available and has permissions for ghcr.io pushes within the same organization.

Optional secrets for enhanced features:

Secret Purpose
CODE_SIGNING_CERT Windows installer code signing (optional)
CODE_SIGNING_PASSWORD Certificate password (optional)

Workflow Permissions Required

Add to each workflow:

permissions:
  contents: write      # For release asset uploads
  packages: write      # For ghcr.io pushes
  actions: read        # For workflow status

Acceptance Criteria

  • Pushing to main triggers automated Docker builds for all components
  • Docker images are properly tagged with branch, SHA, and version
  • release.sh script creates semantic version tags with GPG signing
  • Publishing a release triggers binary builds for all platforms
  • Windows installer is automatically built and attached to releases
  • All workflows have proper caching for faster builds
  • Documentation exists for the release process

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions