GitHub Actions
CI/CD Tool
GitHub Actions
Overview
GitHub Actions is a GitHub-native CI/CD platform. With YAML-based workflow configuration, rich marketplace, and seamless GitHub integration, it provides comprehensive automation from development to deployment.
Details
GitHub Actions is a GitHub platform-integrated CI/CD (Continuous Integration/Continuous Delivery) service provided by Microsoft. Since its release in 2019, it has played a central role in automating software development lifecycles. By defining workflows in YAML files within the .github/workflows/ directory of repositories, you can automate code building, testing, and deployment. GitHub Marketplace offers over 11,000 reusable actions, supporting a wide range of languages and frameworks including Node.js, Python, Java, and .NET. It provides Linux, macOS, Windows, ARM, and GPU runners, enabling efficient CI/CD pipeline construction through matrix builds and parallel execution. It also supports self-hosted runners, enabling flexible operation in enterprise environments. Since 2024, security features have been enhanced, providing secure development processes through Artifact Attestations, encrypted secrets, and dependency scanning.
Pros and Cons
Pros
- Complete GitHub Integration: Seamless connectivity with repositories, Issues, and Pull Requests
- Rich Marketplace: Over 11,000 reusable actions available
- Diverse Execution Environments: Support for Linux, macOS, Windows, ARM, and GPU runners
- Free Tier: Unlimited for public repositories, 2,000 minutes monthly for private repositories
- Scalability: High-speed processing through matrix builds and parallel execution
- Security: Support for encrypted secrets and Artifact Attestations
- Flexibility: Self-hosted runners and custom action creation
- Version-Controlled Configuration: Workflow settings managed through YAML files
Cons
- GitHub Lock-in: Cannot be used on platforms other than GitHub
- Cost: High cost for large-scale use with private repositories
- Learning Curve: Need to understand YAML syntax and workflow concepts
- Complex Debugging: Difficult to identify causes of workflow failures
- Execution Time Limits: Maximum 6-hour limit per job
- Storage Limitations: Limited retention period for artifacts and cache
- Network Constraints: Restrictions and rate limits on external API access
Key Links
- GitHub Actions Official Site
- GitHub Actions Official Documentation
- GitHub Marketplace
- GitHub Actions Starter Workflows
- GitHub Actions Runner
- GitHub Skills
Code Examples
Basic Node.js Workflow
# .github/workflows/node.yml
name: Node.js CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
- run: npm test
TypeScript Project CI/CD
# .github/workflows/typescript.yml
name: TypeScript CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20.x'
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Type check
run: npm run type-check
- name: Lint
run: npm run lint
- name: Run tests
run: npm run test:coverage
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
build:
needs: lint-and-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-files
path: dist/
retention-days: 30
Docker Image Build and Deploy
# .github/workflows/docker.yml
name: Docker Build and Deploy
on:
push:
branches: [main]
tags: ['v*']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
docker stop myapp || true
docker rm myapp || true
docker run -d --name myapp -p 80:3000 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
Multi-Platform Support
# .github/workflows/multi-platform.yml
name: Multi-Platform CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', '3.10', '3.11', '3.12']
exclude:
- os: macos-latest
python-version: '3.9'
- os: windows-latest
python-version: '3.12'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest
- name: Run tests
run: pytest tests/ -v
- name: Platform-specific commands
shell: bash
run: |
if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
echo "Running Ubuntu-specific commands"
sudo apt-get update
elif [[ "${{ matrix.os }}" == "windows-latest" ]]; then
echo "Running Windows-specific commands"
choco --version
elif [[ "${{ matrix.os }}" == "macos-latest" ]]; then
echo "Running macOS-specific commands"
brew --version
fi
Conditional Workflows and Release Automation
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run tests
run: npm test
- name: Generate changelog
id: changelog
run: |
# Generate changelog from git commits
echo "CHANGELOG<<EOF" >> $GITHUB_OUTPUT
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --pretty=format:"- %s (%h)" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref_name }}
release_name: Release ${{ github.ref_name }}
body: |
## Changes in this release
${{ steps.changelog.outputs.CHANGELOG }}
draft: false
prerelease: ${{ contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }}
- name: Publish to NPM
if: ${{ !contains(github.ref_name, 'beta') && !contains(github.ref_name, 'alpha') }}
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Security Scanning and Code Quality
# .github/workflows/security.yml
name: Security and Quality
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 1' # Every Monday
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run dependency vulnerability scan
uses: actions/dependency-review-action@v3
if: github.event_name == 'pull_request'
- name: Run CodeQL Analysis
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'