From 61a9e10b172edb81b90f1b1f64deadc8894ce79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phan=20Sainl=C3=A9ger?= Date: Tue, 10 Mar 2026 16:59:45 +0100 Subject: [PATCH] [IMP] manual deployment workflow with dry-run and filters Replace automatic deployment (on push) with manual workflow_dispatch: - Version filter: deploy to all versions or specific one (16.0, 18.0) - Repo filter: deploy to all repos or comma-separated list - Dry-run mode: preview changes without creating PRs - Detailed summary with emoji indicators and statistics Benefits: - Full control over deployment scope and timing - Safe preview before creating 50+ PRs - Targeted deployments for testing Update README with new deployment guide and examples. --- .gitea/workflows/deploy-config.yml | 223 +++++++++++++++++++++-------- README.md | 67 +++++++-- 2 files changed, 218 insertions(+), 72 deletions(-) diff --git a/.gitea/workflows/deploy-config.yml b/.gitea/workflows/deploy-config.yml index a27e058..1f4fa33 100644 --- a/.gitea/workflows/deploy-config.yml +++ b/.gitea/workflows/deploy-config.yml @@ -1,16 +1,45 @@ -name: Sync Config to All Odoo Repositories -run-name: ${{ gitea.actor }} is deploying new pre-commit config 🚀 +name: Deploy CI Config +run-name: "${{ gitea.actor }} deploying config [${{ inputs.version }}] to [${{ inputs.repos || 'all repos' }}]${{ inputs.dry_run && ' (DRY-RUN)' || '' }}" + on: - push: - branches: - - main + workflow_dispatch: + inputs: + version: + description: 'Odoo version to deploy' + required: true + type: choice + options: + - all + - '16.0' + - '18.0' + default: 'all' + repos: + description: 'Target repos (comma-separated, empty = all *-addons/*-tools)' + required: false + type: string + default: '' + dry_run: + description: 'Dry run (preview changes without creating PRs)' + required: true + type: boolean + default: true jobs: - sync: + deploy: runs-on: ubuntu-latest steps: + - name: Show deployment parameters + run: | + echo "============================================" + echo " DEPLOYMENT PARAMETERS" + echo "============================================" + echo "Version: ${{ inputs.version }}" + echo "Repos: ${{ inputs.repos || '(all)' }}" + echo "Dry-run: ${{ inputs.dry_run }}" + echo "============================================" + - name: Install dependencies run: | sudo apt-get update @@ -24,112 +53,182 @@ jobs: run: | git clone --single-branch --branch main "${GITEA_SERVER}/${ORG_NAME}/${CONFIG_REPO}.git" config-repo - - name: Detect available Odoo versions - id: versions + - name: Determine versions to deploy run: | - # List directories in config/ that are not "common" (these are version directories) - VERSIONS=$(ls -d config-repo/config/*/ | xargs -n1 basename | grep -v common | tr '\n' ' ') - echo "Available versions: $VERSIONS" + # List all available versions + ALL_VERSIONS=$(ls -d config-repo/config/*/ | xargs -n1 basename | grep -v common | tr '\n' ' ') + echo "Available versions: $ALL_VERSIONS" + + # Filter based on input + if [ "${{ inputs.version }}" = "all" ]; then + VERSIONS="$ALL_VERSIONS" + else + VERSIONS="${{ inputs.version }}" + fi + + echo "Versions to deploy: $VERSIONS" echo "VERSIONS=$VERSIONS" >> $GITEA_ENV - - name: Get list of all repos in organization + - name: Build target repos list env: GITEA_SERVER: "https://git.elabore.coop" ORG_NAME: "Elabore" GITEA_TOKEN: ${{ secrets.ELABORE_BOT_TOKEN }} + INPUT_REPOS: ${{ inputs.repos }} run: | - page=1 - per_page=50 REPO_LIST="repos.txt" > $REPO_LIST - while true; do - echo "Fetching page $page" - response=$(curl -s -H "Authorization: token $GITEA_TOKEN" \ - "${GITEA_SERVER}/api/v1/orgs/${ORG_NAME}/repos?page=${page}&limit=${per_page}") - count=$(echo "$response" | jq 'length') - if [ "$count" -eq 0 ]; then - break - fi - echo "$response" | jq -r '.[].name' >> $REPO_LIST - page=$((page + 1)) - done - echo "Repositories found:" - cat $REPO_LIST - - name: Sync config to each repo + if [ -n "$INPUT_REPOS" ]; then + # User specified repos - use them directly + echo "Using user-specified repos: $INPUT_REPOS" + echo "$INPUT_REPOS" | tr ',' '\n' | sed 's/^ *//;s/ *$//' > $REPO_LIST + else + # Fetch all repos from organization + page=1 + per_page=50 + while true; do + echo "Fetching page $page" + response=$(curl -s -H "Authorization: token $GITEA_TOKEN" \ + "${GITEA_SERVER}/api/v1/orgs/${ORG_NAME}/repos?page=${page}&limit=${per_page}") + count=$(echo "$response" | jq 'length') + if [ "$count" -eq 0 ]; then + break + fi + # Filter for *-addons and *-tools repos only + echo "$response" | jq -r '.[].name | select(endswith("-addons") or endswith("-tools"))' >> $REPO_LIST + page=$((page + 1)) + done + fi + + echo "" + echo "Target repositories:" + cat $REPO_LIST + echo "" + echo "Total: $(wc -l < $REPO_LIST) repos" + + - name: Deploy config to repos env: GITEA_SERVER: "git.elabore.coop" ORG_NAME: "Elabore" CONFIG_REPO: "odoo-elabore-ci" GITEA_TOKEN: ${{ secrets.ELABORE_BOT_TOKEN }} VERSIONS: ${{ env.VERSIONS }} + DRY_RUN: ${{ inputs.dry_run }} run: | REPO_LIST="repos.txt" + SUMMARY_FILE="deployment_summary.txt" + > $SUMMARY_FILE + + pr_created=0 + pr_skipped_no_changes=0 + pr_skipped_no_branch=0 + errors=0 + while read repo; do + # Skip empty lines + [ -z "$repo" ] && continue + # Skip the config repo itself if [ "$repo" = "$CONFIG_REPO" ]; then - echo "Skipping config repo: $repo" - continue - fi - - # Skip repos not matching suffixes -addons and -tools - if ! [[ "$repo" == *-addons ]] && ! [[ "$repo" == *-tools ]]; then - echo "Skipping $repo (does not end with -addons or -tools)" + echo "⏭️ Skipping config repo: $repo" continue fi + echo "" echo "==========================================" - echo "Processing repo: $repo" + echo "📦 Processing: $repo" echo "==========================================" - # Try each Odoo version for VERSION in $VERSIONS; do - echo "--- Trying version $VERSION for $repo ---" + echo "" + echo "--- Version $VERSION ---" # Try to clone the target repo at this version branch if ! git clone --quiet --single-branch --branch "$VERSION" "https://elabore_bot:${GITEA_TOKEN}@${GITEA_SERVER}/${ORG_NAME}/${repo}.git" "target-${repo}-${VERSION}" 2>/dev/null; then - echo "Branch $VERSION does not exist in $repo, skipping" + echo "⚠️ Branch $VERSION does not exist in $repo" + pr_skipped_no_branch=$((pr_skipped_no_branch + 1)) continue fi - cd "target-${repo}-${VERSION}" || { echo "Failed to enter target-${repo}-${VERSION}"; exit 1; } + cd "target-${repo}-${VERSION}" || { echo "❌ Failed to enter directory"; errors=$((errors + 1)); continue; } # Copy common files first - echo "Copying common config files..." - rsync -av ../config-repo/config/common/ . + rsync -a ../config-repo/config/common/ . # Copy version-specific files (overwrites common if conflict) - echo "Copying $VERSION-specific config files..." - rsync -av ../config-repo/config/${VERSION}/ . + rsync -a ../config-repo/config/${VERSION}/ . git add -N . - # If there are no changes, skip + # Check for changes if git diff --quiet; then - echo "No changes for $repo on branch $VERSION" + echo "✅ No changes needed for $repo:$VERSION" + pr_skipped_no_changes=$((pr_skipped_no_changes + 1)) else - echo "Changes detected for $repo:$VERSION – committing & pushing" - git config user.name "elabore_bot" - git config user.email "gitea.bot@elabore.coop" - git checkout -b "${VERSION}-config_deployment" - git add . - git commit -m "Sync config from ${CONFIG_REPO} (version ${VERSION})" + echo "📝 Changes detected for $repo:$VERSION" + echo "" + echo "Changed files:" + git diff --stat + echo "" - echo "Pushing to $repo on branch $VERSION" - git push --quiet origin "${VERSION}-config_deployment":refs/for/"${VERSION}" \ - -o topic="${VERSION}-config_deployment" \ - -o title="Sync config from ${CONFIG_REPO} (version ${VERSION})" \ - -o force-push || { echo "Push failed for $repo:$VERSION"; exit 1; } - echo "Push done for $repo:$VERSION" + if [ "$DRY_RUN" = "true" ]; then + echo "🔍 DRY-RUN: Would create PR for $repo:$VERSION" + echo "[DRY-RUN] $repo:$VERSION - PR would be created" >> ../$SUMMARY_FILE + else + echo "🚀 Creating PR for $repo:$VERSION" + git config user.name "elabore_bot" + git config user.email "gitea.bot@elabore.coop" + git checkout -b "${VERSION}-config_deployment" + git add . + git commit -m "Sync config from ${CONFIG_REPO} (version ${VERSION})" + + if git push --quiet origin "${VERSION}-config_deployment":refs/for/"${VERSION}" \ + -o topic="${VERSION}-config_deployment" \ + -o title="Sync config from ${CONFIG_REPO} (version ${VERSION})" \ + -o force-push; then + echo "✅ PR created for $repo:$VERSION" + echo "[CREATED] $repo:$VERSION - PR created" >> ../$SUMMARY_FILE + pr_created=$((pr_created + 1)) + else + echo "❌ Push failed for $repo:$VERSION" + echo "[ERROR] $repo:$VERSION - Push failed" >> ../$SUMMARY_FILE + errors=$((errors + 1)) + fi + fi fi cd .. rm -rf "target-${repo}-${VERSION}" - echo "Cleanup done for $repo:$VERSION" done - echo "Moving to next repo" - echo "" - done < $REPO_LIST + + echo "" + echo "============================================" + echo " DEPLOYMENT SUMMARY" + echo "============================================" + if [ "$DRY_RUN" = "true" ]; then + echo "Mode: DRY-RUN (no PRs created)" + else + echo "Mode: LIVE" + fi + echo "" + echo "PRs created: $pr_created" + echo "Skipped (no changes): $pr_skipped_no_changes" + echo "Skipped (branch missing): $pr_skipped_no_branch" + echo "Errors: $errors" + echo "" + + if [ -s $SUMMARY_FILE ]; then + echo "Details:" + cat $SUMMARY_FILE + fi + + echo "============================================" + + # Exit with error if there were failures + if [ $errors -gt 0 ]; then + exit 1 + fi diff --git a/README.md b/README.md index 07e583b..0256e5f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This repository manages linting and CI configuration centrally for all Odoo repo ``` odoo-elabore-ci/ ├── .gitea/workflows/ -│ └── deploy-config.yml # Automatic deployment workflow +│ └── deploy-config.yml # Manual deployment workflow (with dry-run) └── config/ ├── common/ # Shared files (all versions) │ ├── .editorconfig @@ -43,14 +43,21 @@ odoo-elabore-ci/ ### Deployment Workflow (`deploy-config.yml`) -When a push is made to the `main` branch of this repository: +The deployment is **manually triggered** via Gitea Actions interface, giving you full control over what gets deployed and where. -1. The workflow automatically detects available versions (folders in `config/` other than `common/`) -2. For each `*-addons` or `*-tools` repository in the organization: - - For each configured Odoo version (16.0, 18.0, etc.): - - Attempts to clone the corresponding branch from the target repo - - If it exists: copies `config/common/` then `config/{version}/` - - Creates a Pull Request if changes are detected +**Features:** +- **Version filter**: Deploy to all versions or a specific one (16.0, 18.0) +- **Repo filter**: Deploy to all repos or specific ones (comma-separated) +- **Dry-run mode**: Preview changes without creating any PRs + +**Process:** +1. Detects available versions (folders in `config/` other than `common/`) +2. For each target repository: + - For each selected Odoo version: + - Attempts to clone the corresponding branch + - Copies `config/common/` then `config/{version}/` + - In dry-run: shows what would change + - In live mode: creates a Pull Request if changes detected ### CI Workflow (`pre-commit.yml`) @@ -73,6 +80,44 @@ Deployed to each target repository, this workflow runs on every Pull Request: ## Usage Guide +### Deploying Configuration + +Deployment is done via the Gitea Actions interface: + +1. Go to **Gitea** → `odoo-elabore-ci` → **Actions** +2. Select **"Deploy CI Config"** workflow +3. Click **"Run workflow"** +4. Fill in the parameters: + +| Parameter | Description | Examples | +|-----------|-------------|----------| +| **Version** | Odoo version to deploy | `all`, `16.0`, `18.0` | +| **Repos** | Target repos (empty = all) | `crm-addons, hr-addons` | +| **Dry-run** | Preview without creating PRs | `true` (recommended first) | + +#### Deployment Examples + +| I want to... | Version | Repos | Dry-run | +|--------------|---------|-------|---------| +| Preview all changes | `all` | *(empty)* | ✅ | +| Deploy 16.0 to one repo | `16.0` | `crm-addons` | ❌ | +| Deploy 18.0 to multiple repos | `18.0` | `crm-addons, hr-addons` | ❌ | +| Deploy all versions everywhere | `all` | *(empty)* | ❌ | + +#### Recommended Workflow + +``` +1. Make changes in config/ +2. git commit && git push origin main + → Nothing happens (no auto-deploy) + +3. Run workflow with DRY-RUN enabled + → Review the logs to see what would change + +4. If satisfied, run again WITHOUT dry-run + → PRs are created in target repos +``` + ### Modifying CI Configuration 1. **Edit files in `config/`**: @@ -86,7 +131,7 @@ Deployed to each target repository, this workflow runs on every Pull Request: git push origin main ``` -3. **The workflow automatically creates PRs** in all affected repos +3. **Trigger deployment manually** (see above) ### Adding a New Odoo Version @@ -117,7 +162,9 @@ Deployed to each target repository, this workflow runs on every Pull Request: git push origin main ``` -The workflow will automatically detect the new folder and deploy the configuration to repos with a `19.0` branch. +5. **Deploy** via Gitea Actions: + - The new version will appear in the "Version" dropdown + - Use dry-run first to verify which repos have a `19.0` branch ## Secrets Configuration