Made-with: Cursor
🚀 CI/CD Setup Guide (For Developers)
This project uses a centralized CI/CD system. You only need to configure 1 workflow file + secrets.
📁 1. Add Workflow File
Create:
.gitea/workflows/ci.yml
Paste:
name: CI
on:
push:
branches: [main, beta, staging, testing]
pull_request:
jobs:
ci:
# Prefer a commit SHA from wdipl-actions @main (see "stale reusable workflows" above).
uses: http://git.wdipl.com/Rajendra.Reddy/wdipl-actions/.gitea/workflows/ci.yml@main
with:
tech_stack: node
# Comma-separated: build, sonar, deploy (WDIPL-Runner only forwards one “flag” string reliably).
ci_steps: 'build,sonar,deploy'
wait_for_quality_gate: 'false'
app_path_beta: /var/www/app-beta
app_path_staging: /var/www/app-staging
app_path_prod: /var/www/app-prod
pm2_id: app
secrets:
SONARQUBE_HOST: ${{ secrets.SONARQUBE_HOST }}
SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
BETA_SERVER_HOST: ${{ secrets.BETA_SERVER_HOST }}
BETA_SERVER_PORT: ${{ secrets.BETA_SERVER_PORT }}
BETA_SERVER_USERNAME: ${{ secrets.BETA_SERVER_USERNAME }}
BETA_SERVER_PASSWORD: ${{ secrets.BETA_SERVER_PASSWORD }}
BETA_SERVER_KEY: ${{ secrets.BETA_SERVER_KEY }}
STAGING_SERVER_HOST: ${{ secrets.STAGING_SERVER_HOST }}
STAGING_SERVER_PORT: ${{ secrets.STAGING_SERVER_PORT }}
STAGING_SERVER_USERNAME: ${{ secrets.STAGING_SERVER_USERNAME }}
STAGING_SERVER_PASSWORD: ${{ secrets.STAGING_SERVER_PASSWORD }}
STAGING_SERVER_KEY: ${{ secrets.STAGING_SERVER_KEY }}
PROD_SERVER_HOST: ${{ secrets.PROD_SERVER_HOST }}
PROD_SERVER_PORT: ${{ secrets.PROD_SERVER_PORT }}
PROD_SERVER_USERNAME: ${{ secrets.PROD_SERVER_USERNAME }}
PROD_SERVER_PASSWORD: ${{ secrets.PROD_SERVER_PASSWORD }}
PROD_SERVER_KEY: ${{ secrets.PROD_SERVER_KEY }}
🔐 2. Add Secrets (Repo → Settings → Secrets)
SonarQube
| Name | Value |
|---|---|
| SONARQUBE_HOST | http://your-sonar-server |
| SONARQUBE_TOKEN | your sonar token |
Beta / Testing Server
| Name | Value |
|---|---|
| BETA_SERVER_HOST | server IP/domain |
| BETA_SERVER_PORT | 22 |
| BETA_SERVER_USERNAME | ssh user (ubuntu/root) |
| BETA_SERVER_PASSWORD | password (optional) |
| BETA_SERVER_KEY | private ssh key (optional) |
Staging Server
| Name | Value |
|---|---|
| STAGING_SERVER_HOST | server IP/domain |
| STAGING_SERVER_PORT | 22 |
| STAGING_SERVER_USERNAME | ssh user |
| STAGING_SERVER_PASSWORD | password (optional) |
| STAGING_SERVER_KEY | ssh key (optional) |
Production Server
| Name | Value |
|---|---|
| PROD_SERVER_HOST | server IP/domain |
| PROD_SERVER_PORT | 22 |
| PROD_SERVER_USERNAME | ssh user |
| PROD_SERVER_PASSWORD | password (optional) |
| PROD_SERVER_KEY | ssh key (optional) |
⚙️ 3. Variables (Edit in ci.yml)
| Variable | What to set |
|---|---|
| tech_stack | node / react / nestjs |
| ci_steps | e.g. build,sonar,deploy — no spaces (runner has no replace()) |
| wait_for_quality_gate | 'true' / 'false' (quoted) |
| app_path_beta | path on beta server |
| app_path_staging | path on staging server |
| app_path_prod | path on prod server |
| pm2_id | pm2 app name |
🌿 4. Branch Behavior
| Branch | Action |
|---|---|
| feature/* | Build + Sonar |
| develop | Build + Sonar |
| testing | Deploy to Beta |
| beta | Deploy to Beta |
| staging | Deploy to Staging |
| main / prod | Deploy to Production |
⚙️ 5. What Happens on Deploy
git fetch
git reset --hard origin/<branch>
git pull
npm install
npm run build
pm2 reload <pm2_id>
WDIPL-Runner: stale reusable workflows (uses: ...@main)
The runner caches clones under /root/.cache/act/ (e.g. Rajendra.Reddy-wdipl-actions@main). After you change wdipl-actions, consumers may still execute an old ci.yml (wrong if: / missing ci_steps).
Central ci.yml includes a meta job that writes ci_steps to $GITHUB_OUTPUT so needs.meta.outputs.cs stays available for Sonar/Deploy: WDIPL-Runner clears inputs.ci_steps after the Build reusable workflow runs.
Fix one of:
- Pin
uses:to a commit SHA fromwdipl-actions, e.g.
uses: .../ci.yml@08e779fe5701557b6a589308816be97c20d78dbb
Bump the SHA whenever you change central CI. - On the runner host, delete that cache folder and re-run the workflow.
- Upgrade the runner if a newer release fixes cache invalidation.
Gitea MCP + Actions API (Cursor)
Official gitea-mcp (and the Go SDK it uses) calls GET /api/v1/repos/{owner}/{repo}/actions/runs to list workflow runs and job logs.
- Gitea 1.24.x exposes
/actions/tasksfor the same data but does not register/actions/runs(returns404 page not found). Tools likeactions_run_read→list_runs/list_jobswill fail until the server is updated or a proxy workaround is applied. - Gitea 1.25+ includes
ListWorkflowRunsat/actions/runs— upgradegit.wdipl.comto 1.25 or newer so MCP can list runs and fetch logs without hacks.
Reverse-proxy workaround (until upgrade): map list-runs requests to tasks (response shape is compatible for listing):
# Only for the repository runs list endpoint (no trailing /{run})
location ~ ^/api/v1/repos/([^/]+)/([^/]+)/actions/runs$ {
proxy_pass http://127.0.0.1:3000/api/v1/repos/$1/$2/actions/tasks$is_args$args;
# ... usual proxy headers to your Gitea backend
}
Adjust proxy_pass to your Gitea HTTP upstream. Redeploy/reload nginx, then restart Cursor.
Cursor: set a user or system environment variable GITEA_ACCESS_TOKEN (PAT with repo + Actions read scope) and use ${env:GITEA_ACCESS_TOKEN} in ~/.cursor/mcp.json — do not store tokens in that file.
⚠️ Notes
-
Use either password OR SSH key
-
Ensure server has:
- Node.js
- PM2
-
Paths must exist on server
-
Deployment runs only if
ci_stepsincludesdeploy(comma‑bounded token)
✅ Summary
- Add
ci.yml - Add secrets
- Set paths
Done.