org-migration #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: org-migration | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| organization: | |
| description: 'The GitHub Organization name' | |
| required: true | |
| repo_filter: | |
| description: 'Specific repositories to target (comma-separated). Leave empty for ALL.' | |
| required: false | |
| type: string | |
| mode: | |
| description: 'Choose Action Mode' | |
| required: true | |
| default: 'apply' | |
| type: choice | |
| options: | |
| - apply | |
| - revert | |
| dry_run: | |
| description: 'Dry Run (logs only, no push)' | |
| required: true | |
| default: 'false' | |
| type: boolean | |
| jobs: | |
| manage-migration: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Controller Repo | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.9' | |
| - name: Initialize Report | |
| run: | | |
| echo "# Domain Migration Report (${{ inputs.mode }})" > migration_summary.md | |
| echo "**User:** ${{ github.actor }} | **Mode:** ${{ inputs.mode }}" >> migration_summary.md | |
| echo "" >> migration_summary.md | |
| echo "| Repository | Status | Detail |" >> migration_summary.md | |
| echo "| :--- | :--- | :--- |" >> migration_summary.md | |
| - name: Process Repositories | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} | |
| ORG_NAME: ${{ inputs.organization }} | |
| REPO_FILTER: ${{ inputs.repo_filter }} | |
| MODE: ${{ inputs.mode }} | |
| DRY_RUN: ${{ inputs.dry_run }} | |
| run: | | |
| # 1. Fetch all repos (we filter later in the loop) | |
| echo "Fetching repositories for $ORG_NAME..." | |
| repos=$(gh repo list $ORG_NAME --limit 2000 --json name --jq '.[] | .name') | |
| # 2. Define the Python Script (Only needed for Apply mode) | |
| cat << 'EOF' > process_repo.py | |
| import os | |
| import re | |
| import sys | |
| # --- CONFIGURATION --- | |
| OLD_DOMAIN = 'hybrid-cloud-patterns.io' | |
| NEW_DOMAIN = 'validatedpatterns.io' | |
| NEW_TEAM_ALIAS = 'team-validatedpatterns' | |
| IGNORE_MARKER = 'apiVersion: hybrid-cloud-patterns.io' | |
| mailto_pattern = re.compile(r'(mailto:)([a-zA-Z0-9._%+-]+)(@' + re.escape(OLD_DOMAIN) + r')') | |
| files_changed = 0 | |
| extensions_to_check = ['.yaml', '.yml', '.md', '.txt', '.json', '.sh', '.html', '.rst'] | |
| for root, dirs, files in os.walk('.'): | |
| if '.git' in dirs: dirs.remove('.git') | |
| for file in files: | |
| if not any(file.endswith(ext) for ext in extensions_to_check): continue | |
| file_path = os.path.join(root, file) | |
| try: | |
| with open(file_path, 'r', encoding='utf-8') as f: lines = f.readlines() | |
| except: continue | |
| new_lines = [] | |
| file_modified = False | |
| for line in lines: | |
| if IGNORE_MARKER in line: | |
| new_lines.append(line) | |
| continue | |
| original_line = line | |
| if 'mailto:' in line and OLD_DOMAIN in line: | |
| line = mailto_pattern.sub(r'\1' + NEW_TEAM_ALIAS + '@' + NEW_DOMAIN, line) | |
| if OLD_DOMAIN in line: | |
| line = line.replace(OLD_DOMAIN, NEW_DOMAIN) | |
| if line != original_line: | |
| file_modified = True | |
| new_lines.append(line) | |
| if file_modified: | |
| with open(file_path, 'w', encoding='utf-8') as f: f.writelines(new_lines) | |
| files_changed += 1 | |
| sys.exit(0 if files_changed > 0 else 1) | |
| EOF | |
| # 3. Loop through repositories | |
| BRANCH_NAME="migration/update-domain-references" | |
| for NAME in $repos; do | |
| # --- FILTER LOGIC --- | |
| # If repo_filter is set, skip if NAME is not in the list | |
| if [[ ! -z "$REPO_FILTER" ]]; then | |
| if [[ ",$REPO_FILTER," != *",$NAME,"* ]]; then | |
| continue | |
| fi | |
| fi | |
| echo "------------------------------------------------" | |
| echo "Processing: $NAME" | |
| # Clone | |
| git clone "https://x-access-token:${GH_TOKEN}@github.com/$ORG_NAME/$NAME.git" work_dir | |
| cd work_dir | |
| if [ "$MODE" == "revert" ]; then | |
| # --- REVERT MODE --- | |
| echo "Attempting to revert changes in $NAME..." | |
| # Check if PR exists | |
| PR_LIST=$(gh pr list --head $BRANCH_NAME --json number --jq '.[].number') | |
| if [ ! -z "$PR_LIST" ]; then | |
| if [ "$DRY_RUN" = "false" ]; then | |
| for pr_num in $PR_LIST; do | |
| gh pr close $pr_num --delete-branch --comment "Closing via automated cleanup." | |
| done | |
| echo "| $NAME | 🧹 Reverted | Closed PRs and deleted branch |" >> ../migration_summary.md | |
| else | |
| echo "| $NAME | ⚠️ Dry Run | Would close PRs and delete branch |" >> ../migration_summary.md | |
| fi | |
| else | |
| # Attempt to delete branch even if no PR exists | |
| if git ls-remote --exit-code --heads origin $BRANCH_NAME; then | |
| if [ "$DRY_RUN" = "false" ]; then | |
| git push origin --delete $BRANCH_NAME | |
| echo "| $NAME | 🧹 Cleaned | Branch deleted (No PR found) |" >> ../migration_summary.md | |
| else | |
| echo "| $NAME | ⚠️ Dry Run | Would delete orphan branch |" >> ../migration_summary.md | |
| fi | |
| else | |
| echo "| $NAME | 💨 Skipped | No PR or Branch found |" >> ../migration_summary.md | |
| fi | |
| fi | |
| else | |
| # --- APPLY MODE --- | |
| git checkout -b $BRANCH_NAME || git checkout $BRANCH_NAME | |
| # Run Python | |
| python3 ../process_repo.py | |
| CHANGES_MADE=$? | |
| if [ $CHANGES_MADE -eq 0 ]; then | |
| if [ "$DRY_RUN" = "false" ]; then | |
| git config user.name "Migration Bot" | |
| git config user.email "[email protected]" | |
| git add . | |
| git commit -m "refactor: migrate hybrid-cloud-patterns.io to validatedpatterns.io" | |
| git push origin $BRANCH_NAME --force | |
| PR_URL=$(gh pr create --title "Migrate domain references" --body "Automated migration." --head $BRANCH_NAME --base main 2>/dev/null || echo "PR already exists") | |
| echo "| $NAME | ✅ Migrated | PR Created/Updated |" >> ../migration_summary.md | |
| else | |
| echo "| $NAME | ⚠️ Dry Run | Changes detected |" >> ../migration_summary.md | |
| fi | |
| else | |
| echo "| $NAME | 💤 Skipped | No patterns found |" >> ../migration_summary.md | |
| fi | |
| fi | |
| # Cleanup local dir | |
| cd .. | |
| rm -rf work_dir | |
| done | |
| - name: Create Summary Issue | |
| if: always() | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} | |
| run: | | |
| if [ -f migration_summary.md ]; then | |
| gh issue create --repo ${{ github.repository }} --title "Migration Report: ${{ inputs.organization }} ($MODE)" --body-file migration_summary.md | |
| fi |