update_studio_docs #25
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: Update ABP Studio Docs | |
| on: | |
| repository_dispatch: | |
| types: [update_studio_docs] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Studio version (e.g., 2.1.10)' | |
| required: true | |
| name: | |
| description: 'Release name' | |
| required: true | |
| notes: | |
| description: 'Raw release notes' | |
| required: true | |
| url: | |
| description: 'Release URL' | |
| required: true | |
| target_branch: | |
| description: 'Target branch (leave empty to auto-detect from latest stable ABP release)' | |
| required: false | |
| default: '' | |
| jobs: | |
| update-docs: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| models: read | |
| steps: | |
| # ------------------------------------------------- | |
| # Extract payload (repository_dispatch or workflow_dispatch) | |
| # ------------------------------------------------- | |
| - name: Extract payload | |
| id: payload | |
| run: | | |
| if [ "${{ github.event_name }}" = "repository_dispatch" ]; then | |
| echo "version=${{ github.event.client_payload.version }}" >> $GITHUB_OUTPUT | |
| echo "name=${{ github.event.client_payload.name }}" >> $GITHUB_OUTPUT | |
| echo "url=${{ github.event.client_payload.url }}" >> $GITHUB_OUTPUT | |
| echo "target_branch=${{ github.event.client_payload.target_branch }}" >> $GITHUB_OUTPUT | |
| # Save notes to environment variable (multiline) | |
| { | |
| echo "RAW_NOTES<<NOTES_DELIMITER_EOF" | |
| jq -r '.client_payload.notes' "$GITHUB_EVENT_PATH" | |
| echo "NOTES_DELIMITER_EOF" | |
| } >> $GITHUB_ENV | |
| else | |
| echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT | |
| echo "name=${{ github.event.inputs.name }}" >> $GITHUB_OUTPUT | |
| echo "url=${{ github.event.inputs.url }}" >> $GITHUB_OUTPUT | |
| echo "target_branch=${{ github.event.inputs.target_branch }}" >> $GITHUB_OUTPUT | |
| # Save notes to environment variable (multiline) | |
| { | |
| echo "RAW_NOTES<<NOTES_DELIMITER_EOF" | |
| echo "${{ github.event.inputs.notes }}" | |
| echo "NOTES_DELIMITER_EOF" | |
| } >> $GITHUB_ENV | |
| fi | |
| # ------------------------------------------------- | |
| # Resolve target branch (auto-detect from latest stable ABP if not provided) | |
| # ------------------------------------------------- | |
| - name: Resolve target branch | |
| id: resolve_branch | |
| run: | | |
| TARGET_BRANCH="${{ steps.payload.outputs.target_branch }}" | |
| if [ -z "$TARGET_BRANCH" ]; then | |
| echo "🔍 No target_branch provided - fetching latest stable ABP release..." | |
| RELEASES=$(curl -fsS \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| "https://api.github.com/repos/abpframework/abp/releases?per_page=20") | |
| ABP_VERSION=$(echo "$RELEASES" | jq -r ' | |
| [.[] | select( | |
| (.prerelease == false) and | |
| (.tag_name | test("preview|rc|beta|dev"; "i") | not) | |
| )] | first | .tag_name | |
| ') | |
| if [ -z "$ABP_VERSION" ] || [ "$ABP_VERSION" = "null" ]; then | |
| echo "❌ Could not determine latest stable ABP version" | |
| exit 1 | |
| fi | |
| # Derive rel-X.Y from X.Y.Z (e.g., 10.1.1 -> rel-10.1) | |
| TARGET_BRANCH=$(echo "$ABP_VERSION" | grep -oE '^[0-9]+\.[0-9]+' | sed 's/^/rel-/') | |
| if [ -z "$TARGET_BRANCH" ]; then | |
| echo "❌ Could not derive target branch from version: $ABP_VERSION" | |
| exit 1 | |
| fi | |
| echo "✅ Auto-detected target branch: $TARGET_BRANCH (from ABP $ABP_VERSION)" | |
| else | |
| echo "✅ Using provided target branch: $TARGET_BRANCH" | |
| fi | |
| echo "target_branch=$TARGET_BRANCH" >> $GITHUB_OUTPUT | |
| - name: Validate payload | |
| env: | |
| VERSION: ${{ steps.payload.outputs.version }} | |
| NAME: ${{ steps.payload.outputs.name }} | |
| URL: ${{ steps.payload.outputs.url }} | |
| TARGET_BRANCH: ${{ steps.resolve_branch.outputs.target_branch }} | |
| run: | | |
| if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then | |
| echo "❌ Missing: version" | |
| exit 1 | |
| fi | |
| if [ -z "$NAME" ] || [ "$NAME" = "null" ]; then | |
| echo "❌ Missing: name" | |
| exit 1 | |
| fi | |
| if [ -z "$URL" ] || [ "$URL" = "null" ]; then | |
| echo "❌ Missing: url" | |
| exit 1 | |
| fi | |
| if [ -z "$RAW_NOTES" ]; then | |
| echo "❌ Missing: release notes" | |
| exit 1 | |
| fi | |
| echo "✅ Payload validated" | |
| echo " Version: $VERSION" | |
| echo " Name: $NAME" | |
| echo " Target Branch: $TARGET_BRANCH" | |
| # ------------------------------------------------- | |
| # Checkout target branch | |
| # ------------------------------------------------- | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.resolve_branch.outputs.target_branch }} | |
| fetch-depth: 0 | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # ------------------------------------------------- | |
| # Create working branch | |
| # ------------------------------------------------- | |
| - name: Create branch | |
| env: | |
| VERSION: ${{ steps.payload.outputs.version }} | |
| run: | | |
| BRANCH="docs/studio-${VERSION}" | |
| # Delete remote branch if exists (idempotent) | |
| git push origin --delete "$BRANCH" 2>/dev/null || true | |
| git checkout -B "$BRANCH" | |
| echo "BRANCH=$BRANCH" >> $GITHUB_ENV | |
| # ------------------------------------------------- | |
| # Analyze existing release notes format | |
| # ------------------------------------------------- | |
| - name: Analyze existing format | |
| id: analyze | |
| run: | | |
| FILE="docs/en/studio/release-notes.md" | |
| if [ -f "$FILE" ] && [ -s "$FILE" ]; then | |
| { | |
| echo "EXISTING_FORMAT<<DELIMITER_EOF" | |
| head -50 "$FILE" | sed 's/DELIMITER_EOF/DELIMITER_E0F/g' | |
| echo "DELIMITER_EOF" | |
| } >> $GITHUB_OUTPUT | |
| else | |
| { | |
| echo "EXISTING_FORMAT<<DELIMITER_EOF" | |
| echo "# ABP Studio Release Notes" | |
| echo "" | |
| echo "## 2.1.0 (2025-12-08) Latest" | |
| echo "- Enhanced Module Installation UI" | |
| echo "- Added AI Management option" | |
| echo "DELIMITER_EOF" | |
| } >> $GITHUB_OUTPUT | |
| fi | |
| # ------------------------------------------------- | |
| # Try AI formatting (OPTIONAL - never fails workflow) | |
| # ------------------------------------------------- | |
| - name: Format release notes with AI | |
| id: ai | |
| continue-on-error: true | |
| uses: actions/ai-inference@v1 | |
| with: | |
| model: openai/gpt-4.1 | |
| prompt: | | |
| You are a technical writer for ABP Studio release notes. | |
| Existing release notes format: | |
| ${{ steps.analyze.outputs.EXISTING_FORMAT }} | |
| New release: | |
| Version: ${{ steps.payload.outputs.version }} | |
| Name: ${{ steps.payload.outputs.name }} | |
| Raw notes: | |
| ${{ env.RAW_NOTES }} | |
| CRITICAL RULES: | |
| 1. Extract ONLY essential, user-facing changes | |
| 2. Format as bullet points starting with "- " | |
| 3. Keep it concise and professional | |
| 4. Match the style of existing release notes | |
| 5. Skip internal/technical details unless critical | |
| 6. Return ONLY the bullet points (no version header, no date) | |
| 7. One change per line | |
| Output example: | |
| - Fixed books sample for blazor-webapp tiered solution | |
| - Enhanced Module Installation UI | |
| - Added AI Management option to Startup Templates | |
| Return ONLY the formatted bullet points. | |
| # ------------------------------------------------- | |
| # Fallback: Use raw notes if AI unavailable | |
| # ------------------------------------------------- | |
| - name: Prepare final release notes | |
| run: | | |
| mkdir -p .tmp | |
| AI_RESPONSE="${{ steps.ai.outputs.response }}" | |
| if [ -n "$AI_RESPONSE" ] && [ "$AI_RESPONSE" != "null" ]; then | |
| echo "✅ Using AI-formatted release notes" | |
| echo "$AI_RESPONSE" > .tmp/final-notes.txt | |
| else | |
| echo "⚠️ AI unavailable - using aggressive cleaning on raw release notes" | |
| # Clean and format raw notes with aggressive filtering | |
| echo "$RAW_NOTES" | while IFS= read -r line; do | |
| # Skip empty lines | |
| [ -z "$line" ] && continue | |
| # Skip section headers | |
| [[ "$line" =~ ^#+.*What.*Changed ]] && continue | |
| [[ "$line" =~ ^##[[:space:]] ]] && continue | |
| # Skip full changelog links | |
| [[ "$line" =~ ^\*\*Full\ Changelog ]] && continue | |
| [[ "$line" =~ ^Full\ Changelog ]] && continue | |
| # Remove leading bullet/asterisk | |
| line=$(echo "$line" | sed 's/^[[:space:]]*[*-][[:space:]]*//') | |
| # Aggressive cleaning: remove entire " by @user in https://..." suffix | |
| line=$(echo "$line" | sed 's/[[:space:]]*by @[a-zA-Z0-9_-]*[[:space:]]*in https:\/\/github\.com\/[^[:space:]]*//g') | |
| # Remove remaining "by @username" or "by username" | |
| line=$(echo "$line" | sed 's/[[:space:]]*by @[a-zA-Z0-9_-]*[[:space:]]*$//g') | |
| line=$(echo "$line" | sed 's/[[:space:]]*by [a-zA-Z0-9_-]*[[:space:]]*$//g') | |
| # Remove standalone @mentions | |
| line=$(echo "$line" | sed 's/@[a-zA-Z0-9_-]*//g') | |
| # Clean trailing periods if orphaned | |
| line=$(echo "$line" | sed 's/\.[[:space:]]*$//') | |
| # Trim all whitespace | |
| line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') | |
| # Skip if line is empty or too short | |
| [ -z "$line" ] && continue | |
| [ ${#line} -lt 5 ] && continue | |
| # Capitalize first letter if lowercase | |
| line="$(echo ${line:0:1} | tr '[:lower:]' '[:upper:]')${line:1}" | |
| # Add clean bullet and output | |
| echo "- $line" | |
| done > .tmp/final-notes.txt | |
| fi | |
| # Safety check: verify we have content | |
| if [ ! -s .tmp/final-notes.txt ]; then | |
| echo "⚠️ No valid release notes extracted, using minimal fallback" | |
| echo "- Release ${{ steps.payload.outputs.version }}" > .tmp/final-notes.txt | |
| fi | |
| echo "=== Final release notes ===" | |
| cat .tmp/final-notes.txt | |
| echo "===========================" | |
| # ------------------------------------------------- | |
| # Update release-notes.md (move "Latest" tag correctly) | |
| # ------------------------------------------------- | |
| - name: Update release-notes.md | |
| env: | |
| VERSION: ${{ steps.payload.outputs.version }} | |
| NAME: ${{ steps.payload.outputs.name }} | |
| URL: ${{ steps.payload.outputs.url }} | |
| run: | | |
| FILE="docs/en/studio/release-notes.md" | |
| DATE="$(date +%Y-%m-%d)" | |
| mkdir -p docs/en/studio | |
| # Check if version already exists (idempotent) | |
| if [ -f "$FILE" ] && grep -q "^## $VERSION " "$FILE"; then | |
| echo "⚠️ Version $VERSION already exists in release notes - skipping update" | |
| echo "VERSION_UPDATED=false" >> $GITHUB_ENV | |
| exit 0 | |
| fi | |
| # Read final notes | |
| NOTES_CONTENT="$(cat .tmp/final-notes.txt)" | |
| # Create new entry | |
| NEW_ENTRY="## $VERSION ($DATE) Latest | |
| $NOTES_CONTENT | |
| " | |
| # Process file | |
| if [ ! -f "$FILE" ]; then | |
| # Create new file | |
| cat > "$FILE" <<EOF | |
| # ABP Studio Release Notes | |
| $NEW_ENTRY | |
| EOF | |
| else | |
| # Remove "Latest" tag from existing entries and insert new one | |
| awk -v new_entry="$NEW_ENTRY" ' | |
| BEGIN { inserted = 0 } | |
| # Remove "Latest" from existing entries | |
| /^## [0-9]/ { | |
| gsub(/ Latest$/, "", $0) | |
| } | |
| # Insert after first "## " (version heading) or after title | |
| /^## / && !inserted { | |
| print new_entry | |
| inserted = 1 | |
| } | |
| # Print current line | |
| { print } | |
| # If we reach end without inserting, add at end | |
| END { | |
| if (!inserted) { | |
| print "" | |
| print new_entry | |
| } | |
| } | |
| ' "$FILE" > "$FILE.new" | |
| mv "$FILE.new" "$FILE" | |
| fi | |
| echo "VERSION_UPDATED=true" >> $GITHUB_ENV | |
| echo "=== Updated release-notes.md preview ===" | |
| head -30 "$FILE" | |
| echo "========================================" | |
| # ------------------------------------------------- | |
| # Fetch latest stable ABP version (no preview/rc/beta) | |
| # ------------------------------------------------- | |
| - name: Fetch latest stable ABP version | |
| id: abp | |
| run: | | |
| # Fetch all releases | |
| RELEASES=$(curl -fsS \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| "https://api.github.com/repos/abpframework/abp/releases?per_page=20") | |
| # Filter stable releases (exclude preview, rc, beta, dev) | |
| ABP_VERSION=$(echo "$RELEASES" | jq -r ' | |
| [.[] | select( | |
| (.prerelease == false) and | |
| (.tag_name | test("preview|rc|beta|dev"; "i") | not) | |
| )] | first | .tag_name | |
| ') | |
| if [ -z "$ABP_VERSION" ] || [ "$ABP_VERSION" = "null" ]; then | |
| echo "❌ Could not determine latest stable ABP version" | |
| exit 1 | |
| fi | |
| echo "✅ Latest stable ABP version: $ABP_VERSION" | |
| echo "ABP_VERSION=$ABP_VERSION" >> $GITHUB_ENV | |
| # ------------------------------------------------- | |
| # Update version-mapping.md (smart range expansion) | |
| # ------------------------------------------------- | |
| - name: Update version-mapping.md | |
| env: | |
| STUDIO_VERSION: ${{ steps.payload.outputs.version }} | |
| run: | | |
| FILE="docs/en/studio/version-mapping.md" | |
| ABP_VERSION="${{ env.ABP_VERSION }}" | |
| mkdir -p docs/en/studio | |
| # Create file if doesn't exist | |
| if [ ! -f "$FILE" ]; then | |
| cat > "$FILE" <<EOF | |
| # ABP Studio and ABP Startup Template Version Mappings | |
| | **ABP Studio Version** | **ABP Version of Startup Template** | | |
| |------------------------|-------------------------------------| | |
| | $STUDIO_VERSION | $ABP_VERSION | | |
| EOF | |
| echo "MAPPING_UPDATED=true" >> $GITHUB_ENV | |
| exit 0 | |
| fi | |
| # Use Python for smart version range handling | |
| python3 <<'PYTHON_EOF' | |
| import os | |
| import re | |
| from packaging.version import Version, InvalidVersion | |
| studio_ver = os.environ["STUDIO_VERSION"] | |
| abp_ver = os.environ["ABP_VERSION"] | |
| file_path = "docs/en/studio/version-mapping.md" | |
| try: | |
| studio = Version(studio_ver) | |
| except InvalidVersion: | |
| print(f"❌ Invalid Studio version: {studio_ver}") | |
| exit(1) | |
| with open(file_path, 'r') as f: | |
| lines = f.readlines() | |
| # Find table start (skip SEO and headers) | |
| table_start = 0 | |
| table_end = 0 | |
| for i, line in enumerate(lines): | |
| if line.strip().startswith('|') and '**ABP Studio Version**' in line: | |
| table_start = i | |
| elif table_start > 0 and line.strip() and not line.strip().startswith('|'): | |
| table_end = i | |
| break | |
| if table_start == 0: | |
| print("❌ Could not find version mapping table") | |
| exit(1) | |
| # If no end found, table goes to end of file | |
| if table_end == 0: | |
| table_end = len(lines) | |
| # Extract sections | |
| before_table = lines[:table_start] # Everything before table | |
| table_header = lines[table_start:table_start+2] # Header + separator | |
| data_rows = [l for l in lines[table_start+2:table_end] if l.strip().startswith('|')] # Data rows | |
| after_table = lines[table_end:] # Everything after table | |
| new_rows = [] | |
| handled = False | |
| def parse_version_range(version_str): | |
| """Parse '2.1.5 - 2.1.9' or '2.1.5' into (start, end)""" | |
| version_str = version_str.strip() | |
| if '–' in version_str or '-' in version_str: | |
| # Handle both em-dash and hyphen | |
| parts = re.split(r'\s*[–-]\s*', version_str) | |
| if len(parts) == 2: | |
| try: | |
| return Version(parts[0].strip()), Version(parts[1].strip()) | |
| except InvalidVersion: | |
| return None, None | |
| try: | |
| v = Version(version_str) | |
| return v, v | |
| except InvalidVersion: | |
| return None, None | |
| def format_row(studio_range, abp_version): | |
| """Format a table row with proper spacing""" | |
| return f"| {studio_range:<22} | {abp_version:<27} |\n" | |
| # Process existing rows | |
| for row in data_rows: | |
| match = re.match(r'\|\s*(.+?)\s*\|\s*(.+?)\s*\|', row) | |
| if not match: | |
| continue | |
| existing_studio_range = match.group(1).strip() | |
| existing_abp = match.group(2).strip() | |
| # Only consider rows with matching ABP version | |
| if existing_abp != abp_ver: | |
| new_rows.append(row) | |
| continue | |
| start_ver, end_ver = parse_version_range(existing_studio_range) | |
| if start_ver is None or end_ver is None: | |
| new_rows.append(row) | |
| continue | |
| # Check if current studio version is in this range | |
| if start_ver <= studio <= end_ver: | |
| print(f"✅ Studio version {studio_ver} already covered in range {existing_studio_range}") | |
| handled = True | |
| new_rows.append(row) | |
| # Check if we should extend the range | |
| elif end_ver < studio: | |
| # Calculate if studio is the next logical version | |
| # For patch versions: 2.1.9 -> 2.1.10 | |
| # For minor versions: 2.1.9 -> 2.2.0 | |
| # Simple heuristic: if major.minor match and patch increments, extend range | |
| if (start_ver.major == studio.major and | |
| start_ver.minor == studio.minor and | |
| studio.micro <= end_ver.micro + 5): # Allow small gaps | |
| new_range = f"{start_ver} - {studio}" | |
| new_rows.append(format_row(new_range, abp_ver)) | |
| print(f"✅ Extended range: {new_range}") | |
| handled = True | |
| else: | |
| new_rows.append(row) | |
| else: | |
| new_rows.append(row) | |
| # If not handled, add new row at top of data | |
| if not handled: | |
| new_row = format_row(str(studio), abp_ver) | |
| new_rows.insert(0, new_row) | |
| print(f"✅ Added new mapping: {studio_ver} -> {abp_ver}") | |
| # Write updated file - preserve ALL content | |
| with open(file_path, 'w') as f: | |
| f.writelines(before_table) # SEO, title, intro text | |
| f.writelines(table_header) # Table header | |
| f.writelines(new_rows) # Updated data rows | |
| f.writelines(after_table) # Content after table (preview section, etc.) | |
| print("MAPPING_UPDATED=true") | |
| PYTHON_EOF | |
| echo "MAPPING_UPDATED=true" >> $GITHUB_ENV | |
| echo "=== Updated version-mapping.md preview ===" | |
| head -35 "$FILE" | |
| echo "==========================================" | |
| # ------------------------------------------------- | |
| # Check for changes | |
| # ------------------------------------------------- | |
| - name: Check for changes | |
| id: changes | |
| run: | | |
| git add docs/en/studio/ | |
| if git diff --cached --quiet; then | |
| echo "has_changes=false" >> $GITHUB_OUTPUT | |
| echo "⚠️ No changes detected" | |
| else | |
| echo "has_changes=true" >> $GITHUB_OUTPUT | |
| echo "✅ Changes detected:" | |
| git diff --cached --stat | |
| fi | |
| # ------------------------------------------------- | |
| # Commit & push | |
| # ------------------------------------------------- | |
| - name: Commit and push | |
| if: steps.changes.outputs.has_changes == 'true' | |
| env: | |
| VERSION: ${{ steps.payload.outputs.version }} | |
| NAME: ${{ steps.payload.outputs.name }} | |
| run: | | |
| git commit -m "docs(studio): update documentation for release $VERSION | |
| - Updated release notes for $VERSION | |
| - Updated version mapping with ABP ${{ env.ABP_VERSION }} | |
| Release: $NAME" | |
| git push -f origin "$BRANCH" | |
| # ------------------------------------------------- | |
| # Create or update PR | |
| # ------------------------------------------------- | |
| - name: Create or update PR | |
| if: steps.changes.outputs.has_changes == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ steps.payload.outputs.version }} | |
| NAME: ${{ steps.payload.outputs.name }} | |
| URL: ${{ steps.payload.outputs.url }} | |
| TARGET_BRANCH: ${{ steps.resolve_branch.outputs.target_branch }} | |
| run: | | |
| # Check for existing PR | |
| EXISTING_PR=$(gh pr list \ | |
| --head "$BRANCH" \ | |
| --base "$TARGET_BRANCH" \ | |
| --json number \ | |
| --jq '.[0].number' 2>/dev/null || echo "") | |
| PR_BODY="Automated documentation update for ABP Studio release **$VERSION**. | |
| ## Release Information | |
| - **Version**: $VERSION | |
| - **Name**: $NAME | |
| - **Release**: [View on GitHub]($URL) | |
| - **ABP Framework Version**: ${{ env.ABP_VERSION }} | |
| ## Changes | |
| - ✅ Updated [release-notes.md](docs/en/studio/release-notes.md) | |
| - ✅ Updated [version-mapping.md](docs/en/studio/version-mapping.md) | |
| --- | |
| *This PR was automatically generated by the [update-studio-docs workflow](.github/workflows/update-studio-docs.yml)*" | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "🔄 Updating existing PR #$EXISTING_PR" | |
| gh pr edit "$EXISTING_PR" \ | |
| --title "docs(studio): release $VERSION - $NAME" \ | |
| --body "$PR_BODY" \ | |
| --add-reviewer skoc10 | |
| echo "PR_NUMBER=$EXISTING_PR" >> $GITHUB_ENV | |
| else | |
| echo "📝 Creating new PR" | |
| sleep 2 # Wait for GitHub to sync | |
| PR_URL=$(gh pr create \ | |
| --title "docs(studio): release $VERSION - $NAME" \ | |
| --body "$PR_BODY" \ | |
| --base "$TARGET_BRANCH" \ | |
| --head "$BRANCH" \ | |
| --reviewer skoc10) | |
| PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') | |
| echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV | |
| echo "✅ Created PR #$PR_NUMBER: $PR_URL" | |
| fi | |
| # ------------------------------------------------- | |
| # Enable auto-merge (safe with branch protection) | |
| # ------------------------------------------------- | |
| - name: Enable auto-merge | |
| if: steps.changes.outputs.has_changes == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| run: | | |
| echo "🔄 Attempting to enable auto-merge for PR #$PR_NUMBER" | |
| gh pr merge "$PR_NUMBER" \ | |
| --auto \ | |
| --squash \ | |
| --delete-branch || { | |
| echo "⚠️ Auto-merge not available (branch protection or permissions)" | |
| echo " PR #$PR_NUMBER is ready for manual review" | |
| } | |
| # ------------------------------------------------- | |
| # Summary | |
| # ------------------------------------------------- | |
| - name: Workflow summary | |
| if: always() | |
| env: | |
| VERSION: ${{ steps.payload.outputs.version }} | |
| run: | | |
| echo "## 📚 ABP Studio Docs Update Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: $VERSION" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release**: ${{ steps.payload.outputs.name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Target Branch**: ${{ steps.resolve_branch.outputs.target_branch }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ steps.changes.outputs.has_changes }}" = "true" ]; then | |
| echo "### ✅ Changes Applied" >> $GITHUB_STEP_SUMMARY | |
| echo "- Release notes updated: ${{ env.VERSION_UPDATED }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- Version mapping updated: ${{ env.MAPPING_UPDATED }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- ABP Framework version: ${{ env.ABP_VERSION }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- PR: #${{ env.PR_NUMBER }}" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "### ⚠️ No Changes" >> $GITHUB_STEP_SUMMARY | |
| echo "Version $VERSION already exists in documentation." >> $GITHUB_STEP_SUMMARY | |
| fi |