-
-
Notifications
You must be signed in to change notification settings - Fork 0
CI CD Integration
Norm Brandinger edited this page Nov 20, 2025
·
1 revision
Forgejo Actions and automation workflows for DevStack Core.
- Overview
- Forgejo Actions Overview
- Setting Up Actions
- Workflow Examples
- Testing Workflows
- Build Workflows
- Deployment Workflows
- Secrets in CI/CD
- Notifications
- Best Practices
- GitHub Actions Compatibility
- Related Documentation
Forgejo Actions provides GitHub Actions-compatible CI/CD pipelines for local development and testing.
CI/CD Stack:
- Platform: Forgejo (self-hosted Git with Actions)
- Runners: Forgejo Actions runners
- Compatibility: GitHub Actions syntax
- Integration: Vault, Docker, databases
Forgejo Actions is a CI/CD system compatible with GitHub Actions:
- Workflow Syntax: Same as GitHub Actions
- Action Marketplace: Can use GitHub Actions
- Runners: Self-hosted or Forgejo-managed
- Triggers: push, pull_request, schedule, manual
Git Push → Forgejo → Workflow Detection → Runner Assignment → Job Execution
↓
Results/Artifacts
# Start Forgejo
docker compose up -d forgejo
# Access UI
open http://localhost:3000
# Create admin account (first time)
# Navigate to: http://localhost:3000/install
# Configure Actions
# Settings → Actions → Enable Actions- Access Forgejo: http://localhost:3000
- Admin Panel: Site Administration → Configuration
- Enable Actions: Check "Enable Actions"
- Save Configuration
Install Forgejo Runner:
# Download runner
wget https://dl.gitea.com/act_runner/main/act_runner-main-darwin-arm64
# Make executable
chmod +x act_runner-main-darwin-arm64
# Register runner
./act_runner-main-darwin-arm64 register --instance http://localhost:3000 --token YOUR_TOKEN
# Start runner
./act_runner-main-darwin-arm64 daemonUsing Docker Runner:
# Add to docker-compose.yml
services:
forgejo-runner:
image: gitea/act_runner:latest
container_name: forgejo-runner
environment:
GITEA_INSTANCE_URL: http://forgejo:3000
GITEA_RUNNER_REGISTRATION_TOKEN: ${RUNNER_TOKEN}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- forgejo-runner-data:/data
networks:
- dev-services
depends_on:
- forgejo
volumes:
forgejo-runner-data:Create .forgejo/workflows/ directory:
cd ~/devstack-core
mkdir -p .forgejo/workflows
# Create workflow file
touch .forgejo/workflows/test.yml# .forgejo/workflows/hello.yml
name: Hello World
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
hello:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Print message
run: echo "Hello from Forgejo Actions!"# .forgejo/workflows/test.yml
name: Run Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Start services
run: |
docker compose up -d vault postgres redis-1
sleep 10
- name: Run tests
run: |
./tests/run-all-tests.sh
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results
path: test-results/
- name: Cleanup
if: always()
run: docker compose down -v# .forgejo/workflows/lint.yml
name: Lint Code
on:
push:
branches: [main, develop]
pull_request:
jobs:
lint-python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install flake8 black pylint mypy
- name: Run flake8
run: flake8 reference-apps/fastapi/app/
- name: Run black
run: black --check reference-apps/fastapi/app/
- name: Run pylint
run: pylint reference-apps/fastapi/app/
lint-go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
working-directory: reference-apps/golang# .forgejo/workflows/test-python.yml
name: Python Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: testpass
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
working-directory: reference-apps/fastapi
run: |
pip install -e ".[dev]"
- name: Run pytest
working-directory: reference-apps/fastapi
env:
DATABASE_URL: postgresql://postgres:testpass@postgres:5432/test
REDIS_URL: redis://redis:6379
run: |
pytest tests/ -v --cov=app --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: reference-apps/fastapi/coverage.xml# .forgejo/workflows/integration-tests.yml
name: Integration Tests
on:
push:
branches: [main]
pull_request:
jobs:
integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Start DevStack Core
run: |
docker compose up -d
./devstack.sh vault-init
./devstack.sh vault-bootstrap
- name: Wait for services
run: |
timeout 120 bash -c 'until docker exec postgres pg_isready; do sleep 2; done'
timeout 120 bash -c 'until docker exec redis-1 redis-cli ping; do sleep 2; done'
- name: Run integration tests
run: |
./tests/test-vault.sh
./tests/test-postgres.sh
./tests/test-redis-cluster.sh
./tests/test-fastapi.sh
- name: Collect logs
if: failure()
run: |
mkdir -p logs
docker compose logs > logs/docker-compose.log
- name: Upload logs
if: failure()
uses: actions/upload-artifact@v3
with:
name: failure-logs
path: logs/
- name: Cleanup
if: always()
run: docker compose down -v# .forgejo/workflows/build-image.yml
name: Build Docker Image
on:
push:
branches: [main]
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Registry
uses: docker/login-action@v2
with:
registry: localhost:5000
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: localhost:5000/reference-api
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha
- name: Build and push
uses: docker/build-push-action@v4
with:
context: reference-apps/fastapi
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max# .forgejo/workflows/build-multiplatform.yml
name: Build Multi-platform
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: reference-apps/fastapi
platforms: linux/amd64,linux/arm64
push: true
tags: myregistry/reference-api:${{ github.ref_name }}# .forgejo/workflows/deploy-staging.yml
name: Deploy to Staging
on:
push:
branches: [develop]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build image
run: |
docker build -t reference-api:staging reference-apps/fastapi
- name: Deploy to staging
run: |
docker compose -f docker-compose.staging.yml up -d reference-api
- name: Health check
run: |
timeout 60 bash -c 'until curl -f http://localhost:8000/health; do sleep 2; done'
- name: Run smoke tests
run: |
curl -f http://localhost:8000/health
curl -f http://localhost:8000/api/health/ready# .forgejo/workflows/deploy-production.yml
name: Deploy to Production
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Pull latest image
run: docker pull myregistry/reference-api:${{ github.event.release.tag_name }}
- name: Backup database
run: |
./devstack.sh backup
- name: Deploy
run: |
docker compose pull reference-api
docker compose up -d reference-api
- name: Health check
run: |
timeout 120 bash -c 'until curl -f http://localhost:8000/health; do sleep 2; done'
- name: Rollback on failure
if: failure()
run: |
docker compose up -d reference-api- Repository Settings: Navigate to repository → Settings → Secrets
- Add Secrets: Add secret name and value
-
Use in Workflow:
${{ secrets.SECRET_NAME }}
Common Secrets:
secrets:
VAULT_TOKEN: "hvs.xxxxx"
DATABASE_PASSWORD: "secure_password"
REGISTRY_USERNAME: "user"
REGISTRY_PASSWORD: "pass"
SLACK_WEBHOOK: "https://hooks.slack.com/..."# Use Vault in workflow
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Get secrets from Vault
env:
VAULT_ADDR: http://vault:8200
VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }}
run: |
# Install Vault CLI
wget https://releases.hashicorp.com/vault/1.15.0/vault_1.15.0_linux_amd64.zip
unzip vault_1.15.0_linux_amd64.zip
# Get secrets
export DB_PASSWORD=$(./vault kv get -field=password secret/postgres)
echo "DB_PASSWORD=$DB_PASSWORD" >> $GITHUB_ENV
- name: Use secrets
run: |
echo "Database password retrieved from Vault"# .forgejo/workflows/notify-slack.yml
name: Notify Slack
on:
push:
branches: [main]
pull_request:
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Notify Slack on success
if: success()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "✅ Build succeeded: ${{ github.repository }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Build Succeeded*\nRepository: ${{ github.repository }}\nBranch: ${{ github.ref_name }}\nCommit: ${{ github.sha }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
- name: Notify Slack on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "❌ Build failed: ${{ github.repository }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}# Add email step
- name: Send email
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: "Build Failed: ${{ github.repository }}"
to: team@example.com
from: ci@example.com
body: |
Build failed for ${{ github.repository }}
Branch: ${{ github.ref_name }}
Commit: ${{ github.sha }}# Comment on PR
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ All tests passed!'
}).forgejo/workflows/
├── ci.yml # Main CI pipeline
├── test.yml # Test suite
├── lint.yml # Code linting
├── build.yml # Build images
├── deploy-staging.yml # Deploy to staging
└── deploy-prod.yml # Deploy to production
# Use caching
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
# Parallel jobs
jobs:
test-unit:
runs-on: ubuntu-latest
steps: [...]
test-integration:
runs-on: ubuntu-latest
steps: [...]
lint:
runs-on: ubuntu-latest
steps: [...]
# Conditional execution
- name: Deploy
if: github.ref == 'refs/heads/main'
run: ./deploy.sh# 1. Use secrets for sensitive data
env:
DATABASE_PASSWORD: ${{ secrets.DB_PASSWORD }}
# 2. Minimize secret exposure
- name: Login
run: echo "${{ secrets.PASSWORD }}" | docker login -u user --password-stdin
# 3. Use environment protection
jobs:
deploy:
environment: production
steps: [...]
# 4. Review workflow permissions
permissions:
contents: read
pull-requests: writeMost GitHub Actions work with Forgejo:
# Checkout
- uses: actions/checkout@v3
# Setup languages
- uses: actions/setup-python@v4
- uses: actions/setup-node@v3
- uses: actions/setup-go@v4
# Docker
- uses: docker/setup-buildx-action@v2
- uses: docker/build-push-action@v4
# Artifacts
- uses: actions/upload-artifact@v3
- uses: actions/download-artifact@v3-
Copy workflows: Copy
.github/workflows/to.forgejo/workflows/ - Update references: Change GitHub-specific variables
- Test locally: Run with act (GitHub Actions locally)
- Adjust paths: Update any GitHub-specific paths
# Test workflow locally with act
brew install act
act -l # List workflows
act push # Simulate push event- Forgejo Setup - Forgejo configuration
- Testing Guide - Testing strategies
- Contributing Guide - Contribution workflow
- Development Workflow - Development process
- Deployment Guide - Deployment strategies
Quick Reference Card:
# Basic Workflow
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: ./tests/run-all-tests.sh
# With Services
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
# With Secrets
env:
VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }}
# With Artifacts
- uses: actions/upload-artifact@v3
with:
name: test-results
path: results/