24 Commits
v0.1 ... main

Author SHA1 Message Date
WDI-Ideas
baedab602c refactor(ci): remove job dependencies for pure flag execution
Drop sonar/deploy needs so each stage runs only when its own run_* flag is true.

Made-with: Cursor
2026-04-09 12:20:40 +05:30
WDI-Ideas
cf425dbc7a fix(ci): switch sonar secret names to SONARQUBE_HOST/TOKEN
Align central and quality workflows with repository secret names SONARQUBE_HOST and SONARQUBE_TOKEN and pass them to sonar-scanner via environment variables.

Made-with: Cursor
2026-04-08 20:20:01 +05:30
WDI-Ideas
32582809a1 fix(ci): align workflow_call inputs across central and deploy workflows
Pass missing branch_name/pm2_id to deploy workflow, add matching deploy inputs, and harden run_* conditions to support both boolean and string true/false values.

Made-with: Cursor
2026-04-08 20:01:15 +05:30
645a44d0f8 Update .gitea/workflows/ci.yml 2026-04-07 15:56:07 +00:00
91501feb27 Update .gitea/workflows/ci.yml 2026-04-07 14:54:40 +00:00
fa1438082f Update .gitea/workflows/ci.yml 2026-04-07 14:48:12 +00:00
bcce02dc9e Update .gitea/workflows/ci.yml 2026-04-07 14:46:00 +00:00
bf23979a4a Update .gitea/workflows/quality.yml 2026-04-07 14:41:33 +00:00
96d8b6bd67 Update .gitea/workflows/build.yml 2026-04-07 13:07:49 +00:00
36e949e752 Update .gitea/workflows/build.yml 2026-04-07 12:46:24 +00:00
16da32c424 Update .gitea/workflows/build.yml 2026-04-07 12:25:08 +00:00
173c476f74 Update .gitea/workflows/build.yml 2026-04-07 12:16:18 +00:00
1b7187bd09 Update .gitea/workflows/ci.yml 2026-04-07 11:36:00 +00:00
c98ef88d48 Update .gitea/workflows/ci.yml 2026-04-07 11:34:31 +00:00
41aff8d460 Update .gitea/workflows/ci.yml 2026-04-07 10:24:33 +00:00
bf47b5b156 Add readme.md 2026-04-07 10:20:05 +00:00
6815d4fbfd Update .gitea/workflows/deploy.yml 2026-04-07 09:45:03 +00:00
d5031ad5ad Update .gitea/workflows/deploybak.yml 2026-04-07 09:44:40 +00:00
d62b0b2d72 Update .gitea/workflows/quality.yml 2026-04-07 07:57:19 +00:00
b569e7a97b Add .gitea/workflows/quality.yml 2026-04-07 07:56:37 +00:00
0603b4f374 Add .gitea/workflows/build.yml 2026-04-07 07:52:51 +00:00
e9858cbb5d Add .gitea/workflows/ci.yml 2026-04-07 07:51:41 +00:00
7d5ed3ec51 Add actions/sonar/action.yml 2026-04-06 12:29:44 +00:00
239378e081 Update .gitea/workflows/qualitytest.yml 2026-04-06 11:51:45 +00:00
7 changed files with 607 additions and 51 deletions

View File

@@ -0,0 +1,40 @@
name: Build
on:
workflow_call:
inputs:
tech_stack:
type: string
required: true
build_command:
type: string
required: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
# 🟢 NODE / REACT / NESTJS
- name: Setup Node
if: inputs.tech_stack == 'node' || inputs.tech_stack == 'react' || inputs.tech_stack == 'nestjs'
uses: actions/setup-node@v3
with:
node-version: 20
- name: Build (Node / React / NestJS)
if: inputs.tech_stack == 'node' || inputs.tech_stack == 'react' || inputs.tech_stack == 'nestjs'
run: |
if [ -n "${{ inputs.build_command }}" ]; then
set -xe
echo "Running custom build command"
${{ inputs.build_command }}
else
set -xe
npm install
npm run build
fi

137
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,137 @@
name: Central CI
on:
workflow_call:
inputs:
run_build:
type: string
default: 'true'
run_sonar:
type: string
default: 'true'
run_deploy:
type: string
default: 'false'
wait_for_quality_gate:
type: string
default: 'true'
tech_stack:
type: string
required: true
# Variables
app_path_beta:
type: string
required: false
app_path_testing:
type: string
required: false
app_path_staging:
type: string
required: false
app_path_prod:
type: string
required: false
build_command:
type: string
required: false
deploy_command:
type: string
required: false
runtime:
type: string
required: false
pm2_id:
type: string
required: false
secrets:
SONARQUBE_HOST:
required: false
SONARQUBE_TOKEN:
required: false
BETA_SERVER_HOST:
required: false
BETA_SERVER_PORT:
required: false
BETA_SERVER_USERNAME:
required: false
BETA_SERVER_PASSWORD:
required: false
BETA_SERVER_KEY:
required: false
STAGING_SERVER_HOST:
required: false
STAGING_SERVER_PORT:
required: false
STAGING_SERVER_USERNAME:
required: false
STAGING_SERVER_PASSWORD:
required: false
STAGING_SERVER_KEY:
required: false
PROD_SERVER_HOST:
required: false
PROD_SERVER_PORT:
required: false
PROD_SERVER_USERNAME:
required: false
PROD_SERVER_PASSWORD:
required: false
PROD_SERVER_KEY:
required: false
jobs:
# 🔨 BUILD
build:
if: inputs.run_build == true || inputs.run_build == 'true'
uses: Rajendra.Reddy/wdipl-actions/.gitea/workflows/build.yml@main
with:
tech_stack: ${{ inputs.tech_stack }}
build_command: ${{ inputs.build_command }}
# 🔍 SONAR
sonar:
if: inputs.run_sonar == true || inputs.run_sonar == 'true'
uses: Rajendra.Reddy/wdipl-actions/.gitea/workflows/quality.yml@main
with:
wait_for_quality_gate: ${{ inputs.wait_for_quality_gate }}
secrets:
SONARQUBE_HOST: ${{ secrets.SONARQUBE_HOST }}
SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
# 🚀 DEPLOY
deploy:
if: inputs.run_deploy == true || inputs.run_deploy == 'true'
uses: Rajendra.Reddy/wdipl-actions/.gitea/workflows/deploy.yml@main
with:
tech_stack: ${{ inputs.tech_stack }}
branch_name: ${{ github.ref_name }}
pm2_id: ${{ inputs.pm2_id }}
deploy_command: ${{ inputs.deploy_command }}
app_path_beta: ${{ inputs.app_path_beta }}
app_path_testing: ${{ inputs.app_path_testing }}
app_path_staging: ${{ inputs.app_path_staging }}
app_path_prod: ${{ inputs.app_path_prod }}
secrets:
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 }}

View File

@@ -1,32 +1,67 @@
name: Deploy
on: on:
workflow_call: workflow_call:
inputs: inputs:
host: tech_stack:
required: true required: true
type: string type: string
username:
required: true
type: string
port:
required: true
type: number
project_folder:
required: true
type: string
pm2_id:
required: false
type: string
branch_name: branch_name:
required: true required: true
type: string type: string
tech:
required: true app_path_beta:
required: false
type: string
app_path_testing:
required: false
type: string
app_path_staging:
required: false
type: string
app_path_prod:
required: false
type: string
deploy_command:
required: false
type: string
pm2_id:
required: false
type: string type: string
secrets: secrets:
password: BETA_SERVER_HOST:
required: false required: false
key: BETA_SERVER_PORT:
required: false
BETA_SERVER_USERNAME:
required: false
BETA_SERVER_PASSWORD:
required: false
BETA_SERVER_KEY:
required: false
STAGING_SERVER_HOST:
required: false
STAGING_SERVER_PORT:
required: false
STAGING_SERVER_USERNAME:
required: false
STAGING_SERVER_PASSWORD:
required: false
STAGING_SERVER_KEY:
required: false
PROD_SERVER_HOST:
required: false
PROD_SERVER_PORT:
required: false
PROD_SERVER_USERNAME:
required: false
PROD_SERVER_PASSWORD:
required: false
PROD_SERVER_KEY:
required: false required: false
jobs: jobs:
@@ -34,49 +69,123 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Deploy via SSH
# 🔹 BETA / TESTING
- name: Deploy Beta/Testing
if: inputs.branch_name == 'beta' || inputs.branch_name == 'testing'
uses: appleboy/ssh-action@v1 uses: appleboy/ssh-action@v1
with: with:
host: ${{ inputs.host }} host: ${{ secrets.BETA_SERVER_HOST }}
username: ${{ inputs.username }} username: ${{ secrets.BETA_SERVER_USERNAME }}
password: ${{ secrets.password }} port: ${{ secrets.BETA_SERVER_PORT }}
key: ${{ secrets.key }} password: ${{ secrets.BETA_SERVER_PASSWORD }}
port: ${{ inputs.port }} key: ${{ secrets.BETA_SERVER_KEY }}
script: | script: |
set -xe set -xe
if [ "${{ inputs.branch_name }}" = "testing" ] && [ -n "${{ inputs.app_path_testing }}" ]; then
cd ${{ inputs.project_folder }} cd ${{ inputs.app_path_testing }}
else
cd ${{ inputs.app_path_beta }}
fi
git fetch git fetch
git reset --hard origin/${{ inputs.branch_name }} git reset --hard origin/${{ inputs.branch_name }}
git pull origin ${{ inputs.branch_name }} git pull origin ${{ inputs.branch_name }}
echo "Installing deps" case "${{ inputs.tech_stack }}" in
npm install node|react|nestjs)
if [ -n "${{ inputs.deploy_command }}" ]; then
echo "Running tech-specific steps" echo "Running custom deploy command"
case "${{ inputs.tech }}" in ${{ inputs.deploy_command }}
node) else
npm i npm install
npx prisma generate npm run build || true
npx prisma migrate deploy pm2 reload ${{ inputs.pm2_id }} || true
npm run build fi
pm2 reload ${{ inputs.pm2_id }}
;; ;;
nestjs) docker)
npm i docker compose up -d --build
npx prisma generate
npx prisma migrate deploy
npm run build
pm2 reload ${{ inputs.pm2_id }}
;; ;;
python)
docker-compose up -d --build
;;
*) *)
echo "Unknown tech" echo "Unknown tech"
;; ;;
esac esac
# 🔹 STAGING
- name: Deploy Staging
if: inputs.branch_name == 'staging'
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.STAGING_SERVER_HOST }}
username: ${{ secrets.STAGING_SERVER_USERNAME }}
port: ${{ secrets.STAGING_SERVER_PORT }}
password: ${{ secrets.STAGING_SERVER_PASSWORD }}
key: ${{ secrets.STAGING_SERVER_KEY }}
script: |
set -xe
cd ${{ inputs.app_path_staging }}
git fetch
git reset --hard origin/${{ inputs.branch_name }}
git pull origin ${{ inputs.branch_name }}
case "${{ inputs.tech_stack }}" in
node|react|nestjs)
if [ -n "${{ inputs.deploy_command }}" ]; then
echo "Running custom deploy command"
${{ inputs.deploy_command }}
else
npm install
npm run build || true
pm2 reload ${{ inputs.pm2_id }} || true
fi
;;
docker)
docker compose up -d --build
;;
*)
echo "Unknown tech"
;;
esac
# 🔹 PRODUCTION
- name: Deploy Production
if: inputs.branch_name == 'main' || inputs.branch_name == 'prod'
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PROD_SERVER_HOST }}
username: ${{ secrets.PROD_SERVER_USERNAME }}
port: ${{ secrets.PROD_SERVER_PORT }}
password: ${{ secrets.PROD_SERVER_PASSWORD }}
key: ${{ secrets.PROD_SERVER_KEY }}
script: |
set -xe
cd ${{ inputs.app_path_prod }}
git fetch
git reset --hard origin/${{ inputs.branch_name }}
git pull origin ${{ inputs.branch_name }}
case "${{ inputs.tech_stack }}" in
node|react|nestjs)
if [ -n "${{ inputs.deploy_command }}" ]; then
echo "Running custom deploy command"
${{ inputs.deploy_command }}
else
npm install
npm run build || true
pm2 reload ${{ inputs.pm2_id }} || true
fi
;;
docker)
docker compose up -d --build
;;
*)
echo "Unknown tech"
;;
esac

View File

@@ -0,0 +1,41 @@
name: SonarQube Analysis
on:
workflow_call:
inputs:
project_key:
type: string
required: true
wait_for_quality_gate:
type: string
default: false
secrets:
SONARQUBE_HOST:
required: true
SONARQUBE_TOKEN:
required: true
jobs:
sonarqube:
runs-on: ubuntu-latest
container:
image: sonarsource/sonar-scanner-cli:12.0.0.3214_8.0.1
options: --user root
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Run SonarQube Scan
env:
SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
run: |
sonar-scanner \
-Dsonar.projectKey=${{ inputs.project_key }} \
-Dsonar.projectName=${{ inputs.project_key }} \
-Dsonar.sources=. \
-Dsonar.exclusions=node_modules/**,dist/**,coverage/** \
-Dsonar.qualitygate.wait=${{ inputs.wait_for_quality_gate }}

View File

@@ -7,9 +7,9 @@ on:
required: true required: true
type: string type: string
secrets: secrets:
SONAR_HOST_URL: SONARQUBE_HOST:
required: true required: true
SONAR_TOKEN: SONARQUBE_TOKEN:
required: true required: true
jobs: jobs:
@@ -24,12 +24,13 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Run SonarQube Scan (with Quality Gate) - name: Run SonarQube Scan (with Quality Gate)
env:
SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
run: | run: |
sonar-scanner \ sonar-scanner \
-Dsonar.projectKey=${{ inputs.project_key }} \ -Dsonar.projectKey=${{ inputs.project_key }} \
-Dsonar.projectName=${{ inputs.project_key }} \ -Dsonar.projectName=${{ inputs.project_key }} \
-Dsonar.sources=. \ -Dsonar.sources=. \
-Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
-Dsonar.token=${{ secrets.SONAR_TOKEN }} \
-Dsonar.exclusions=node_modules/**,dist/**,coverage/** \ -Dsonar.exclusions=node_modules/**,dist/**,coverage/** \
-Dsonar.qualitygate.wait=true -Dsonar.qualitygate.wait=false

49
actions/sonar/action.yml Normal file
View File

@@ -0,0 +1,49 @@
name: "SonarQube Scan"
description: "Run SonarQube scan with Quality Gate enforcement"
inputs:
sonar_host_url:
required: true
sonar_token:
required: true
wait_for_quality_gate:
required: false
default: "true"
runs:
using: "composite"
steps:
- name: Set Project Key (from repo name)
shell: bash
run: |
echo "PROJECT_KEY=${{ gitea.event.repository.name }}" >> $GITHUB_ENV
- name: Debug Info
shell: bash
run: |
echo "Project Key: $PROJECT_KEY"
echo "Wait for Quality Gate: ${{ inputs.wait_for_quality_gate }}"
- name: Run Sonar Scanner
shell: bash
run: |
if [ "${{ inputs.wait_for_quality_gate }}" = "true" ]; then
sonar-scanner \
-Dsonar.projectKey=$PROJECT_KEY \
-Dsonar.projectName=$PROJECT_KEY \
-Dsonar.sources=. \
-Dsonar.host.url=${{ inputs.sonar_host_url }} \
-Dsonar.token=${{ inputs.sonar_token }} \
-Dsonar.exclusions=node_modules/**,dist/**,coverage/** \
-Dsonar.qualitygate.wait=true
else
sonar-scanner \
-Dsonar.projectKey=$PROJECT_KEY \
-Dsonar.projectName=$PROJECT_KEY \
-Dsonar.sources=. \
-Dsonar.host.url=${{ inputs.sonar_host_url }} \
-Dsonar.token=${{ inputs.sonar_token }} \
-Dsonar.exclusions=node_modules/**,dist/**,coverage/**
fi

179
readme.md Normal file
View File

@@ -0,0 +1,179 @@
# 🚀 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:
```yaml
name: CI
on:
push:
branches: [main, beta, staging, testing]
pull_request:
jobs:
ci:
uses: http://git.wdipl.com/Rajendra.Reddy/wdipl-actions/.gitea/workflows/ci.yml@main
with:
tech_stack: node
run_build: true
run_sonar: true
run_deploy: true
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:
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
SONAR_TOKEN: ${{ secrets.SONAR_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 |
| -------------- | ------------------------ |
| SONAR_HOST_URL | http://your-sonar-server |
| SONAR_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 |
| run_build | true/false |
| run_sonar | true/false |
| run_deploy | true/false |
| wait_for_quality_gate | true/false |
| 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
```bash
git fetch
git reset --hard origin/<branch>
git pull
npm install
npm run build
pm2 reload <pm2_id>
```
---
# ⚠️ Notes
* Use **either password OR SSH key**
* Ensure server has:
* Node.js
* PM2
* Paths must exist on server
* Deployment runs only if `run_deploy = true`
---
# ✅ Summary
1. Add `ci.yml`
2. Add secrets
3. Set paths
Done.
---