14 KiB
Gitea Actions CI/CD Setup
This document describes the CI/CD pipeline configuration for the GlyphDiff project using Gitea Actions (GitHub Actions compatible).
Table of Contents
- Overview
- Workflow Files
- Workflow Triggers
- Setup Instructions
- Self-Hosted Runner Setup
- Caching Strategy
- Environment Variables
- Troubleshooting
Overview
The CI/CD pipeline consists of four main workflows:
- Lint - Code quality checks (oxlint, dprint formatting)
- Test - Type checking and E2E tests (Playwright)
- Build - Production build verification
- Deploy - Deployment automation (optional/template)
All workflows are designed to run on both push and pull request events, with appropriate branch filtering and concurrency controls.
Workflow Files
.gitea/workflows/lint.yml
Purpose: Run code quality checks to ensure code style and formatting standards.
Checks performed:
oxlint- Fast JavaScript/TypeScript linterdprint check- Code formatting verification
Triggers:
- Push to
main,develop,feature/*branches - Pull requests to
mainordevelop - Manual workflow dispatch
Cache: Node modules and Yarn cache
Concurrency: Cancels in-progress runs for the same branch when a new commit is pushed.
.gitea/workflows/test.yml
Purpose: Run type checking and end-to-end tests.
Jobs:
1. type-check job
tsc --noEmit- TypeScript type checkingsvelte-check --threshold warning- Svelte component type checking
2. e2e-tests job
- Installs Playwright browsers with system dependencies
- Runs E2E tests using Playwright
- Uploads test report artifacts (retained for 7 days)
- Uploads screenshots on test failure for debugging
Triggers: Same as lint workflow
Cache: Node modules and Yarn cache
Artifacts:
playwright-report- Test execution reportplaywright-screenshots- Screenshots from failed tests
.gitea/workflows/build.yml
Purpose: Verify that the production build completes successfully.
Steps:
- Checkout repository
- Setup Node.js v20 with Yarn caching
- Install dependencies with
--frozen-lockfile - Run
svelte-kit syncto prepare SvelteKit - Build the project with
NODE_ENV=production - Upload build artifacts (
.svelte-kit/output,.svelte-kit/build) - Run the preview server and verify it responds (health check)
Triggers:
- Push to
mainordevelopbranches - Pull requests to
mainordevelop - Manual workflow dispatch
Cache: Node modules and Yarn cache
Artifacts:
build-artifacts- Compiled SvelteKit output (retained for 7 days)
.gitea/workflows/deploy.yml
Purpose: Automated deployment pipeline (template configuration).
Current state: Placeholder configuration. Uncomment and customize one of the deployment examples.
Pre-deployment checks:
- Must pass linting workflow
- Must pass testing workflow
- Must pass build workflow
Deployment examples included:
- Docker container registry - Build and push Docker image
- SSH deployment - Deploy to server via SSH
- Vercel - Deploy to Vercel platform
Triggers:
- Push to
mainbranch - Manual workflow dispatch with environment selection (staging/production)
Secrets required (configure in Gitea):
- For Docker:
REGISTRY_URL,REGISTRY_USERNAME,REGISTRY_PASSWORD - For SSH:
DEPLOY_HOST,DEPLOY_USER,DEPLOY_SSH_KEY - For Vercel:
VERCEL_TOKEN,VERCEL_ORG_ID,VERCEL_PROJECT_ID
Workflow Triggers
Branch-Specific Behavior
| Workflow | Push Triggers | PR Triggers | Runs on Merge |
|---|---|---|---|
| Lint | main, develop, feature/* |
To main, develop |
Yes |
| Test | main, develop, feature/* |
To main, develop |
Yes |
| Build | main, develop |
To main, develop |
Yes |
| Deploy | main only |
None | Yes |
Concurrency Strategy
All workflows use concurrency groups based on the workflow name and branch reference:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # or false for deploy workflow
This ensures:
- For lint/test/build: New commits cancel in-progress runs (saves resources)
- For deploy: Prevents concurrent deployments (ensures safety)
Setup Instructions
Step 1: Verify Gitea Actions is Enabled
- Navigate to your Gitea instance
- Go to Site Administration → Actions
- Ensure Actions is enabled
- Configure default runner settings if needed
Step 2: Configure Repository Settings
- Go to your repository in Gitea
- Click Settings → Actions
- Enable Actions for the repository if not already enabled
- Set appropriate permissions for read/write access
Step 3: Push Workflows to Repository
The workflow files are already in .gitea/workflows/. Commit and push them:
git add .gitea/workflows/
git commit -m "Add Gitea Actions CI/CD workflows"
git push origin main
Step 4: Verify Workflows Run
- Navigate to Actions tab in your repository
- You should see the workflows trigger on the next push
- Click into a workflow run to view logs and status
Step 5: Configure Secrets (Optional - for deployment)
- Go to repository Settings → Secrets → Actions
- Click Add New Secret
- Add secrets required for your deployment method
Example secrets for SSH deployment:
DEPLOY_HOST=your-server.com
DEPLOY_USER=deploy
DEPLOY_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
Self-Hosted Runner Setup
Option 1: Using Gitea's Built-in Act Runner (Recommended)
Gitea provides act_runner (compatible with GitHub Actions runner).
Install act_runner
On Linux (Debian/Ubuntu):
wget -O /usr/local/bin/act_runner https://gitea.com/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
chmod +x /usr/local/bin/act_runner
Verify installation:
act_runner --version
Register the Runner
- In Gitea, navigate to repository Settings → Actions → Runners
- Click New Runner
- Copy the registration token
- Run the registration command:
act_runner register \
--instance https://your-gitea-instance.com \
--token YOUR_REGISTRATION_TOKEN \
--name "linux-runner-1" \
--labels ubuntu-latest,linux,docker \
--no-interactive
Start the Runner as a Service
Create a systemd service file at /etc/systemd/system/gitea-runner.service:
[Unit]
Description=Gitea Actions Runner
After=network.target
[Service]
Type=simple
User=git
WorkingDirectory=/var/lib/gitea-runner
ExecStart=/usr/local/bin/act_runner daemon
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable gitea-runner
sudo systemctl start gitea-runner
Check Runner Status
sudo systemctl status gitea-runner
Verify in Gitea: The runner should appear as Online with the ubuntu-latest label.
Option 2: Using Self-Hosted Runners with Docker
If you prefer Docker-based execution:
Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
Configure Runner to Use Docker
Ensure the runner has access to the Docker socket:
sudo usermod -aG docker act_runner_user
The workflows will now run containers inside the runner's Docker environment.
Option 3: Using External Runners (GitHub Actions Runner Compatible)
If you want to use standard GitHub Actions runners:
# Download and configure GitHub Actions runner
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz
# Configure to point to Gitea instance
./config.sh --url https://your-gitea-instance.com --token YOUR_TOKEN
Caching Strategy
Node.js and Yarn Cache
All workflows use actions/setup-node@v4 with built-in caching:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'
This caches:
node_modulesdirectory- Yarn cache directory (
~/.yarn/cache) - Reduces installation time from minutes to seconds on subsequent runs
Playwright Cache
Playwright browsers are installed fresh each time. To cache Playwright (optional optimization):
- name: Cache Playwright binaries
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-playwright-
Environment Variables
Default Environment Variables
The workflows use the following environment variables:
NODE_ENV=production # For build workflow
NODE_VERSION=20 # Node.js version used across all workflows
Custom Environment Variables
To add custom environment variables:
- Go to repository Settings → Variables → Actions
- Click Add New Variable
- Add variable name and value
- Set scope (environment, repository, or organization)
Example for feature flags:
ENABLE_ANALYTICS=false
API_URL=https://api.example.com
Access in workflow:
env:
API_URL: ${{ vars.API_URL }}
ENABLE_ANALYTICS: ${{ vars.ENABLE_ANALYTICS }}
Troubleshooting
Workflows Not Running
Symptoms: Workflows don't appear or don't trigger
Solutions:
- Verify Actions is enabled in Gitea site administration
- Check repository Settings → Actions is enabled
- Verify workflow files are in
.gitea/workflows/directory - Check workflow YAML syntax (no indentation errors)
Runner Offline
Symptoms: Runner shows as Offline or Idle
Solutions:
- Check runner service status:
sudo systemctl status gitea-runner - Review runner logs:
journalctl -u gitea-runner -f - Verify network connectivity to Gitea instance
- Restart runner:
sudo systemctl restart gitea-runner
Linting Fails with Formatting Errors
Symptoms: dprint check fails on CI but passes locally
Solutions:
- Ensure dprint configuration (
dprint.json) is committed - Run
yarn dprint fmtlocally before committing - Consider adding auto-fix workflow (see below)
Playwright Tests Timeout
Symptoms: E2E tests fail with timeout errors
Solutions:
- Check
playwright.config.tstimeout settings - Ensure preview server starts before tests run (built into config)
- Increase timeout in workflow:
- name: Run Playwright tests run: yarn test:e2e env: PLAYWRIGHT_TIMEOUT: 60000
Build Fails with Out of Memory
Symptoms: Build fails with memory allocation errors
Solutions:
- Increase Node.js memory limit:
- name: Build project run: yarn build env: NODE_OPTIONS: --max-old-space-size=4096 - Ensure runner has sufficient RAM (minimum 2GB recommended)
Permission Denied on Runner
Symptoms: Runner can't access repository or secrets
Solutions:
- Verify runner has read access to repository
- Check secret names match exactly in workflow
- Ensure runner user has file system permissions
Yarn Install Fails with Lockfile Conflict
Symptoms: yarn install --frozen-lockfile fails
Solutions:
- Ensure
yarn.lockis up-to-date locally - Run
yarn installand commit updatedyarn.lock - Do not use
--frozen-lockfileif using different platforms (arm64 vs amd64)
Slow Workflow Execution
Symptoms: Workflows take too long to complete
Solutions:
- Verify caching is working (check logs for "Cache restored")
- Use
--frozen-lockfilefor faster dependency resolution - Consider matrix strategy for parallel execution (not currently used)
- Optimize Playwright tests (reduce test count, increase timeouts only if needed)
Best Practices
1. Keep Dependencies Updated
Regularly update action versions:
- uses: actions/checkout@v4 # Update from v3 to v4 when available
- uses: actions/setup-node@v4
2. Use Frozen Lockfile
Always use --frozen-lockfile in CI to ensure reproducible builds:
yarn install --frozen-lockfile
3. Monitor Workflow Status
Set up notifications for workflow failures:
- Email notifications in Gitea user settings
- Integrate with Slack/Mattermost for team alerts
- Use status badges in README
4. Test Locally Before Pushing
Run the same checks locally:
yarn lint # oxlint
yarn dprint check # Formatting check
yarn tsc --noEmit # Type check
yarn test:e2e # E2E tests
yarn build # Build
5. Leverage Git Hooks
The project uses lefthook for pre-commit/pre-push checks. This catches issues before they reach CI:
# Pre-commit: Format code, lint staged files
# Pre-push: Full type check, format check, full lint
Additional Resources
- Gitea Actions Documentation
- Gitea act_runner Documentation
- GitHub Actions Documentation
- SvelteKit Deployment Guide
- Playwright CI/CD Guide
Status Badges
Add status badges to your README.md:



Next Steps
- Customize deployment: Modify
deploy.ymlwith your deployment strategy - Add notifications: Set up workflow failure notifications
- Optimize caching: Add Playwright cache if needed
- Add badges: Include status badges in README
- Schedule tasks: Add periodic tests or dependency updates (optional)
Last Updated: December 30, 2025 Version: 1.0.0