GitHub Actions CI/CD Guide
This guide explains the automated workflows configured for the MyStation project using GitHub Actions.
Overview​
MyStation uses two GitHub Actions workflows for continuous integration and deployment:
- Build and Release Firmware - Compiles ESP32 firmware and creates releases
- Deploy Documentation - Builds and deploys Docusaurus documentation to GitHub Pages
Workflow 1: Build and Release Firmware​
File: .github/workflows/build-firmware.yml
Purpose​
Automatically builds ESP32 firmware whenever code changes are pushed or a new version is tagged. Creates GitHub Releases for tagged versions.
When It Runs​
Trigger Conditions:
- Pull Requests to
mainbranch → Build and test - Tags matching
v*pattern (e.g.,v1.0.0,v2.1.3) → Build and release
Example:
# This triggers build only (PR)
git checkout -b feature/new-display-mode
git commit -m "Add new display mode"
git push origin feature/new-display-mode
# → Open PR → GitHub Actions builds firmware
# This triggers build + release
git tag v1.2.0
git push origin v1.2.0
# → GitHub Actions builds AND creates release
What It Does​
Job 1: Build​
Environment: Ubuntu Latest
Matrix Strategy: Builds for esp32-c3-production environment
Steps:
-
Checkout Code
- uses: actions/checkout@v4Clones the repository to the GitHub Actions runner.
-
Cache Dependencies
- uses: actions/cache@v4Caches PlatformIO packages and Python pip to speed up builds.
- Cached items:
~/.cache/pip,~/.platformio/.cache,~/.platformio/packages - Cache key: OS-specific (e.g.,
Linux-pio)
- Cached items:
-
Setup Python
- uses: actions/setup-python@v5
with:
python-version: '3.11'Installs Python 3.11 for PlatformIO.
-
Install PlatformIO
pip install --upgrade platformio==6.1.18Installs specific PlatformIO version for consistency.
-
Create Secrets Files
cat > src/secrets/general_secrets.h << EOF
#define GOOGLE_API_KEY "${{ secrets.GOOGLE_API_KEY }}"
#define ENCRYPTION_KEY "${{ secrets.ENCRYPTION_KEY }}"
#define RMV_API_KEY "${{ secrets.RMV_API_KEY }}"
EOFImportant: This step creates the secrets header file from GitHub Secrets.
Required Secrets (configure in GitHub Settings → Secrets):
GOOGLE_API_KEY- Google Geolocation API keyENCRYPTION_KEY- AES encryption key for secure storageRMV_API_KEY- RMV public transport API keyACTION_TOKEN- GitHub Personal Access Token for releases
-
Build Firmware
pio run -e esp32-c3-productionCompiles firmware for ESP32-C3 production environment.
Output Files:
.pio/build/esp32-c3-production/firmware.bin- Main firmware.pio/build/esp32-c3-production/bootloader.bin- Bootloader.pio/build/esp32-c3-production/partitions.bin- Partition table.pio/build/esp32-c3-production/firmware.elf- Debug symbols
-
Create Build Info
echo "Commit: ${{ github.sha }}" >> build_info.txt
echo "Branch: ${{ github.ref_name }}" >> build_info.txtGenerates metadata file with build information.
-
Upload Artifacts
- uses: actions/upload-artifact@v4Uploads compiled binaries as workflow artifacts.
- Retention: 30 days
- Includes: All
.binfiles,firmware.elf,build_info.txt
Job 2: Release​
Depends On: build job
Condition: Only runs when a version tag is pushed (if: github.ref_type == 'tag')
Steps:
-
Download Artifacts
- uses: actions/download-artifact@v5Downloads all build artifacts from the build job.
-
Create Release Package
- Copies firmware binaries to
release/directory - Creates
FLASHING_INSTRUCTIONS.mdwith detailed flashing guide - Generates
VERSION.txtwith version information - Creates ZIP package:
mystation-firmware-{commit}.zip
- Copies firmware binaries to
-
Create GitHub Release
- uses: softprops/action-gh-release@v2Creates a new GitHub Release with:
- Name:
MyStation E-Board v1.2.0 - Tag: Version tag (e.g.,
v1.2.0) - Files: All binaries, instructions, and package
- Body: Auto-generated release notes with:
- What's new
- Files included
- Quick flash command
- Documentation links
- Name:
Artifacts Produced​
mystation-firmware-{sha}/
├── firmware.bin # Main application binary
├── bootloader.bin # ESP32 bootloader
├── partitions.bin # Partition table
├── firmware.elf # Debug symbols (for crash analysis)
├── littlefs.bin # Web interface filesystem
├── build_info.txt # Build metadata
├── config_my_station.html # Configuration web page
├── FLASHING_INSTRUCTIONS.md # User guide
└── VERSION.txt # Version information
Configuration​
PlatformIO Default Environment: esp32-s3-production
Workflow 2: Deploy Documentation​
File: .github/workflows/deploy-docs.yml
Purpose​
Automatically builds and deploys the Docusaurus documentation website to GitHub Pages whenever documentation files are updated.
When It Runs​
Trigger Conditions:
- Push to
mainbranch → Build and deploy - Push to branches starting with
docs(e.g.,docs-update,docs/feature) → Build only (preview) - Pull Request to
main→ Build only (verify) - Manual Trigger (
workflow_dispatch) → Build and deploy
Paths Watched:
docs/**- Documentation contentwebsite/**- Docusaurus configuration and theme.github/workflows/deploy-docs.yml- The workflow itself
Example:
# Triggers build + deploy (main branch)
git checkout main
git commit -m "Update user guide"
git push origin main
# → Builds and deploys to GitHub Pages
# Triggers build only (docs branch)
git checkout -b docs-new-feature
git commit -m "Add new feature documentation"
git push origin docs-new-feature
# → Builds but doesn't deploy (preview only)
# Manual trigger (from GitHub UI)
# Go to Actions → Deploy Documentation → Run workflow
# → Builds and deploys regardless of branch
What It Does​
Job 1: Build​
Environment: Ubuntu Latest Node.js Version: 22 (Latest LTS)
Steps:
-
Checkout Repository
- uses: actions/checkout@v5Clones the repository with documentation files.
-
Setup Node.js
- uses: actions/setup-node@v6
with:
node-version: '22'Installs Node.js 22 LTS for Docusaurus.
-
Install Dependencies
cd website
npm installInstalls all npm packages from
website/package.json:@docusaurus/core@docusaurus/preset-classic- Theme packages
- Plugins (Mermaid, etc.)
-
Build Docusaurus Site
npm run buildRuns Docusaurus production build:
- Processes all markdown files
- Renders Mermaid diagrams
- Generates static HTML
- Optimizes assets (JS, CSS)
- Creates search index
Output:
website/build/directory with complete static site -
Upload Artifact
- uses: actions/upload-pages-artifact@v3
with:
path: ./website/buildUploads the built site for deployment.
Job 2: Deploy​
Depends On: build job
Environment: github-pages (special GitHub environment)
Condition: Only deploys from main branch or manual trigger
Permissions Required:
permissions:
contents: read # Read repository
pages: write # Write to GitHub Pages
id-token: write # Verify identity
Steps:
-
Deploy to GitHub Pages
- uses: actions/deploy-pages@v4Deploys the built site to GitHub Pages:
- Publishes to
https://{username}.github.io/{repo}/ - Updates the live documentation site
- Returns the deployment URL
- Publishes to
Concurrency Control​
concurrency:
group: "pages"
cancel-in-progress: false
Purpose: Prevents multiple deployments from running simultaneously.
- Only one deployment can run at a time
- New deployments wait for current one to finish (no cancellation)
- Ensures stable, consistent deployments
Deployment URL​
After successful deployment, documentation is available at:
https://gogo-boot.github.io/mystation/
Structure:
/- Homepage/docs/user-guide/quick-start- User documentation/docs/developer-guide/index- Developer documentation/docs/reference/configuration-keys-quick-reference- Quick references
Setting Up GitHub Actions​
Required Repository Secrets​
Navigate to: Settings → Secrets and variables → Actions → New repository secret
| Secret Name | Description | Example |
|---|---|---|
GOOGLE_API_KEY | Encrypted Google Geolocation API key | AIzaSyC... |
ENCRYPTION_KEY | 32-character AES encryption key | your-32-char-encryption-key-here |
RMV_API_KEY | Encrypted RMV public transport API key | your-rmv-api-key |
ACTION_TOKEN | GitHub Personal Access Token (classic) | ghp_... |
Creating ACTION_TOKEN:
- Go to GitHub Settings → Developer settings → Personal access tokens
- Generate new token (classic)
- Select scopes:
repo(full repository access) - Copy token and add as secret
Enabling GitHub Pages​
- Go to Settings → Pages
- Source: GitHub Actions
- No additional configuration needed (workflow handles deployment)
Manual Workflow Triggers​
Triggering Documentation Deployment​
Via GitHub UI:
- Go to Actions tab
- Select "Deploy Docusaurus Documentation"
- Click Run workflow
- Select branch (usually
main) - Click Run workflow button
Via GitHub CLI:
gh workflow run deploy-docs.yml
Use Case: Force documentation update without code changes
Creating a Release​
Via Git Tag:
# Create and push tag
git tag v1.0.0
git push origin v1.0.0
# Or create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
Via GitHub UI:
- Go to Releases tab
- Click Draft a new release
- Create new tag (e.g.,
v1.0.0) - Click Publish release
- Workflow automatically triggered
Cost and Usage Limits​
GitHub Actions Limits​
Free Tier (Public Repositories):
- ✅ Unlimited minutes
- ✅ Unlimited storage (artifacts expire after 90 days max)
Private Repositories:
- 2,000 minutes/month (Free tier)
- 500 MB storage for artifacts
Optimization Tips​
- Use caching - Reduces build time and bandwidth
- Clean up old artifacts - Set appropriate retention days
- Cancel redundant runs - Push force updates cancel old runs
- Use matrix builds - Parallel execution is free
Summary​
Build Firmware Workflow​
- Triggers: Pull requests, version tags
- Duration: ~2 minutes (cached)
- Output: Compiled binaries + GitHub Release
- Purpose: Automated firmware compilation and distribution
Deploy Docs Workflow​
- Triggers: Pushes to main/docs branches, manual
- Duration: ~1 minute (cached)
- Output: Live documentation website
- Purpose: Automated documentation deployment
Both workflows ensure:
- ✅ Consistent builds across environments
- ✅ Automated testing and deployment
- ✅ Version tracking and artifacts
- ✅ Reduced manual errors
Related Documentation​
- Development Setup - Local build instructions
- Configuration Layers - How configuration works
- Testing - Running tests locally
- Run Book - Operational procedures and troubleshooting