fix(release): Improve Patch Release Workflow Comments: Clearer Approval Guidance (#21894)

This commit is contained in:
Jerop Kipruto
2026-03-10 13:15:04 -04:00
committed by GitHub
parent 0b78de9601
commit 80cf2fe444
5 changed files with 77 additions and 46 deletions

View File

@@ -120,6 +120,9 @@ jobs:
if (recentRuns.length > 0) { if (recentRuns.length > 0) {
core.setOutput('dispatched_run_urls', recentRuns.map(r => r.html_url).join(',')); core.setOutput('dispatched_run_urls', recentRuns.map(r => r.html_url).join(','));
core.setOutput('dispatched_run_ids', recentRuns.map(r => r.id).join(',')); core.setOutput('dispatched_run_ids', recentRuns.map(r => r.id).join(','));
const markdownLinks = recentRuns.map(r => `- [View dispatched workflow run](${r.html_url})`).join('\n');
core.setOutput('dispatched_run_links', markdownLinks);
} }
- name: 'Comment on Failure' - name: 'Comment on Failure'
@@ -138,16 +141,19 @@ jobs:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}' issue-number: '${{ github.event.issue.number }}'
body: | body: |
**Patch workflow(s) dispatched successfully!** 🚀 **[Step 1/4] Patch workflow(s) waiting for approval!**
**📋 Details:** **📋 Details:**
- **Channels**: `${{ steps.dispatch_patch.outputs.dispatched_channels }}` - **Channels**: `${{ steps.dispatch_patch.outputs.dispatched_channels }}`
- **Commit**: `${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}` - **Commit**: `${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}`
- **Workflows Created**: ${{ steps.dispatch_patch.outputs.dispatched_run_count }} - **Workflows Created**: ${{ steps.dispatch_patch.outputs.dispatched_run_count }}
**⏳ Status:** The patch creation workflow has been triggered and is waiting for deployment approval. Please visit the specific workflow links below and approve the runs.
**🔗 Track Progress:** **🔗 Track Progress:**
- [View patch workflows](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml) ${{ steps.dispatch_patch.outputs.dispatched_run_links }}
- [This workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - [View patch workflow history](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml)
- [This trigger workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
- name: 'Final Status Comment - Dispatch Success (No URL)' - name: 'Final Status Comment - Dispatch Success (No URL)'
if: "always() && startsWith(github.event.comment.body, '/patch') && steps.dispatch_patch.outcome == 'success' && !steps.dispatch_patch.outputs.dispatched_run_urls" if: "always() && startsWith(github.event.comment.body, '/patch') && steps.dispatch_patch.outcome == 'success' && !steps.dispatch_patch.outputs.dispatched_run_urls"
@@ -156,16 +162,18 @@ jobs:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}' issue-number: '${{ github.event.issue.number }}'
body: | body: |
**Patch workflow(s) dispatched successfully!** 🚀 **[Step 1/4] Patch workflow(s) waiting for approval!**
**📋 Details:** **📋 Details:**
- **Channels**: `${{ steps.dispatch_patch.outputs.dispatched_channels }}` - **Channels**: `${{ steps.dispatch_patch.outputs.dispatched_channels }}`
- **Commit**: `${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}` - **Commit**: `${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}`
- **Workflows Created**: ${{ steps.dispatch_patch.outputs.dispatched_run_count }} - **Workflows Created**: ${{ steps.dispatch_patch.outputs.dispatched_run_count }}
**⏳ Status:** The patch creation workflow has been triggered and is waiting for deployment approval. Please visit the workflow history link below and approve the runs.
**🔗 Track Progress:** **🔗 Track Progress:**
- [View patch workflows](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml) - [View patch workflow history](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml)
- [This workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - [This trigger workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
- name: 'Final Status Comment - Failure' - name: 'Final Status Comment - Failure'
if: "always() && startsWith(github.event.comment.body, '/patch') && (steps.dispatch_patch.outcome == 'failure' || steps.dispatch_patch.outcome == 'cancelled')" if: "always() && startsWith(github.event.comment.body, '/patch') && (steps.dispatch_patch.outcome == 'failure' || steps.dispatch_patch.outcome == 'cancelled')"
@@ -174,7 +182,7 @@ jobs:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}' issue-number: '${{ github.event.issue.number }}'
body: | body: |
❌ **Patch workflow dispatch failed!** ❌ **[Step 1/4] Patch workflow dispatch failed!**
There was an error dispatching the patch creation workflow. There was an error dispatching the patch creation workflow.

View File

@@ -128,7 +128,7 @@ async function main() {
let commentBody; let commentBody;
if (success) { if (success) {
commentBody = `✅ **Patch Release Complete!** commentBody = `✅ **[Step 4/4] Patch Release Complete!**
**📦 Release Details:** **📦 Release Details:**
- **Version**: [\`${releaseVersion}\`](https://github.com/${repo.owner}/${repo.repo}/releases/tag/${releaseTag}) - **Version**: [\`${releaseVersion}\`](https://github.com/${repo.owner}/${repo.repo}/releases/tag/${releaseTag})
@@ -144,9 +144,10 @@ async function main() {
**🔗 Links:** **🔗 Links:**
- [GitHub Release](https://github.com/${repo.owner}/${repo.repo}/releases/tag/${releaseTag}) - [GitHub Release](https://github.com/${repo.owner}/${repo.repo}/releases/tag/${releaseTag})
- [Workflow Run](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})`; - [This release workflow run](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})
- [Workflow History](https://github.com/${repo.owner}/${repo.repo}/actions/workflows/release-patch-3-release.yml)`;
} else if (raceConditionFailure) { } else if (raceConditionFailure) {
commentBody = `⚠️ **Patch Release Cancelled - Concurrent Release Detected** commentBody = `⚠️ **[Step 4/4] Patch Release Cancelled - Concurrent Release Detected**
**🚦 What Happened:** **🚦 What Happened:**
Another patch release completed while this one was in progress, causing a version conflict. Another patch release completed while this one was in progress, causing a version conflict.
@@ -163,7 +164,7 @@ Another patch release completed while this one was in progress, causing a versio
- **Next patch should be**: \`${currentReleaseVersion}\` - **Next patch should be**: \`${currentReleaseVersion}\`
- **New release tag**: \`${currentReleaseTag || 'unknown'}\`` - **New release tag**: \`${currentReleaseTag || 'unknown'}\``
: ` : `
- **Status**: Version information updated since this release started` - **Status**: Version information updated since this release was triggered`
} }
**🔄 Next Steps:** **🔄 Next Steps:**
@@ -175,9 +176,10 @@ Another patch release completed while this one was in progress, causing a versio
Multiple patch releases can't run simultaneously. When they do, the second one is automatically cancelled to maintain version consistency. Multiple patch releases can't run simultaneously. When they do, the second one is automatically cancelled to maintain version consistency.
**🔗 Details:** **🔗 Details:**
- [View cancelled workflow run](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})`; - [This release workflow run](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})
- [Workflow History](https://github.com/${repo.owner}/${repo.repo}/actions/workflows/release-patch-3-release.yml)`;
} else { } else {
commentBody = `❌ **Patch Release Failed!** commentBody = `❌ **[Step 4/4] Patch Release Failed!**
**📋 Details:** **📋 Details:**
- **Version**: \`${releaseVersion || 'Unknown'}\` - **Version**: \`${releaseVersion || 'Unknown'}\`
@@ -190,8 +192,9 @@ Multiple patch releases can't run simultaneously. When they do, the second one i
3. You may need to retry the patch once the issue is resolved 3. You may need to retry the patch once the issue is resolved
**🔗 Troubleshooting:** **🔗 Troubleshooting:**
- [View workflow run](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId}) - [This release workflow run](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})
- [View workflow logs](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})`; - [View workflow logs](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})
- [Workflow History](https://github.com/${repo.owner}/${repo.repo}/actions/workflows/release-patch-3-release.yml)`;
} }
if (testMode) { if (testMode) {

View File

@@ -145,7 +145,7 @@ async function main() {
manualCommands = manualCommandsMatch[1].trim(); manualCommands = manualCommandsMatch[1].trim();
} }
commentBody = `🔒 **GitHub App Permission Issue** commentBody = `🔒 **[Step 2/4] GitHub App Permission Issue**
The patch creation failed due to insufficient GitHub App permissions for creating workflow files. The patch creation failed due to insufficient GitHub App permissions for creating workflow files.
@@ -169,7 +169,7 @@ After running these commands, you can re-run the patch workflow.`
const prMatch = logContent.match(/Found existing PR #(\d+): (.*)/); const prMatch = logContent.match(/Found existing PR #(\d+): (.*)/);
if (prMatch) { if (prMatch) {
const [, prNumber, prUrl] = prMatch; const [, prNumber, prUrl] = prMatch;
commentBody = ` **Patch PR already exists!** commentBody = ` **[Step 2/4] Patch PR already exists!**
A patch PR for this change already exists: [#${prNumber}](${prUrl}). A patch PR for this change already exists: [#${prNumber}](${prUrl}).
@@ -185,7 +185,7 @@ A patch PR for this change already exists: [#${prNumber}](${prUrl}).
const branchMatch = logContent.match(/Hotfix branch (.*) already exists/); const branchMatch = logContent.match(/Hotfix branch (.*) already exists/);
if (branchMatch) { if (branchMatch) {
const [, branch] = branchMatch; const [, branch] = branchMatch;
commentBody = ` **Patch branch exists but no PR found!** commentBody = ` **[Step 2/4] Patch branch exists but no PR found!**
A patch branch [\`${branch}\`](https://github.com/${repository}/tree/${branch}) exists but has no open PR. A patch branch [\`${branch}\`](https://github.com/${repository}/tree/${branch}) exists but has no open PR.
@@ -213,7 +213,7 @@ A patch branch [\`${branch}\`](https://github.com/${repository}/tree/${branch})
logContent.includes('Cherry-pick has conflicts') || logContent.includes('Cherry-pick has conflicts') ||
logContent.includes('[CONFLICTS]'); logContent.includes('[CONFLICTS]');
commentBody = `🚀 **Patch PR Created!** commentBody = `🚀 **[Step 2/4] Patch PR Created!**
**📋 Patch Details:** **📋 Patch Details:**
- **Environment**: \`${environment}\` - **Environment**: \`${environment}\`
@@ -228,7 +228,8 @@ ${hasConflicts ? '3' : '2'}. Once merged, the patch release will automatically t
${hasConflicts ? '4' : '3'}. You'll receive updates here when the release completes ${hasConflicts ? '4' : '3'}. You'll receive updates here when the release completes
**🔗 Track Progress:** **🔗 Track Progress:**
- [View hotfix PR #${mockPrNumber}](${mockPrUrl})`; - [View hotfix PR #${mockPrNumber}](${mockPrUrl})
- [This patch creation workflow run](https://github.com/${repository}/actions/runs/${runId})`;
} else if (hasGitHubCli) { } else if (hasGitHubCli) {
// Find the actual PR for the new branch using gh CLI // Find the actual PR for the new branch using gh CLI
try { try {
@@ -269,7 +270,7 @@ ${hasConflicts ? '4' : '3'}. You'll receive updates here when the release comple
logContent.includes('Cherry-pick has conflicts') || logContent.includes('Cherry-pick has conflicts') ||
pr.title.includes('[CONFLICTS]'); pr.title.includes('[CONFLICTS]');
commentBody = `🚀 **Patch PR Created!** commentBody = `🚀 **[Step 2/4] Patch PR Created!**
**📋 Patch Details:** **📋 Patch Details:**
- **Environment**: \`${environment}\` - **Environment**: \`${environment}\`
@@ -284,10 +285,11 @@ ${hasConflicts ? '3' : '2'}. Once merged, the patch release will automatically t
${hasConflicts ? '4' : '3'}. You'll receive updates here when the release completes ${hasConflicts ? '4' : '3'}. You'll receive updates here when the release completes
**🔗 Track Progress:** **🔗 Track Progress:**
- [View hotfix PR #${pr.number}](${pr.url})`; - [View hotfix PR #${pr.number}](${pr.url})
- [This patch creation workflow run](https://github.com/${repository}/actions/runs/${runId})`;
} else { } else {
// Fallback if PR not found yet // Fallback if PR not found yet
commentBody = `🚀 **Patch PR Created!** commentBody = `🚀 **[Step 2/4] Patch PR Created!**
The patch release PR for this change has been created on branch [\`${branch}\`](https://github.com/${repository}/tree/${branch}). The patch release PR for this change has been created on branch [\`${branch}\`](https://github.com/${repository}/tree/${branch}).
@@ -296,23 +298,25 @@ The patch release PR for this change has been created on branch [\`${branch}\`](
2. Once merged, the patch release will automatically trigger 2. Once merged, the patch release will automatically trigger
**🔗 Links:** **🔗 Links:**
- [View all patch PRs](https://github.com/${repository}/pulls?q=is%3Apr+is%3Aopen+label%3Apatch)`; - [View all patch PRs](https://github.com/${repository}/pulls?q=is%3Apr+is%3Aopen+label%3Apatch)
- [This patch creation workflow run](https://github.com/${repository}/actions/runs/${runId})`;
} }
} catch (error) { } catch (error) {
console.log('Error finding PR for branch:', error.message); console.log('Error finding PR for branch:', error.message);
// Fallback // Fallback
commentBody = `🚀 **Patch PR Created!** commentBody = `🚀 **[Step 2/4] Patch PR Created!**
The patch release PR for this change has been created. The patch release PR for this change has been created.
**🔗 Links:** **🔗 Links:**
- [View all patch PRs](https://github.com/${repository}/pulls?q=is%3Apr+is%3Aopen+label%3Apatch)`; - [View all patch PRs](https://github.com/${repository}/pulls?q=is%3Apr+is%3Aopen+label%3Apatch)
- [This patch creation workflow run](https://github.com/${repository}/actions/runs/${runId})`;
} }
} }
} }
} else { } else {
// Failure // Failure
commentBody = `❌ **Patch creation failed!** commentBody = `❌ **[Step 2/4] Patch creation failed!**
There was an error creating the patch release. There was an error creating the patch release.
@@ -326,7 +330,7 @@ There was an error creating the patch release.
} }
if (!commentBody) { if (!commentBody) {
commentBody = `❌ **Patch creation failed!** commentBody = `❌ **[Step 2/4] Patch creation failed!**
No output was generated during patch creation. No output was generated during patch creation.

View File

@@ -115,6 +115,7 @@ async function main() {
const isDryRun = argv.dryRun || body.includes('[DRY RUN]'); const isDryRun = argv.dryRun || body.includes('[DRY RUN]');
const forceSkipTests = const forceSkipTests =
argv.forceSkipTests || process.env.FORCE_SKIP_TESTS === 'true'; argv.forceSkipTests || process.env.FORCE_SKIP_TESTS === 'true';
const runId = process.env.GITHUB_RUN_ID || '0';
if (!headRef) { if (!headRef) {
throw new Error( throw new Error(
@@ -264,7 +265,7 @@ async function main() {
console.log(`Commenting on original PR ${originalPr}...`); console.log(`Commenting on original PR ${originalPr}...`);
const npmTag = channel === 'stable' ? 'latest' : 'preview'; const npmTag = channel === 'stable' ? 'latest' : 'preview';
const commentBody = `🚀 **Patch Release Started!** const commentBody = `🚀 **[Step 3/4] Patch Release ${environment === 'prod' ? 'Waiting for Approval' : 'Triggered'}!**
**📋 Release Details:** **📋 Release Details:**
- **Environment**: \`${environment}\` - **Environment**: \`${environment}\`
@@ -273,10 +274,11 @@ async function main() {
- **Hotfix PR**: Merged ✅ - **Hotfix PR**: Merged ✅
- **Release Branch**: [\`${releaseRef}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/tree/${releaseRef}) - **Release Branch**: [\`${releaseRef}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/tree/${releaseRef})
**⏳ Status:** The patch release is now running. You'll receive another update when it completes. **⏳ Status:** The patch release has been triggered${environment === 'prod' ? ' and is waiting for deployment approval. Please visit the specific workflow run link below and approve the deployment' : ''}. You'll receive another update when it completes.
**🔗 Track Progress:** **🔗 Track Progress:**
- [View release workflow](https://github.com/${context.repo.owner}/${context.repo.repo}/actions)`; - [View release workflow history](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/workflows/${workflowId})
- [This trigger workflow run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId})`;
if (!testMode) { if (!testMode) {
let tempDir; let tempDir;

View File

@@ -57,7 +57,7 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
expect(result.stdout).toContain('Environment**: `prod`'); expect(result.stdout).toContain('Environment**: `prod`');
}); });
@@ -68,7 +68,7 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
expect(result.stdout).toContain('Environment**: `dev`'); expect(result.stdout).toContain('Environment**: `dev`');
}); });
@@ -90,7 +90,7 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
expect(result.stdout).toContain('Environment**: `prod`'); expect(result.stdout).toContain('Environment**: `prod`');
}); });
}); });
@@ -106,7 +106,7 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
expect(result.stdout).toContain('Channel**: `preview`'); expect(result.stdout).toContain('Channel**: `preview`');
expect(result.stdout).toContain('Commit**: `abc1234`'); expect(result.stdout).toContain('Commit**: `abc1234`');
}); });
@@ -118,7 +118,9 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('❌ **Patch creation failed!**'); expect(result.stdout).toContain(
'❌ **[Step 2/4] Patch creation failed!**',
);
expect(result.stdout).toContain( expect(result.stdout).toContain(
'There was an error creating the patch release', 'There was an error creating the patch release',
); );
@@ -136,7 +138,7 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
expect(result.stdout).toContain('Channel**: `stable`'); expect(result.stdout).toContain('Channel**: `stable`');
expect(result.stdout).toContain('Commit**: `abc1234`'); expect(result.stdout).toContain('Commit**: `abc1234`');
expect(result.stdout).not.toContain('⚠️ Status'); expect(result.stdout).not.toContain('⚠️ Status');
@@ -152,7 +154,7 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
expect(result.stdout).toContain( expect(result.stdout).toContain(
'⚠️ Status**: Cherry-pick conflicts detected', '⚠️ Status**: Cherry-pick conflicts detected',
); );
@@ -174,7 +176,9 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain(' **Patch PR already exists!**'); expect(result.stdout).toContain(
' **[Step 2/4] Patch PR already exists!**',
);
expect(result.stdout).toContain( expect(result.stdout).toContain(
'A patch PR for this change already exists: [#8700](https://github.com/google-gemini/gemini-cli/pull/8700)', 'A patch PR for this change already exists: [#8700](https://github.com/google-gemini/gemini-cli/pull/8700)',
); );
@@ -194,7 +198,7 @@ describe('patch-create-comment', () => {
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain( expect(result.stdout).toContain(
' **Patch branch exists but no PR found!**', ' **[Step 2/4] Patch branch exists but no PR found!**',
); );
expect(result.stdout).toContain( expect(result.stdout).toContain(
'Delete the branch: `git branch -D hotfix/v0.5.0-preview.2/preview/cherry-pick-jkl3456`', 'Delete the branch: `git branch -D hotfix/v0.5.0-preview.2/preview/cherry-pick-jkl3456`',
@@ -213,7 +217,9 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('❌ **Patch creation failed!**'); expect(result.stdout).toContain(
'❌ **[Step 2/4] Patch creation failed!**',
);
expect(result.stdout).toContain( expect(result.stdout).toContain(
'There was an error creating the patch release', 'There was an error creating the patch release',
); );
@@ -231,7 +237,9 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('❌ **Patch creation failed!**'); expect(result.stdout).toContain(
'❌ **[Step 2/4] Patch creation failed!**',
);
expect(result.stdout).toContain( expect(result.stdout).toContain(
'There was an error creating the patch release', 'There was an error creating the patch release',
); );
@@ -292,7 +300,9 @@ describe('patch-create-comment', () => {
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('❌ **Patch creation failed!**'); expect(result.stdout).toContain(
'❌ **[Step 2/4] Patch creation failed!**',
);
expect(result.stdout).toContain( expect(result.stdout).toContain(
'There was an error creating the patch release', 'There was an error creating the patch release',
); );
@@ -316,7 +326,9 @@ git push origin hotfix/v0.4.1/stable/cherry-pick-abc1234
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('🔒 **GitHub App Permission Issue**'); expect(result.stdout).toContain(
'🔒 **[Step 2/4] GitHub App Permission Issue**',
);
expect(result.stdout).toContain( expect(result.stdout).toContain(
'Please run these commands manually to create the release branch:', 'Please run these commands manually to create the release branch:',
); );
@@ -339,7 +351,7 @@ git push origin hotfix/v0.4.1/stable/cherry-pick-abc1234
expect(result.stdout).toContain( expect(result.stdout).toContain(
'🧪 TEST MODE - No API calls will be made', '🧪 TEST MODE - No API calls will be made',
); );
expect(result.stdout).toContain('🚀 **Patch PR Created!**'); expect(result.stdout).toContain('🚀 **[Step 2/4] Patch PR Created!**');
}); });
it('should generate mock content in test mode for failure', () => { it('should generate mock content in test mode for failure', () => {
@@ -348,7 +360,9 @@ git push origin hotfix/v0.4.1/stable/cherry-pick-abc1234
); );
expect(result.success).toBe(true); expect(result.success).toBe(true);
expect(result.stdout).toContain('❌ **Patch creation failed!**'); expect(result.stdout).toContain(
'❌ **[Step 2/4] Patch creation failed!**',
);
}); });
}); });
}); });