ci: setup odoo 18 scaffolding and workflows
This commit is contained in:
parent
5b0a3de8ac
commit
d610095b71
|
|
@ -0,0 +1,48 @@
|
||||||
|
name: Auto Delete Branch After Merge
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [closed]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
delete-merged-branch:
|
||||||
|
if: github.event.pull_request.merged == true
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Delete merged branch
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const base = context.payload.pull_request.base.ref;
|
||||||
|
const head = context.payload.pull_request.head.ref;
|
||||||
|
const owner = context.repo.owner;
|
||||||
|
const repo = context.repo.repo;
|
||||||
|
|
||||||
|
core.info(`Check Deletion for: ${head} (merged into ${base})`);
|
||||||
|
|
||||||
|
// Protected Patterns
|
||||||
|
const protectedPrefixes = ["dev_", "preprod_", "master_", "main"];
|
||||||
|
|
||||||
|
// Check if head branch is protected
|
||||||
|
const isProtected = protectedPrefixes.some(prefix => head.startsWith(prefix));
|
||||||
|
|
||||||
|
if (isProtected) {
|
||||||
|
core.info(`🛡️ Branch '${head}' is a protected environment branch. Skipping deletion.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional Safety: Don't delete if it's not a standard feature/fix pattern?
|
||||||
|
// User wants to clean up users branches.
|
||||||
|
|
||||||
|
try {
|
||||||
|
core.info(`🧹 Deleting branch: ${head}`);
|
||||||
|
await github.rest.git.deleteRef({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
ref: `heads/${head}`
|
||||||
|
});
|
||||||
|
core.info("✅ Branch deleted successfully.");
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Failed to delete branch: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
name: Hydra Deployment Manager (Odoo 18)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'dev_**'
|
||||||
|
- 'preprod_**'
|
||||||
|
# - 'master_**'
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
target_env:
|
||||||
|
description: 'Target Environment'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- dev
|
||||||
|
- preprod
|
||||||
|
- prod
|
||||||
|
default: 'dev'
|
||||||
|
force_restart:
|
||||||
|
description: 'Force Service Restart'
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy
|
||||||
|
steps:
|
||||||
|
- name: Extract Context
|
||||||
|
id: context
|
||||||
|
run: |
|
||||||
|
REF_NAME=${{ github.ref_name }}
|
||||||
|
EVENT_NAME=${{ github.event_name }}
|
||||||
|
INPUT_ENV=${{ inputs.target_env }}
|
||||||
|
|
||||||
|
echo "Processing Event: $EVENT_NAME on Ref: $REF_NAME"
|
||||||
|
|
||||||
|
ENV=""
|
||||||
|
MODULE=""
|
||||||
|
PORT=""
|
||||||
|
|
||||||
|
# Logic:
|
||||||
|
if [ "$EVENT_NAME" == "push" ]; then
|
||||||
|
if [[ "$REF_NAME" == dev_* ]]; then
|
||||||
|
ENV="dev"
|
||||||
|
MODULE=${REF_NAME#dev_}
|
||||||
|
elif [[ "$REF_NAME" == preprod_* ]]; then
|
||||||
|
ENV="preprod"
|
||||||
|
MODULE=${REF_NAME#preprod_}
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [ "$EVENT_NAME" == "workflow_dispatch" ]; then
|
||||||
|
ENV="$INPUT_ENV"
|
||||||
|
if [[ "$REF_NAME" == dev_* ]]; then
|
||||||
|
MODULE=${REF_NAME#dev_}
|
||||||
|
elif [[ "$REF_NAME" == preprod_* ]]; then
|
||||||
|
MODULE=${REF_NAME#preprod_}
|
||||||
|
elif [[ "$REF_NAME" == master_* ]]; then
|
||||||
|
MODULE=${REF_NAME#master_}
|
||||||
|
else
|
||||||
|
# Fallback assuming valid module name in branch suffix
|
||||||
|
MODULE=${REF_NAME#*_}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ODOO 18 PORT CONFIGURATION
|
||||||
|
if [ "$ENV" == "dev" ]; then
|
||||||
|
PORT="18000"
|
||||||
|
elif [ "$ENV" == "preprod" ]; then
|
||||||
|
PORT="18010"
|
||||||
|
elif [ "$ENV" == "prod" ]; then
|
||||||
|
PORT="18069"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ENV=$ENV" >> $GITHUB_OUTPUT
|
||||||
|
echo "MODULE=$MODULE" >> $GITHUB_OUTPUT
|
||||||
|
echo "PORT=$PORT" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Deploy to Hydra Server (SSH)
|
||||||
|
if: steps.context.outputs.ENV != ''
|
||||||
|
uses: appleboy/ssh-action@v1.0.0
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HYDRA_HOST }}
|
||||||
|
username: ${{ secrets.HYDRA_USER }}
|
||||||
|
key: ${{ secrets.HYDRA_SSH_KEY }}
|
||||||
|
port: 22
|
||||||
|
script: |
|
||||||
|
MODULE="${{ steps.context.outputs.MODULE }}"
|
||||||
|
ENV="${{ steps.context.outputs.ENV }}"
|
||||||
|
BRANCH="${{ github.ref_name }}"
|
||||||
|
FORCE_RESTART="${{ inputs.force_restart }}"
|
||||||
|
|
||||||
|
echo "🚀 Deploying (Odoo 18) $MODULE to $ENV Environment..."
|
||||||
|
|
||||||
|
if [ "$ENV" == "dev" ]; then
|
||||||
|
TARGET_ROOT="/root/odoo-infra/odoo18/addons/custom_modules"
|
||||||
|
SERVICE="odoo-18"
|
||||||
|
else
|
||||||
|
echo "🚧 Environment '$ENV' folder structure is not yet created on the server for Odoo 18. Deployment simulated."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_DIR="$TARGET_ROOT/$MODULE"
|
||||||
|
|
||||||
|
# Auto-create directory if it doesn't exist (First run)
|
||||||
|
if [ ! -d "$TARGET_DIR" ]; then
|
||||||
|
echo "✨ Creating new module directory: $TARGET_DIR"
|
||||||
|
mkdir -p "$TARGET_DIR"
|
||||||
|
# Initial clone logic handled by script usually, but here we can just git init if empty
|
||||||
|
# Better to assume the setup script handles it, or handle it here:
|
||||||
|
cd "$TARGET_DIR"
|
||||||
|
git init
|
||||||
|
git remote add origin git@github.com:hydracp9/odex30_standard.git
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$TARGET_DIR"
|
||||||
|
echo "⬇️ Pulling changes from $BRANCH..."
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard origin/$BRANCH
|
||||||
|
|
||||||
|
if [ "$FORCE_RESTART" == "true" ] || [ "${{ github.event_name }}" == "push" ]; then
|
||||||
|
echo "🔄 Restarting Service ($SERVICE)..."
|
||||||
|
cd /root/odoo-infra
|
||||||
|
docker compose restart $SERVICE
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Deployment Successful."
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
name: Prevent Invalid Merges
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize, edited]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-merge-flow:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Validate Branch Flow
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const base = context.payload.pull_request.base.ref;
|
||||||
|
const head = context.payload.pull_request.head.ref;
|
||||||
|
|
||||||
|
core.info(`Checking Merge Flow: ${head} -> ${base}`);
|
||||||
|
|
||||||
|
// 1. Parse module name from base branch
|
||||||
|
// Expected formats: dev_X, preprod_X, master_X
|
||||||
|
const tiers = ["dev", "preprod", "master"];
|
||||||
|
|
||||||
|
function parseBranch(branchName) {
|
||||||
|
for (const tier of tiers) {
|
||||||
|
if (branchName.startsWith(tier + "_")) {
|
||||||
|
return { tier: tier, module: branchName.substring(tier.length + 1) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // Not a standard environment branch (maybe feature/fix)
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseInfo = parseBranch(base);
|
||||||
|
const headInfo = parseBranch(head);
|
||||||
|
|
||||||
|
// If base is not a protected tier (dev/preprod/master), allow merge (feature -> feature)
|
||||||
|
if (!baseInfo) {
|
||||||
|
core.info("Base branch is not a protected environment tier. Merge allowed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logic for Protected Base Branches
|
||||||
|
|
||||||
|
// ❌ Rule: Cannot merge directly into master from anywhere except preprod (of same module)
|
||||||
|
if (baseInfo.tier === "master") {
|
||||||
|
if (!headInfo || headInfo.tier !== "preprod" || headInfo.module !== baseInfo.module) {
|
||||||
|
core.setFailed(`❌ Forbidden: You can ONLY merge into 'master_${baseInfo.module}' from 'preprod_${baseInfo.module}'. Detected: ${head}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ Rule: Cannot merge directly into preprod from anywhere except dev (of same module)
|
||||||
|
if (baseInfo.tier === "preprod") {
|
||||||
|
if (!headInfo || headInfo.tier !== "dev" || headInfo.module !== baseInfo.module) {
|
||||||
|
core.setFailed(`❌ Forbidden: You can ONLY merge into 'preprod_${baseInfo.module}' from 'dev_${baseInfo.module}'. Detected: ${head}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ Rule: Cannot merge directly into dev from master or preprod (reverse flow)
|
||||||
|
// (Optional: You might allow hotfixes, but strictly strictly dev<-feature is best)
|
||||||
|
if (baseInfo.tier === "dev") {
|
||||||
|
// Allow feature branches to merge into dev
|
||||||
|
// Block upstream branches
|
||||||
|
if (headInfo && (headInfo.tier === "master" || headInfo.tier === "preprod")) {
|
||||||
|
core.setFailed(`❌ Forbidden: Cannot merge upstream (${head}) back into dev.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info("✅ Merge flow validation passed.");
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
name: Pull Code
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev_odex_base
|
|
||||||
- dev_odex_hr
|
|
||||||
- dev_odex30_accounting
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
environment:
|
|
||||||
description: 'Select Server'
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- dev
|
|
||||||
default: dev
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
deploy_dev_server:
|
|
||||||
name: Deploy to dev server <159.89.22.77>
|
|
||||||
runs-on: odex30-runner
|
|
||||||
if: |
|
|
||||||
(github.ref == 'refs/heads/dev_odex_base' || github.ref == 'refs/heads/dev_odex_hr' || github.ref == 'refs/heads/dev_odex30_accounting') &&
|
|
||||||
(github.event_name == 'push' ||
|
|
||||||
(github.event_name == 'workflow_dispatch' && github.event.inputs.environment != ''))
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout And Restart Project
|
|
||||||
run: |
|
|
||||||
echo "** [INFO] Running on branch --> ${GITHUB_REF#refs/heads/}"
|
|
||||||
sudo chmod +x /home/${{ secrets.CLIENT_USER }}/scripts/pull/pull_code.sh
|
|
||||||
sudo /home/${{ secrets.CLIENT_USER }}/scripts/pull/pull_code.sh
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
name: Upgrade Module
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
database_name:
|
|
||||||
description: 'Database Name'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
module_name:
|
|
||||||
description: 'Module Name'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
environment:
|
|
||||||
description: 'Select Server'
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- dev
|
|
||||||
default: dev
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
upgrade_master:
|
|
||||||
name: Upgrade Dev server
|
|
||||||
runs-on: odex30-runner
|
|
||||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'dev'
|
|
||||||
steps:
|
|
||||||
- name: Upgrade Module
|
|
||||||
env:
|
|
||||||
DATABASE_NAME: ${{ github.event.inputs.database_name }}
|
|
||||||
MODULE_NAME: ${{ github.event.inputs.module_name }}
|
|
||||||
run: |
|
|
||||||
chmod +x /home/${{ secrets.CLIENT_USER }}/scripts/upgrade/upgrade-module.sh
|
|
||||||
/home/${{ secrets.CLIENT_USER }}/scripts/upgrade/upgrade-module.sh "$DATABASE_NAME" "$MODULE_NAME"
|
|
||||||
Loading…
Reference in New Issue