From 2c9472fa6d64dc85e81353a25fe1ffc5076e05b3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:29:52 +0000 Subject: [PATCH 1/7] Initial plan From 154c68a15d6667cde86768ed17feb538cbbaf092 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:34:45 +0000 Subject: [PATCH 2/7] Initial plan: Add allow-empty field to create-pull-request safe output Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/aw/github-agentic-workflows.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/aw/github-agentic-workflows.md b/.github/aw/github-agentic-workflows.md index 13ddf594f4..0b3df484a9 100644 --- a/.github/aw/github-agentic-workflows.md +++ b/.github/aw/github-agentic-workflows.md @@ -392,11 +392,11 @@ The YAML frontmatter supports these fields: target-repo: "owner/repo" # Optional: cross-repository ``` When using `safe-outputs.close-pull-request`, the main job does **not** need `pull-requests: write` permission since PR closing is handled by a separate job with appropriate permissions. - - `add-labels:` - Safe label addition to issues or PRs. Labels will be created if they don't already exist in the repository. + - `add-labels:` - Safe label addition to issues or PRs ```yaml safe-outputs: add-labels: - allowed: [bug, enhancement, documentation] # Optional: restrict to specific labels (will be created if missing) + allowed: [bug, enhancement, documentation] # Optional: restrict to specific labels max: 3 # Optional: maximum number of labels (default: 3) target: "*" # Optional: "triggering" (default), "*" (any issue/PR), or number target-repo: "owner/repo" # Optional: cross-repository From 4971f565dfe0d5bc6316429b7965646a69bd32fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:44:58 +0000 Subject: [PATCH 3/7] feat: Add allow-empty field to create-pull-request safe output - Add allow-empty field to CreatePullRequestsConfig struct - Add allow-empty to JSON schema with description - Parse allow-empty field from config and pass to JavaScript via env var - Update create_pull_request.cjs to handle allow-empty mode: - Skip patch file existence/validation checks when allow-empty is true - Allow creating branch and PR without any changes - Push empty branch to create feature branch for future changes - Update dev.md to demonstrate creating an empty PR Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/cloclo.lock.yml | 142 +- .github/workflows/daily-doc-updater.lock.yml | 142 +- .../workflows/daily-workflow-updater.lock.yml | 142 +- .github/workflows/dev.lock.yml | 1192 +++++++++-------- .github/workflows/dev.md | 12 +- .../developer-docs-consolidator.lock.yml | 142 +- .github/workflows/dictation-prompt.lock.yml | 142 +- .../github-mcp-tools-report.lock.yml | 142 +- .../workflows/glossary-maintainer.lock.yml | 142 +- .github/workflows/go-logger.lock.yml | 142 +- .../workflows/instructions-janitor.lock.yml | 142 +- .../workflows/layout-spec-maintainer.lock.yml | 142 +- .github/workflows/poem-bot.lock.yml | 142 +- .github/workflows/q.lock.yml | 142 +- .github/workflows/security-fix-pr.lock.yml | 142 +- .github/workflows/spec-kit-execute.lock.yml | 142 +- .github/workflows/spec-kit-executor.lock.yml | 142 +- .../workflows/technical-doc-writer.lock.yml | 142 +- .github/workflows/tidy.lock.yml | 142 +- .github/workflows/unbloat-docs.lock.yml | 142 +- pkg/cli/templates/github-agentic-workflows.md | 4 +- pkg/parser/schemas/main_workflow_schema.json | 4 + pkg/workflow/create_pull_request.go | 11 + pkg/workflow/js/create_pull_request.cjs | 175 ++- 24 files changed, 2469 insertions(+), 1485 deletions(-) diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 484767e533..ce1ce121ef 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -7475,6 +7475,7 @@ jobs: GH_AW_PR_LABELS: "automation,cloclo" GH_AW_PR_DRAFT: "true" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} @@ -7661,52 +7662,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -7727,7 +7743,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -7743,6 +7759,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -7952,16 +7970,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index 31a86a7e9f..7e6d2cb62c 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -5732,6 +5732,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Daily Documentation Updater" GH_AW_TRACKER_ID: "daily-doc-updater" @@ -5916,52 +5917,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -5982,7 +5998,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -5998,6 +6014,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6207,16 +6225,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index 3c799501bf..2779a409eb 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -6166,6 +6166,7 @@ jobs: GH_AW_PR_LABELS: "dependencies,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Daily Workflow Updater" GH_AW_TRACKER_ID: "daily-workflow-updater" @@ -6350,52 +6351,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6416,7 +6432,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6432,6 +6448,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6641,16 +6659,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 4a93dd40cf..d8f4015c41 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -18,14 +18,14 @@ # gh aw compile # For more information: https://github.com/githubnext/gh-aw/blob/main/.github/aw/github-agentic-workflows.md # -# Create a poem about GitHub and save it to repo-memory +# Create an empty pull request for agent to push changes to # # Original Frontmatter: # ```yaml # on: # workflow_dispatch: # name: Dev -# description: Create a poem about GitHub and save it to repo-memory +# description: Create an empty pull request for agent to push changes to # timeout-minutes: 5 # strict: false # engine: copilot @@ -39,7 +39,8 @@ # imports: # - shared/gh.md # safe-outputs: -# create-issue: +# create-pull-request: +# allow-empty: true # staged: true # steps: # - name: Download issues data @@ -59,16 +60,17 @@ # activation["activation"] # agent["agent"] # conclusion["conclusion"] -# create_issue["create_issue"] +# create_pull_request["create_pull_request"] # detection["detection"] # activation --> agent # activation --> conclusion +# activation --> create_pull_request # agent --> conclusion -# agent --> create_issue +# agent --> create_pull_request # agent --> detection -# create_issue --> conclusion +# create_pull_request --> conclusion # detection --> conclusion -# detection --> create_issue +# detection --> create_pull_request # ``` # # Original Prompt: @@ -90,8 +92,11 @@ # # # -# Read the last pull request using `githubissues-gh` tool -# and create an issue with the summary. +# Create an empty pull request that prepares a branch for future changes. +# The pull request should have: +# - Title: "Feature: Prepare branch for agent updates" +# - Body: "This is an empty pull request created to prepare a feature branch that an agent can push changes to later." +# - Branch name: "feature/agent-updates" # ``` # # Pinned GitHub Actions: @@ -339,39 +344,32 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{"max":0},"noop":{"max":1}} + {"create_pull_request":{},"missing_tool":{"max":0},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [ { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created.", + "description": "Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 1 pull request(s) can be created.", "inputSchema": { "additionalProperties": false, "properties": { "body": { - "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", + "description": "Detailed PR description in Markdown. Include what changes were made, why, testing notes, and any breaking changes. Do NOT repeat the title as a heading.", + "type": "string" + }, + "branch": { + "description": "Source branch name containing the changes. If omitted, uses the current working branch.", "type": "string" }, "labels": { - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", + "description": "Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.", "items": { "type": "string" }, "type": "array" }, - "parent": { - "description": "Parent issue number for creating sub-issues. Can be a real issue number (e.g., 42) or a temporary_id (e.g., 'aw_abc123def456') from a previously created issue in the same workflow run.", - "type": [ - "number", - "string" - ] - }, - "temporary_id": { - "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 12 hex characters (e.g., 'aw_abc123def456'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", - "type": "string" - }, "title": { - "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", + "description": "Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.", "type": "string" } }, @@ -381,7 +379,7 @@ jobs: ], "type": "object" }, - "name": "create_issue" + "name": "create_pull_request" }, { "description": "Report that a tool or capability needed to complete the task is not available. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", @@ -430,7 +428,7 @@ jobs: EOF cat > /tmp/gh-aw/safeoutputs/validation.json << 'EOF' { - "create_issue": { + "create_pull_request": { "defaultMax": 1, "fields": { "body": { @@ -439,22 +437,18 @@ jobs: "sanitize": true, "maxLength": 65000 }, + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, "labels": { "type": "array", "itemType": "string", "itemSanitize": true, "itemMaxLength": 128 }, - "parent": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "temporary_id": { - "type": "string" - }, "title": { "required": true, "type": "string", @@ -3292,8 +3286,11 @@ jobs: - Read the last pull request using `githubissues-gh` tool - and create an issue with the summary. + Create an empty pull request that prepares a branch for future changes. + The pull request should have: + - Title: "Feature: Prepare branch for agent updates" + - Body: "This is an empty pull request created to prepare a feature branch that an agent can push changes to later." + - Branch name: "feature/agent-updates" PROMPT_EOF - name: Append XPIA security instructions to prompt @@ -3357,7 +3354,7 @@ jobs: To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls. - **Available tools**: create_issue, missing_tool, noop + **Available tools**: create_pull_request, missing_tool, noop **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped. @@ -6370,12 +6367,19 @@ jobs: if (typeof module === "undefined" || require.main === module) { main(); } + - name: Upload git patch + if: always() + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + with: + name: aw.patch + path: /tmp/gh-aw/aw.patch + if-no-files-found: ignore conclusion: needs: - activation - agent - - create_issue + - create_pull_request - detection if: (always()) && (needs.agent.result != 'skipped') runs-on: ubuntu-slim @@ -6625,8 +6629,8 @@ jobs: GH_AW_WORKFLOW_NAME: "Dev" GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.result }} - GH_AW_SAFE_OUTPUT_JOBS: "{\"create_issue\":\"issue_url\"}" - GH_AW_OUTPUT_CREATE_ISSUE_ISSUE_URL: ${{ needs.create_issue.outputs.issue_url }} + GH_AW_SAFE_OUTPUT_JOBS: "{\"create_pull_request\":\"pull_request_url\"}" + GH_AW_OUTPUT_CREATE_PULL_REQUEST_PULL_REQUEST_URL: ${{ needs.create_pull_request.outputs.pull_request_url }} with: github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -6881,23 +6885,50 @@ jobs: core.setFailed(error instanceof Error ? error.message : String(error)); }); - create_issue: + create_pull_request: needs: + - activation - agent - detection if: > - (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_issue'))) && + (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))) && (needs.detection.outputs.success == 'true') runs-on: ubuntu-slim permissions: - contents: read + contents: write issues: write + pull-requests: write timeout-minutes: 10 outputs: - issue_number: ${{ steps.create_issue.outputs.issue_number }} - issue_url: ${{ steps.create_issue.outputs.issue_url }} - temporary_id_map: ${{ steps.create_issue.outputs.temporary_id_map }} + branch_name: ${{ steps.create_pull_request.outputs.branch_name }} + fallback_used: ${{ steps.create_pull_request.outputs.fallback_used }} + issue_number: ${{ steps.create_pull_request.outputs.issue_number }} + issue_url: ${{ steps.create_pull_request.outputs.issue_url }} + pull_request_number: ${{ steps.create_pull_request.outputs.pull_request_number }} + pull_request_url: ${{ steps.create_pull_request.outputs.pull_request_url }} steps: + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 + with: + name: aw.patch + path: /tmp/gh-aw/ + - name: Checkout repository + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Download agent output artifact continue-on-error: true uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 @@ -6909,138 +6940,130 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Create Output Issue - id: create_issue + - name: Create Pull Request + id: create_pull_request uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_ID: "agent" + GH_AW_BASE_BRANCH: ${{ github.ref_name }} + GH_AW_PR_DRAFT: "true" + GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "true" + GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Dev" GH_AW_ENGINE_ID: "copilot" GH_AW_SAFE_OUTPUTS_STAGED: "true" with: github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - function sanitizeLabelContent(content) { - if (!content || typeof content !== "string") { - return ""; - } - let sanitized = content.trim(); - sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, ""); - sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ""); - sanitized = sanitized.replace( - /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g, - (_m, p1, p2) => `${p1}\`@${p2}\`` - ); - sanitized = sanitized.replace(/[<>&'"]/g, ""); - return sanitized.trim(); - } const fs = require("fs"); const crypto = require("crypto"); - const MAX_LOG_CONTENT_LENGTH = 10000; - function truncateForLogging(content) { - if (content.length <= MAX_LOG_CONTENT_LENGTH) { - return content; - } - return content.substring(0, MAX_LOG_CONTENT_LENGTH) + `\n... (truncated, total length: ${content.length})`; - } - function loadAgentOutput() { - const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT; - if (!agentOutputFile) { - core.info("No GH_AW_AGENT_OUTPUT environment variable found"); - return { success: false }; - } - let outputContent; - try { - outputContent = fs.readFileSync(agentOutputFile, "utf8"); - } catch (error) { - const errorMessage = `Error reading agent output file: ${error instanceof Error ? error.message : String(error)}`; - core.error(errorMessage); - return { success: false, error: errorMessage }; - } - if (outputContent.trim() === "") { - core.info("Agent output content is empty"); - return { success: false }; - } - core.info(`Agent output content length: ${outputContent.length}`); - let validatedOutput; - try { - validatedOutput = JSON.parse(outputContent); - } catch (error) { - const errorMessage = `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}`; - core.error(errorMessage); - core.info(`Failed to parse content:\n${truncateForLogging(outputContent)}`); - return { success: false, error: errorMessage }; - } - if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - core.info("No valid items found in agent output"); - core.info(`Parsed content: ${truncateForLogging(JSON.stringify(validatedOutput))}`); - return { success: false }; + async function updateActivationComment(github, context, core, itemUrl, itemNumber, itemType = "pull_request") { + const itemLabel = itemType === "issue" ? "issue" : "pull request"; + const linkMessage = + itemType === "issue" + ? `\n\nāœ… Issue created: [#${itemNumber}](${itemUrl})` + : `\n\nāœ… Pull request created: [#${itemNumber}](${itemUrl})`; + await updateActivationCommentWithMessage(github, context, core, linkMessage, itemLabel); + } + async function updateActivationCommentWithCommit(github, context, core, commitSha, commitUrl) { + const shortSha = commitSha.substring(0, 7); + const message = `\n\nāœ… Commit pushed: [\`${shortSha}\`](${commitUrl})`; + await updateActivationCommentWithMessage(github, context, core, message, "commit"); + } + async function updateActivationCommentWithMessage(github, context, core, message, label = "") { + const commentId = process.env.GH_AW_COMMENT_ID; + const commentRepo = process.env.GH_AW_COMMENT_REPO; + if (!commentId) { + core.info("No activation comment to update (GH_AW_COMMENT_ID not set)"); + return; } - return { success: true, items: validatedOutput.items }; - } - async function generateStagedPreview(options) { - const { title, description, items, renderItem } = options; - let summaryContent = `## šŸŽ­ Staged Mode: ${title} Preview\n\n`; - summaryContent += `${description}\n\n`; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - summaryContent += renderItem(item, i); - summaryContent += "---\n\n"; + core.info(`Updating activation comment ${commentId}`); + let repoOwner = context.repo.owner; + let repoName = context.repo.repo; + if (commentRepo) { + const parts = commentRepo.split("/"); + if (parts.length === 2) { + repoOwner = parts[0]; + repoName = parts[1]; + } else { + core.warning(`Invalid comment repo format: ${commentRepo}, expected "owner/repo". Falling back to context.repo.`); + } } + core.info(`Updating comment in ${repoOwner}/${repoName}`); + const isDiscussionComment = commentId.startsWith("DC_"); try { - await core.summary.addRaw(summaryContent).write(); - core.info(summaryContent); - core.info(`šŸ“ ${title} preview written to step summary`); + if (isDiscussionComment) { + const currentComment = await github.graphql( + ` + query($commentId: ID!) { + node(id: $commentId) { + ... on DiscussionComment { + body + } + } + }`, + { commentId: commentId } + ); + if (!currentComment?.node?.body) { + core.warning("Unable to fetch current comment body, comment may have been deleted or is inaccessible"); + return; + } + const currentBody = currentComment.node.body; + const updatedBody = currentBody + message; + const result = await github.graphql( + ` + mutation($commentId: ID!, $body: String!) { + updateDiscussionComment(input: { commentId: $commentId, body: $body }) { + comment { + id + url + } + } + }`, + { commentId: commentId, body: updatedBody } + ); + const comment = result.updateDiscussionComment.comment; + const successMessage = label + ? `Successfully updated discussion comment with ${label} link` + : "Successfully updated discussion comment"; + core.info(successMessage); + core.info(`Comment ID: ${comment.id}`); + core.info(`Comment URL: ${comment.url}`); + } else { + const currentComment = await github.request("GET /repos/{owner}/{repo}/issues/comments/{comment_id}", { + owner: repoOwner, + repo: repoName, + comment_id: parseInt(commentId, 10), + headers: { + Accept: "application/vnd.github+json", + }, + }); + if (!currentComment?.data?.body) { + core.warning("Unable to fetch current comment body, comment may have been deleted"); + return; + } + const currentBody = currentComment.data.body; + const updatedBody = currentBody + message; + const response = await github.request("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", { + owner: repoOwner, + repo: repoName, + comment_id: parseInt(commentId, 10), + body: updatedBody, + headers: { + Accept: "application/vnd.github+json", + }, + }); + const successMessage = label ? `Successfully updated comment with ${label} link` : "Successfully updated comment"; + core.info(successMessage); + core.info(`Comment ID: ${response.data.id}`); + core.info(`Comment URL: ${response.data.html_url}`); + } } catch (error) { - core.setFailed(error instanceof Error ? error : String(error)); + core.warning(`Failed to update activation comment: ${error instanceof Error ? error.message : String(error)}`); } } - function generateXMLMarker(workflowName, runUrl) { - const engineId = process.env.GH_AW_ENGINE_ID || ""; - const engineVersion = process.env.GH_AW_ENGINE_VERSION || ""; - const engineModel = process.env.GH_AW_ENGINE_MODEL || ""; - const trackerId = process.env.GH_AW_TRACKER_ID || ""; - const parts = []; - parts.push(`agentic-workflow: ${workflowName}`); - if (trackerId) { - parts.push(`tracker-id: ${trackerId}`); - } - if (engineId) { - parts.push(`engine: ${engineId}`); - } - if (engineVersion) { - parts.push(`version: ${engineVersion}`); - } - if (engineModel) { - parts.push(`model: ${engineModel}`); - } - parts.push(`run: ${runUrl}`); - return ``; - } - function generateFooter( - workflowName, - runUrl, - workflowSource, - workflowSourceURL, - triggeringIssueNumber, - triggeringPRNumber, - triggeringDiscussionNumber - ) { - let footer = `\n\n> AI generated by [${workflowName}](${runUrl})`; - if (triggeringIssueNumber) { - footer += ` for #${triggeringIssueNumber}`; - } else if (triggeringPRNumber) { - footer += ` for #${triggeringPRNumber}`; - } else if (triggeringDiscussionNumber) { - footer += ` for discussion #${triggeringDiscussionNumber}`; - } - if (workflowSource && workflowSourceURL) { - footer += `\n>\n> To add this workflow in your repository, run \`gh aw add ${workflowSource}\`. See [usage guide](https://githubnext.github.io/gh-aw/tools/cli/).`; - } - footer += "\n\n" + generateXMLMarker(workflowName, runUrl); - footer += "\n"; - return footer; - } function getTrackerID(format) { const trackerID = process.env.GH_AW_TRACKER_ID || ""; if (trackerID) { @@ -7049,130 +7072,6 @@ jobs: } return ""; } - const TEMPORARY_ID_PATTERN = /#(aw_[0-9a-f]{12})/gi; - function generateTemporaryId() { - return "aw_" + crypto.randomBytes(6).toString("hex"); - } - function isTemporaryId(value) { - if (typeof value === "string") { - return /^aw_[0-9a-f]{12}$/i.test(value); - } - return false; - } - function normalizeTemporaryId(tempId) { - return String(tempId).toLowerCase(); - } - function replaceTemporaryIdReferences(text, tempIdMap, currentRepo) { - return text.replace(TEMPORARY_ID_PATTERN, (match, tempId) => { - const resolved = tempIdMap.get(normalizeTemporaryId(tempId)); - if (resolved !== undefined) { - if (currentRepo && resolved.repo === currentRepo) { - return `#${resolved.number}`; - } - return `${resolved.repo}#${resolved.number}`; - } - return match; - }); - } - function replaceTemporaryIdReferencesLegacy(text, tempIdMap) { - return text.replace(TEMPORARY_ID_PATTERN, (match, tempId) => { - const issueNumber = tempIdMap.get(normalizeTemporaryId(tempId)); - if (issueNumber !== undefined) { - return `#${issueNumber}`; - } - return match; - }); - } - function loadTemporaryIdMap() { - const mapJson = process.env.GH_AW_TEMPORARY_ID_MAP; - if (!mapJson || mapJson === "{}") { - return new Map(); - } - try { - const mapObject = JSON.parse(mapJson); - const result = new Map(); - for (const [key, value] of Object.entries(mapObject)) { - const normalizedKey = normalizeTemporaryId(key); - if (typeof value === "number") { - const contextRepo = `${context.repo.owner}/${context.repo.repo}`; - result.set(normalizedKey, { repo: contextRepo, number: value }); - } else if (typeof value === "object" && value !== null && "repo" in value && "number" in value) { - result.set(normalizedKey, { repo: String(value.repo), number: Number(value.number) }); - } - } - return result; - } catch (error) { - if (typeof core !== "undefined") { - core.warning(`Failed to parse temporary ID map: ${error instanceof Error ? error.message : String(error)}`); - } - return new Map(); - } - } - function resolveIssueNumber(value, temporaryIdMap) { - if (value === undefined || value === null) { - return { resolved: null, wasTemporaryId: false, errorMessage: "Issue number is missing" }; - } - const valueStr = String(value); - if (isTemporaryId(valueStr)) { - const resolvedPair = temporaryIdMap.get(normalizeTemporaryId(valueStr)); - if (resolvedPair !== undefined) { - return { resolved: resolvedPair, wasTemporaryId: true, errorMessage: null }; - } - return { - resolved: null, - wasTemporaryId: true, - errorMessage: `Temporary ID '${valueStr}' not found in map. Ensure the issue was created before linking.`, - }; - } - const issueNumber = typeof value === "number" ? value : parseInt(valueStr, 10); - if (isNaN(issueNumber) || issueNumber <= 0) { - return { resolved: null, wasTemporaryId: false, errorMessage: `Invalid issue number: ${value}` }; - } - const contextRepo = typeof context !== "undefined" ? `${context.repo.owner}/${context.repo.repo}` : ""; - return { resolved: { repo: contextRepo, number: issueNumber }, wasTemporaryId: false, errorMessage: null }; - } - function serializeTemporaryIdMap(tempIdMap) { - const obj = Object.fromEntries(tempIdMap); - return JSON.stringify(obj); - } - function parseAllowedRepos() { - const allowedReposEnv = process.env.GH_AW_ALLOWED_REPOS; - const set = new Set(); - if (allowedReposEnv) { - allowedReposEnv - .split(",") - .map(repo => repo.trim()) - .filter(repo => repo) - .forEach(repo => set.add(repo)); - } - return set; - } - function getDefaultTargetRepo() { - const targetRepoSlug = process.env.GH_AW_TARGET_REPO_SLUG; - if (targetRepoSlug) { - return targetRepoSlug; - } - return `${context.repo.owner}/${context.repo.repo}`; - } - function validateRepo(repo, defaultRepo, allowedRepos) { - if (repo === defaultRepo) { - return { valid: true, error: null }; - } - if (allowedRepos.has(repo)) { - return { valid: true, error: null }; - } - return { - valid: false, - error: `Repository '${repo}' is not in the allowed-repos list. Allowed: ${defaultRepo}${allowedRepos.size > 0 ? ", " + Array.from(allowedRepos).join(", ") : ""}`, - }; - } - function parseRepoSlug(repoSlug) { - const parts = repoSlug.split("/"); - if (parts.length !== 2 || !parts[0] || !parts[1]) { - return null; - } - return { owner: parts[0], repo: parts[1] }; - } function addExpirationComment(bodyLines, envVarName, entityType) { const expiresEnv = process.env[envVarName]; if (expiresEnv) { @@ -7186,305 +7085,488 @@ jobs: } } } + function generatePatchPreview(patchContent) { + if (!patchContent || !patchContent.trim()) { + return ""; + } + const lines = patchContent.split("\n"); + const maxLines = 500; + const maxChars = 2000; + let preview = lines.length <= maxLines ? patchContent : lines.slice(0, maxLines).join("\n"); + const lineTruncated = lines.length > maxLines; + const charTruncated = preview.length > maxChars; + if (charTruncated) { + preview = preview.slice(0, maxChars); + } + const truncated = lineTruncated || charTruncated; + const summary = truncated + ? `Show patch preview (${Math.min(maxLines, lines.length)} of ${lines.length} lines)` + : `Show patch (${lines.length} lines)`; + return `\n\n
${summary}\n\n\`\`\`diff\n${preview}${truncated ? "\n... (truncated)" : ""}\n\`\`\`\n\n
`; + } async function main() { + core.setOutput("pull_request_number", ""); + core.setOutput("pull_request_url", ""); core.setOutput("issue_number", ""); core.setOutput("issue_url", ""); - core.setOutput("temporary_id_map", "{}"); - core.setOutput("issues_to_assign_copilot", ""); + core.setOutput("branch_name", ""); + core.setOutput("fallback_used", ""); const isStaged = process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true"; - const result = loadAgentOutput(); - if (!result.success) { + const workflowId = process.env.GH_AW_WORKFLOW_ID; + if (!workflowId) { + throw new Error("GH_AW_WORKFLOW_ID environment variable is required"); + } + const baseBranch = process.env.GH_AW_BASE_BRANCH; + if (!baseBranch) { + throw new Error("GH_AW_BASE_BRANCH environment variable is required"); + } + const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT || ""; + let outputContent = ""; + if (agentOutputFile.trim() !== "") { + try { + outputContent = fs.readFileSync(agentOutputFile, "utf8"); + } catch (error) { + core.setFailed(`Error reading agent output file: ${error instanceof Error ? error.message : String(error)}`); + return; + } + } + if (outputContent.trim() === "") { + core.info("Agent output content is empty"); + } + const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; + if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); + return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } + } + } + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } + if (patchContent.includes("Failed to generate patch")) { + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); + return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } + } + } + if (!isEmpty) { + const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); + const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); + const patchSizeKb = Math.ceil(patchSizeBytes / 1024); + core.info(`Patch size: ${patchSizeKb} KB (maximum allowed: ${maxSizeKb} KB)`); + if (patchSizeKb > maxSizeKb) { + const message = `Patch size (${patchSizeKb} KB) exceeds maximum allowed size (${maxSizeKb} KB)`; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āŒ Patch size exceeded\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch size error)"); + return; + } + throw new Error(message); + } + core.info("Patch size validation passed"); + } + if (isEmpty && !isStaged && !allowEmpty) { + const message = "Patch file is empty - no changes to apply (noop operation)"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to push - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } + } + core.info(`Agent output content length: ${outputContent.length}`); + if (!isEmpty) { + core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); + } else { + core.info("Patch file is empty - processing noop operation"); + } + let validatedOutput; + try { + validatedOutput = JSON.parse(outputContent); + } catch (error) { + core.setFailed(`Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}`); return; } - const createIssueItems = result.items.filter(item => item.type === "create_issue"); - if (createIssueItems.length === 0) { - core.info("No create-issue items found in agent output"); + if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { + core.warning("No valid items found in agent output"); return; } - core.info(`Found ${createIssueItems.length} create-issue item(s)`); - const allowedRepos = parseAllowedRepos(); - const defaultTargetRepo = getDefaultTargetRepo(); - core.info(`Default target repo: ${defaultTargetRepo}`); - if (allowedRepos.size > 0) { - core.info(`Allowed repos: ${Array.from(allowedRepos).join(", ")}`); + const pullRequestItem = validatedOutput.items.find( item => item.type === "create_pull_request"); + if (!pullRequestItem) { + core.warning("No create-pull-request item found in agent output"); + return; } + core.info(`Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}`); if (isStaged) { - await generateStagedPreview({ - title: "Create Issues", - description: "The following issues would be created if staged mode was disabled:", - items: createIssueItems, - renderItem: (item, index) => { - let content = `### Issue ${index + 1}\n`; - content += `**Title:** ${item.title || "No title provided"}\n\n`; - if (item.temporary_id) { - content += `**Temporary ID:** ${item.temporary_id}\n\n`; - } - if (item.repo) { - content += `**Repository:** ${item.repo}\n\n`; - } - if (item.body) { - content += `**Body:**\n${item.body}\n\n`; - } - if (item.labels && item.labels.length > 0) { - content += `**Labels:** ${item.labels.join(", ")}\n\n`; - } - if (item.parent) { - content += `**Parent:** ${item.parent}\n\n`; - } - return content; - }, - }); + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Title:** ${pullRequestItem.title || "No title provided"}\n\n`; + summaryContent += `**Branch:** ${pullRequestItem.branch || "auto-generated"}\n\n`; + summaryContent += `**Base:** ${baseBranch}\n\n`; + if (pullRequestItem.body) { + summaryContent += `**Body:**\n${pullRequestItem.body}\n\n`; + } + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + const patchStats = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + if (patchStats.trim()) { + summaryContent += `**Changes:** Patch file exists with ${patchStats.split("\n").length} lines\n\n`; + summaryContent += `
Show patch preview\n\n\`\`\`diff\n${patchStats.slice(0, 2000)}${patchStats.length > 2000 ? "\n... (truncated)" : ""}\n\`\`\`\n\n
\n\n`; + } else { + summaryContent += `**Changes:** No changes (empty patch)\n\n`; + } + } + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary"); return; } - const parentIssueNumber = context.payload?.issue?.number; - const temporaryIdMap = new Map(); - const triggeringIssueNumber = - context.payload?.issue?.number && !context.payload?.issue?.pull_request ? context.payload.issue.number : undefined; - const triggeringPRNumber = - context.payload?.pull_request?.number || (context.payload?.issue?.pull_request ? context.payload.issue.number : undefined); - const triggeringDiscussionNumber = context.payload?.discussion?.number; - const labelsEnv = process.env.GH_AW_ISSUE_LABELS; - let envLabels = labelsEnv + let title = pullRequestItem.title.trim(); + let bodyLines = pullRequestItem.body.split("\n"); + let branchName = pullRequestItem.branch ? pullRequestItem.branch.trim() : null; + if (!title) { + title = "Agent Output"; + } + const titlePrefix = process.env.GH_AW_PR_TITLE_PREFIX; + if (titlePrefix && !title.startsWith(titlePrefix)) { + title = titlePrefix + title; + } + const workflowName = process.env.GH_AW_WORKFLOW_NAME || "Workflow"; + const runId = context.runId; + const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com"; + const runUrl = context.payload.repository + ? `${context.payload.repository.html_url}/actions/runs/${runId}` + : `${githubServer}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; + const trackerIDComment = getTrackerID("markdown"); + if (trackerIDComment) { + bodyLines.push(trackerIDComment); + } + addExpirationComment(bodyLines, "GH_AW_PR_EXPIRES", "Pull Request"); + bodyLines.push(``, ``, `> AI generated by [${workflowName}](${runUrl})`, ""); + const body = bodyLines.join("\n").trim(); + const labelsEnv = process.env.GH_AW_PR_LABELS; + const labels = labelsEnv ? labelsEnv .split(",") - .map(label => label.trim()) - .filter(label => label) + .map( label => label.trim()) + .filter( label => label) : []; - const createdIssues = []; - for (let i = 0; i < createIssueItems.length; i++) { - const createIssueItem = createIssueItems[i]; - const itemRepo = createIssueItem.repo ? String(createIssueItem.repo).trim() : defaultTargetRepo; - const repoValidation = validateRepo(itemRepo, defaultTargetRepo, allowedRepos); - if (!repoValidation.valid) { - core.warning(`Skipping issue: ${repoValidation.error}`); - continue; + const draftEnv = process.env.GH_AW_PR_DRAFT; + const draft = draftEnv ? draftEnv.toLowerCase() === "true" : true; + core.info(`Creating pull request with title: ${title}`); + core.info(`Labels: ${JSON.stringify(labels)}`); + core.info(`Draft: ${draft}`); + core.info(`Body length: ${body.length}`); + const randomHex = crypto.randomBytes(8).toString("hex"); + if (!branchName) { + core.info("No branch name provided in JSONL, generating unique branch name"); + branchName = `${workflowId}-${randomHex}`; + } else { + branchName = `${branchName}-${randomHex}`; + core.info(`Using branch name from JSONL with added salt: ${branchName}`); + } + core.info(`Generated branch name: ${branchName}`); + core.info(`Base branch: ${baseBranch}`); + core.info(`Fetching latest changes and checking out base branch: ${baseBranch}`); + await exec.exec("git fetch origin"); + await exec.exec(`git checkout ${baseBranch}`); + core.info(`Branch should not exist locally, creating new branch from base: ${branchName}`); + await exec.exec(`git checkout -b ${branchName}`); + core.info(`Created new branch from base: ${branchName}`); + if (!isEmpty) { + core.info("Applying patch..."); + const patchLines = patchContent.split("\n"); + const previewLineCount = Math.min(500, patchLines.length); + core.info(`Patch preview (first ${previewLineCount} of ${patchLines.length} lines):`); + for (let i = 0; i < previewLineCount; i++) { + core.info(patchLines[i]); } - const repoParts = parseRepoSlug(itemRepo); - if (!repoParts) { - core.warning(`Skipping issue: Invalid repository format '${itemRepo}'. Expected 'owner/repo'.`); - continue; + try { + await exec.exec("git am /tmp/gh-aw/aw.patch"); + core.info("Patch applied successfully"); + } catch (patchError) { + core.error(`Failed to apply patch: ${patchError instanceof Error ? patchError.message : String(patchError)}`); + try { + core.info("Investigating patch failure..."); + const statusResult = await exec.getExecOutput("git", ["status"]); + core.info("Git status output:"); + core.info(statusResult.stdout); + const patchResult = await exec.getExecOutput("git", ["am", "--show-current-patch=diff"]); + core.info("Failed patch content:"); + core.info(patchResult.stdout); + } catch (investigateError) { + core.warning( + `Failed to investigate patch failure: ${investigateError instanceof Error ? investigateError.message : String(investigateError)}` + ); + } + core.setFailed("Failed to apply patch"); + return; } - const temporaryId = createIssueItem.temporary_id || generateTemporaryId(); - core.info( - `Processing create-issue item ${i + 1}/${createIssueItems.length}: title=${createIssueItem.title}, bodyLength=${createIssueItem.body.length}, temporaryId=${temporaryId}, repo=${itemRepo}` - ); - core.info(`Debug: createIssueItem.parent = ${JSON.stringify(createIssueItem.parent)}`); - core.info(`Debug: parentIssueNumber from context = ${JSON.stringify(parentIssueNumber)}`); - let effectiveParentIssueNumber; - let effectiveParentRepo = itemRepo; - if (createIssueItem.parent !== undefined) { - if (isTemporaryId(createIssueItem.parent)) { - const resolvedParent = temporaryIdMap.get(normalizeTemporaryId(createIssueItem.parent)); - if (resolvedParent !== undefined) { - effectiveParentIssueNumber = resolvedParent.number; - effectiveParentRepo = resolvedParent.repo; - core.info(`Resolved parent temporary ID '${createIssueItem.parent}' to ${effectiveParentRepo}#${effectiveParentIssueNumber}`); - } else { - core.warning( - `Parent temporary ID '${createIssueItem.parent}' not found in map. Ensure parent issue is created before sub-issues.` - ); - effectiveParentIssueNumber = undefined; + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; } - } else { - effectiveParentIssueNumber = parseInt(String(createIssueItem.parent), 10); - if (isNaN(effectiveParentIssueNumber)) { - core.warning(`Invalid parent value: ${createIssueItem.parent}`); - effectiveParentIssueNumber = undefined; + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Changes pushed to branch"); + } catch (pushError) { + core.error(`Git push failed: ${pushError instanceof Error ? pushError.message : String(pushError)}`); + core.warning("Git push operation failed - creating fallback issue instead of pull request"); + const runId = context.runId; + const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com"; + const runUrl = context.payload.repository + ? `${context.payload.repository.html_url}/actions/runs/${runId}` + : `${githubServer}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; + let patchPreview = ""; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + patchPreview = generatePatchPreview(patchContent); + } + const fallbackBody = `${body} + --- + > [!NOTE] + > This was originally intended as a pull request, but the git push operation failed. + > + > **Workflow Run:** [View run details and download patch artifact](${runUrl}) + > + > The patch file is available as an artifact (\`aw.patch\`) in the workflow run linked above. + To apply the patch locally: + \`\`\`sh + # Download the artifact from the workflow run ${runUrl} + # (Use GitHub MCP tools if gh CLI is not available) + gh run download ${runId} -n aw.patch + # Apply the patch + git am aw.patch + \`\`\` + ${patchPreview}`; + try { + const { data: issue } = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: title, + body: fallbackBody, + labels: labels, + }); + core.info(`Created fallback issue #${issue.number}: ${issue.html_url}`); + await updateActivationComment(github, context, core, issue.html_url, issue.number, "issue"); + core.setOutput("issue_number", issue.number); + core.setOutput("issue_url", issue.html_url); + core.setOutput("branch_name", branchName); + core.setOutput("fallback_used", "true"); + core.setOutput("push_failed", "true"); + await core.summary + .addRaw( + ` + ## Push Failure Fallback + - **Push Error:** ${pushError instanceof Error ? pushError.message : String(pushError)} + - **Fallback Issue:** [#${issue.number}](${issue.html_url}) + - **Patch Artifact:** Available in workflow run artifacts + - **Note:** Push failed, created issue as fallback + ` + ) + .write(); + return; + } catch (issueError) { + core.setFailed( + `Failed to push and failed to create fallback issue. Push error: ${pushError instanceof Error ? pushError.message : String(pushError)}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}` + ); + return; + } + } + } else { + core.info("Skipping patch application (empty patch)"); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); + return; } } else { - const contextRepo = `${context.repo.owner}/${context.repo.repo}`; - if (itemRepo === contextRepo) { - effectiveParentIssueNumber = parentIssueNumber; + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; } } - core.info( - `Debug: effectiveParentIssueNumber = ${JSON.stringify(effectiveParentIssueNumber)}, effectiveParentRepo = ${effectiveParentRepo}` - ); - if (effectiveParentIssueNumber && createIssueItem.parent !== undefined) { - core.info(`Using explicit parent issue number from item: ${effectiveParentRepo}#${effectiveParentIssueNumber}`); - } - let labels = [...envLabels]; - if (createIssueItem.labels && Array.isArray(createIssueItem.labels)) { - labels = [...labels, ...createIssueItem.labels]; - } - labels = labels - .filter(label => !!label) - .map(label => String(label).trim()) - .filter(label => label) - .map(label => sanitizeLabelContent(label)) - .filter(label => label) - .map(label => (label.length > 64 ? label.substring(0, 64) : label)) - .filter((label, index, arr) => arr.indexOf(label) === index); - let title = createIssueItem.title ? createIssueItem.title.trim() : ""; - let processedBody = replaceTemporaryIdReferences(createIssueItem.body, temporaryIdMap, itemRepo); - let bodyLines = processedBody.split("\n"); - if (!title) { - title = createIssueItem.body || "Agent Output"; - } - const titlePrefix = process.env.GH_AW_ISSUE_TITLE_PREFIX; - if (titlePrefix && !title.startsWith(titlePrefix)) { - title = titlePrefix + title; - } - if (effectiveParentIssueNumber) { - core.info("Detected issue context, parent issue " + effectiveParentRepo + "#" + effectiveParentIssueNumber); - if (effectiveParentRepo === itemRepo) { - bodyLines.push(`Related to #${effectiveParentIssueNumber}`); - } else { - bodyLines.push(`Related to ${effectiveParentRepo}#${effectiveParentIssueNumber}`); - } + } + try { + const { data: pullRequest } = await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: title, + body: body, + head: branchName, + base: baseBranch, + draft: draft, + }); + core.info(`Created pull request #${pullRequest.number}: ${pullRequest.html_url}`); + if (labels.length > 0) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pullRequest.number, + labels: labels, + }); + core.info(`Added labels to pull request: ${JSON.stringify(labels)}`); } - const workflowName = process.env.GH_AW_WORKFLOW_NAME || "Workflow"; - const workflowSource = process.env.GH_AW_WORKFLOW_SOURCE || ""; - const workflowSourceURL = process.env.GH_AW_WORKFLOW_SOURCE_URL || ""; - const runId = context.runId; + core.setOutput("pull_request_number", pullRequest.number); + core.setOutput("pull_request_url", pullRequest.html_url); + core.setOutput("branch_name", branchName); + await updateActivationComment(github, context, core, pullRequest.html_url, pullRequest.number); + await core.summary + .addRaw( + ` + ## Pull Request + - **Pull Request**: [#${pullRequest.number}](${pullRequest.html_url}) + - **Branch**: \`${branchName}\` + - **Base Branch**: \`${baseBranch}\` + ` + ) + .write(); + } catch (prError) { + core.warning(`Failed to create pull request: ${prError instanceof Error ? prError.message : String(prError)}`); + core.info("Falling back to creating an issue instead"); const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com"; - const runUrl = context.payload.repository - ? `${context.payload.repository.html_url}/actions/runs/${runId}` - : `${githubServer}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; - const trackerIDComment = getTrackerID("markdown"); - if (trackerIDComment) { - bodyLines.push(trackerIDComment); - } - addExpirationComment(bodyLines, "GH_AW_ISSUE_EXPIRES", "Issue"); - bodyLines.push( - ``, - ``, - generateFooter( - workflowName, - runUrl, - workflowSource, - workflowSourceURL, - triggeringIssueNumber, - triggeringPRNumber, - triggeringDiscussionNumber - ).trimEnd(), - "" - ); - const body = bodyLines.join("\n").trim(); - core.info(`Creating issue in ${itemRepo} with title: ${title}`); - core.info(`Labels: ${labels}`); - core.info(`Body length: ${body.length}`); + const branchUrl = context.payload.repository + ? `${context.payload.repository.html_url}/tree/${branchName}` + : `${githubServer}/${context.repo.owner}/${context.repo.repo}/tree/${branchName}`; + let patchPreview = ""; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + patchPreview = generatePatchPreview(patchContent); + } + const fallbackBody = `${body} + --- + **Note:** This was originally intended as a pull request, but PR creation failed. The changes have been pushed to the branch [\`${branchName}\`](${branchUrl}). + **Original error:** ${prError instanceof Error ? prError.message : String(prError)} + You can manually create a pull request from the branch if needed.${patchPreview}`; try { const { data: issue } = await github.rest.issues.create({ - owner: repoParts.owner, - repo: repoParts.repo, + owner: context.repo.owner, + repo: context.repo.repo, title: title, - body: body, + body: fallbackBody, labels: labels, }); - core.info(`Created issue ${itemRepo}#${issue.number}: ${issue.html_url}`); - createdIssues.push({ ...issue, _repo: itemRepo }); - temporaryIdMap.set(normalizeTemporaryId(temporaryId), { repo: itemRepo, number: issue.number }); - core.info(`Stored temporary ID mapping: ${temporaryId} -> ${itemRepo}#${issue.number}`); - core.info(`Debug: About to check if sub-issue linking is needed. effectiveParentIssueNumber = ${effectiveParentIssueNumber}`); - if (effectiveParentIssueNumber && effectiveParentRepo === itemRepo) { - core.info(`Attempting to link issue #${issue.number} as sub-issue of #${effectiveParentIssueNumber}`); - try { - core.info(`Fetching node ID for parent issue #${effectiveParentIssueNumber}...`); - const getIssueNodeIdQuery = ` - query($owner: String!, $repo: String!, $issueNumber: Int!) { - repository(owner: $owner, name: $repo) { - issue(number: $issueNumber) { - id - } - } - } - `; - const parentResult = await github.graphql(getIssueNodeIdQuery, { - owner: repoParts.owner, - repo: repoParts.repo, - issueNumber: effectiveParentIssueNumber, - }); - const parentNodeId = parentResult.repository.issue.id; - core.info(`Parent issue node ID: ${parentNodeId}`); - core.info(`Fetching node ID for child issue #${issue.number}...`); - const childResult = await github.graphql(getIssueNodeIdQuery, { - owner: repoParts.owner, - repo: repoParts.repo, - issueNumber: issue.number, - }); - const childNodeId = childResult.repository.issue.id; - core.info(`Child issue node ID: ${childNodeId}`); - core.info(`Executing addSubIssue mutation...`); - const addSubIssueMutation = ` - mutation($issueId: ID!, $subIssueId: ID!) { - addSubIssue(input: { - issueId: $issueId, - subIssueId: $subIssueId - }) { - subIssue { - id - number - } - } - } - `; - await github.graphql(addSubIssueMutation, { - issueId: parentNodeId, - subIssueId: childNodeId, - }); - core.info("āœ“ Successfully linked issue #" + issue.number + " as sub-issue of #" + effectiveParentIssueNumber); - } catch (error) { - core.info(`Warning: Could not link sub-issue to parent: ${error instanceof Error ? error.message : String(error)}`); - core.info(`Error details: ${error instanceof Error ? error.stack : String(error)}`); - try { - core.info(`Attempting fallback: adding comment to parent issue #${effectiveParentIssueNumber}...`); - await github.rest.issues.createComment({ - owner: repoParts.owner, - repo: repoParts.repo, - issue_number: effectiveParentIssueNumber, - body: `Created related issue: #${issue.number}`, - }); - core.info("āœ“ Added comment to parent issue #" + effectiveParentIssueNumber + " (sub-issue linking not available)"); - } catch (commentError) { - core.info( - `Warning: Could not add comment to parent issue: ${commentError instanceof Error ? commentError.message : String(commentError)}` - ); - } - } - } else if (effectiveParentIssueNumber && effectiveParentRepo !== itemRepo) { - core.info(`Skipping sub-issue linking: parent is in different repository (${effectiveParentRepo})`); - } else { - core.info(`Debug: No parent issue number set, skipping sub-issue linking`); - } - if (i === createIssueItems.length - 1) { - core.setOutput("issue_number", issue.number); - core.setOutput("issue_url", issue.html_url); - } - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - if (errorMessage.includes("Issues has been disabled in this repository")) { - core.info(`⚠ Cannot create issue "${title}" in ${itemRepo}: Issues are disabled for this repository`); - core.info("Consider enabling issues in repository settings if you want to create issues automatically"); - continue; - } - core.error(`āœ— Failed to create issue "${title}" in ${itemRepo}: ${errorMessage}`); - throw error; - } - } - if (createdIssues.length > 0) { - let summaryContent = "\n\n## GitHub Issues\n"; - for (const issue of createdIssues) { - const repoLabel = issue._repo !== defaultTargetRepo ? ` (${issue._repo})` : ""; - summaryContent += `- Issue #${issue.number}${repoLabel}: [${issue.title}](${issue.html_url})\n`; + core.info(`Created fallback issue #${issue.number}: ${issue.html_url}`); + await updateActivationComment(github, context, core, issue.html_url, issue.number, "issue"); + core.setOutput("issue_number", issue.number); + core.setOutput("issue_url", issue.html_url); + core.setOutput("branch_name", branchName); + core.setOutput("fallback_used", "true"); + await core.summary + .addRaw( + ` + ## Fallback Issue Created + - **Issue**: [#${issue.number}](${issue.html_url}) + - **Branch**: [\`${branchName}\`](${branchUrl}) + - **Base Branch**: \`${baseBranch}\` + - **Note**: Pull request creation failed, created issue as fallback + ` + ) + .write(); + } catch (issueError) { + core.setFailed( + `Failed to create both pull request and fallback issue. PR error: ${prError instanceof Error ? prError.message : String(prError)}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}` + ); + return; } - await core.summary.addRaw(summaryContent).write(); - } - const tempIdMapOutput = serializeTemporaryIdMap(temporaryIdMap); - core.setOutput("temporary_id_map", tempIdMapOutput); - core.info(`Temporary ID map: ${tempIdMapOutput}`); - const assignCopilot = process.env.GH_AW_ASSIGN_COPILOT === "true"; - if (assignCopilot && createdIssues.length > 0) { - const issuesToAssign = createdIssues.map(issue => `${issue._repo}:${issue.number}`).join(","); - core.setOutput("issues_to_assign_copilot", issuesToAssign); - core.info(`Issues to assign copilot: ${issuesToAssign}`); } - core.info(`Successfully created ${createdIssues.length} issue(s)`); } - (async () => { - await main(); - })(); + await main(); detection: needs: agent @@ -7524,7 +7606,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: WORKFLOW_NAME: "Dev" - WORKFLOW_DESCRIPTION: "Create a poem about GitHub and save it to repo-memory" + WORKFLOW_DESCRIPTION: "Create an empty pull request for agent to push changes to" with: script: | const fs = require('fs'); diff --git a/.github/workflows/dev.md b/.github/workflows/dev.md index ab15ccc1ca..7ea30ca9f0 100644 --- a/.github/workflows/dev.md +++ b/.github/workflows/dev.md @@ -2,7 +2,7 @@ on: workflow_dispatch: name: Dev -description: Create a poem about GitHub and save it to repo-memory +description: Create an empty pull request for agent to push changes to timeout-minutes: 5 strict: false engine: copilot @@ -16,7 +16,8 @@ tools: imports: - shared/gh.md safe-outputs: - create-issue: + create-pull-request: + allow-empty: true staged: true steps: - name: Download issues data @@ -26,5 +27,8 @@ steps: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} --- -Read the last pull request using `githubissues-gh` tool -and create an issue with the summary. +Create an empty pull request that prepares a branch for future changes. +The pull request should have: +- Title: "Feature: Prepare branch for agent updates" +- Body: "This is an empty pull request created to prepare a feature branch that an agent can push changes to later." +- Branch name: "feature/agent-updates" diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 73d7055863..37807751b1 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -7584,6 +7584,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Developer Documentation Consolidator" GH_AW_ENGINE_ID: "claude" @@ -7767,52 +7768,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -7833,7 +7849,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -7849,6 +7865,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -8058,16 +8076,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 5d6f48da2f..6eaf0e7dd5 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -6110,6 +6110,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Dictation Prompt Generator" GH_AW_ENGINE_ID: "copilot" @@ -6293,52 +6294,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6359,7 +6375,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6375,6 +6391,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6584,16 +6602,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index dc7a6b597b..86691705f9 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -7287,6 +7287,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "GitHub MCP Remote Server Tools Report Generator" GH_AW_ENGINE_ID: "claude" @@ -7470,52 +7471,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -7536,7 +7552,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -7552,6 +7568,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -7761,16 +7779,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index 1f61d09d4b..4e768e201a 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -7275,6 +7275,7 @@ jobs: GH_AW_PR_LABELS: "documentation,glossary" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Glossary Maintainer" GH_AW_ENGINE_ID: "copilot" @@ -7458,52 +7459,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -7524,7 +7540,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -7540,6 +7556,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -7749,16 +7767,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 1b6ab1fe97..b1b8444e41 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -5892,6 +5892,7 @@ jobs: GH_AW_PR_LABELS: "enhancement,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Go Logger Enhancement" GH_AW_ENGINE_ID: "claude" @@ -6075,52 +6076,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6141,7 +6157,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6157,6 +6173,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6366,16 +6384,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 8c93021139..3ce4508508 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -5657,6 +5657,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation,instructions" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Instructions Janitor" GH_AW_ENGINE_ID: "claude" @@ -5840,52 +5841,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -5906,7 +5922,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -5922,6 +5938,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6131,16 +6149,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index 9010cecbe3..9f804be9da 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -6404,6 +6404,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Layout Specification Maintainer" GH_AW_TRACKER_ID: "layout-spec-maintainer" @@ -6588,52 +6589,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6654,7 +6670,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6670,6 +6686,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6879,16 +6897,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 5050c8e9a5..e0b22c8b2b 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -10658,6 +10658,7 @@ jobs: GH_AW_PR_LABELS: "poetry,automation,creative-writing" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} @@ -10846,52 +10847,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -10912,7 +10928,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -10928,6 +10944,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -11137,16 +11155,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index fcb8e104b1..a88c260f43 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -8215,6 +8215,7 @@ jobs: GH_AW_PR_LABELS: "automation,workflow-optimization" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "ignore" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} @@ -8401,52 +8402,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -8467,7 +8483,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -8483,6 +8499,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -8692,16 +8710,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 11147835a8..f369cb4dcd 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -5665,6 +5665,7 @@ jobs: GH_AW_PR_LABELS: "security,automated-fix" GH_AW_PR_DRAFT: "true" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Security Fix PR" GH_AW_ENGINE_ID: "claude" @@ -5848,52 +5849,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -5914,7 +5930,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -5930,6 +5946,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6139,16 +6157,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/spec-kit-execute.lock.yml b/.github/workflows/spec-kit-execute.lock.yml index 963d31625b..d51ed39039 100644 --- a/.github/workflows/spec-kit-execute.lock.yml +++ b/.github/workflows/spec-kit-execute.lock.yml @@ -6732,6 +6732,7 @@ jobs: GH_AW_PR_LABELS: "spec-kit,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Spec-Kit Execute" GH_AW_TRACKER_ID: "spec-kit-execute" @@ -6916,52 +6917,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6982,7 +6998,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6998,6 +7014,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -7207,16 +7225,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/spec-kit-executor.lock.yml b/.github/workflows/spec-kit-executor.lock.yml index 9b2c7cc611..4cc0f6b12d 100644 --- a/.github/workflows/spec-kit-executor.lock.yml +++ b/.github/workflows/spec-kit-executor.lock.yml @@ -6422,6 +6422,7 @@ jobs: GH_AW_PR_LABELS: "spec-kit,automation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Spec Kit Executor" GH_AW_TRACKER_ID: "spec-kit-executor" @@ -6606,52 +6607,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6672,7 +6688,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6688,6 +6704,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6897,16 +6915,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index a281e4a797..3d31a4ae20 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -7474,6 +7474,7 @@ jobs: GH_AW_PR_LABELS: "documentation" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_WORKFLOW_NAME: "Technical Doc Writer" GH_AW_ENGINE_ID: "copilot" @@ -7658,52 +7659,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -7724,7 +7740,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -7740,6 +7756,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -7949,16 +7967,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 8452b43a15..338d6a30da 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -6518,6 +6518,7 @@ jobs: GH_AW_PR_LABELS: "automation,maintenance" GH_AW_PR_DRAFT: "false" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} @@ -6703,52 +6704,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -6769,7 +6785,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -6785,6 +6801,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -6994,16 +7012,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index e1be373962..eb4470d995 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -7277,6 +7277,7 @@ jobs: GH_AW_PR_LABELS: "documentation,automation" GH_AW_PR_DRAFT: "true" GH_AW_PR_IF_NO_CHANGES: "warn" + GH_AW_PR_ALLOW_EMPTY: "false" GH_AW_MAX_PATCH_SIZE: 1024 GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} @@ -7463,52 +7464,67 @@ jobs: core.info("Agent output content is empty"); } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); @@ -7529,7 +7545,7 @@ jobs: } core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { case "error": @@ -7545,6 +7561,8 @@ jobs: core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -7754,16 +7772,44 @@ jobs: } } else { core.info("Skipping patch application (empty patch)"); - const message = "No changes to apply - noop operation completed successfully"; - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - return; - case "warn": - default: - core.warning(message); + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + try { + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + const message = "No changes to apply - noop operation completed successfully"; + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + return; + case "warn": + default: + core.warning(message); + return; + } } } try { diff --git a/pkg/cli/templates/github-agentic-workflows.md b/pkg/cli/templates/github-agentic-workflows.md index 13ddf594f4..0b3df484a9 100644 --- a/pkg/cli/templates/github-agentic-workflows.md +++ b/pkg/cli/templates/github-agentic-workflows.md @@ -392,11 +392,11 @@ The YAML frontmatter supports these fields: target-repo: "owner/repo" # Optional: cross-repository ``` When using `safe-outputs.close-pull-request`, the main job does **not** need `pull-requests: write` permission since PR closing is handled by a separate job with appropriate permissions. - - `add-labels:` - Safe label addition to issues or PRs. Labels will be created if they don't already exist in the repository. + - `add-labels:` - Safe label addition to issues or PRs ```yaml safe-outputs: add-labels: - allowed: [bug, enhancement, documentation] # Optional: restrict to specific labels (will be created if missing) + allowed: [bug, enhancement, documentation] # Optional: restrict to specific labels max: 3 # Optional: maximum number of labels (default: 3) target: "*" # Optional: "triggering" (default), "*" (any issue/PR), or number target-repo: "owner/repo" # Optional: cross-repository diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index 49bcb62eeb..15d501d8a9 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -3552,6 +3552,10 @@ "enum": ["warn", "error", "ignore"], "description": "Behavior when no changes to push: 'warn' (default - log warning but succeed), 'error' (fail the action), or 'ignore' (silent success)" }, + "allow-empty": { + "type": "boolean", + "description": "When true, allows creating a pull request without any initial changes or git patch. This is useful for preparing a feature branch that an agent can push changes to later. The branch will be created from the base branch without applying any patch. Defaults to false." + }, "target-repo": { "type": "string", "description": "Target repository in format 'owner/repo' for cross-repository pull request creation. Takes precedence over trial target repo settings." diff --git a/pkg/workflow/create_pull_request.go b/pkg/workflow/create_pull_request.go index b25ab32048..911df2d534 100644 --- a/pkg/workflow/create_pull_request.go +++ b/pkg/workflow/create_pull_request.go @@ -18,6 +18,7 @@ type CreatePullRequestsConfig struct { Reviewers []string `yaml:"reviewers,omitempty"` // List of users/bots to assign as reviewers to the pull request Draft *bool `yaml:"draft,omitempty"` // Pointer to distinguish between unset (nil) and explicitly false IfNoChanges string `yaml:"if-no-changes,omitempty"` // Behavior when no changes to push: "warn" (default), "error", or "ignore" + AllowEmpty bool `yaml:"allow-empty,omitempty"` // Allow creating PR without patch file or with empty patch (useful for preparing feature branches) TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository in format "owner/repo" for cross-repository pull requests Expires int `yaml:"expires,omitempty"` // Days until the pull request expires and should be automatically closed (only for same-repo PRs) } @@ -77,6 +78,9 @@ func (c *Compiler) buildCreateOutputPullRequestJob(data *WorkflowData, mainJobNa } customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_PR_IF_NO_CHANGES: %q\n", ifNoChanges)) + // Pass the allow-empty configuration + customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_PR_ALLOW_EMPTY: %q\n", fmt.Sprintf("%t", data.SafeOutputs.CreatePullRequests.AllowEmpty))) + // Pass the maximum patch size configuration maxPatchSize := 1024 // Default value if data.SafeOutputs != nil && data.SafeOutputs.MaximumPatchSize > 0 { @@ -185,6 +189,13 @@ func (c *Compiler) parsePullRequestsConfig(outputMap map[string]any) *CreatePull } } + // Parse allow-empty + if allowEmpty, exists := configMap["allow-empty"]; exists { + if allowEmptyBool, ok := allowEmpty.(bool); ok { + pullRequestsConfig.AllowEmpty = allowEmptyBool + } + } + // Parse target-repo using shared helper with validation targetRepoSlug, isInvalid := parseTargetRepoWithValidation(configMap) if isInvalid { diff --git a/pkg/workflow/js/create_pull_request.cjs b/pkg/workflow/js/create_pull_request.cjs index 3f4fcf58b5..d490b96ea8 100644 --- a/pkg/workflow/js/create_pull_request.cjs +++ b/pkg/workflow/js/create_pull_request.cjs @@ -82,71 +82,89 @@ async function main() { } const ifNoChanges = process.env.GH_AW_PR_IF_NO_CHANGES || "warn"; + const allowEmpty = (process.env.GH_AW_PR_ALLOW_EMPTY || "false").toLowerCase() === "true"; // Check if patch file exists and has valid content if (!fs.existsSync("/tmp/gh-aw/aw.patch")) { - const message = "No patch file found - cannot create pull request without changes"; - - // If in staged mode, still show preview - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø No patch file found\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - - // Write to step summary - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); - return; - } + // If allow-empty is enabled, we can proceed without a patch file + if (allowEmpty) { + core.info("No patch file found, but allow-empty is enabled - will create empty PR"); + } else { + const message = "No patch file found - cannot create pull request without changes"; - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - // Silent success - no console output - return; - case "warn": - default: - core.warning(message); + // If in staged mode, still show preview + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø No patch file found\n\n`; + summaryContent += `**Message:** ${message}\n\n`; + + // Write to step summary + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (no patch file)"); return; + } + + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + // Silent success - no console output + return; + case "warn": + default: + core.warning(message); + return; + } } } - const patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + let patchContent = ""; + let isEmpty = true; + + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { + patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); + isEmpty = !patchContent || !patchContent.trim(); + } // Check for actual error conditions (but allow empty patches as valid noop) if (patchContent.includes("Failed to generate patch")) { - const message = "Patch file contains error message - cannot create pull request without changes"; - - // If in staged mode, still show preview - if (isStaged) { - let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; - summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; - summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; - summaryContent += `**Message:** ${message}\n\n`; - - // Write to step summary - await core.summary.addRaw(summaryContent).write(); - core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); - return; - } + // If allow-empty is enabled, ignore patch errors and proceed + if (allowEmpty) { + core.info("Patch file contains error, but allow-empty is enabled - will create empty PR"); + patchContent = ""; + isEmpty = true; + } else { + const message = "Patch file contains error message - cannot create pull request without changes"; + + // If in staged mode, still show preview + if (isStaged) { + let summaryContent = "## šŸŽ­ Staged Mode: Create Pull Request Preview\n\n"; + summaryContent += "The following pull request would be created if staged mode was disabled:\n\n"; + summaryContent += `**Status:** āš ļø Patch file contains error\n\n`; + summaryContent += `**Message:** ${message}\n\n`; - switch (ifNoChanges) { - case "error": - throw new Error(message); - case "ignore": - // Silent success - no console output - return; - case "warn": - default: - core.warning(message); + // Write to step summary + await core.summary.addRaw(summaryContent).write(); + core.info("šŸ“ Pull request creation preview written to step summary (patch error)"); return; + } + + switch (ifNoChanges) { + case "error": + throw new Error(message); + case "ignore": + // Silent success - no console output + return; + case "warn": + default: + core.warning(message); + return; + } } } // Validate patch size (unless empty) - const isEmpty = !patchContent || !patchContent.trim(); if (!isEmpty) { // Get maximum patch size from environment (default: 1MB = 1024 KB) const maxSizeKb = parseInt(process.env.GH_AW_MAX_PATCH_SIZE || "1024", 10); @@ -176,7 +194,8 @@ async function main() { core.info("Patch size validation passed"); } - if (isEmpty && !isStaged) { + + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; switch (ifNoChanges) { @@ -195,6 +214,8 @@ async function main() { core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); + } else if (allowEmpty) { + core.info("Patch file is empty - processing empty PR creation (allow-empty is enabled)"); } else { core.info("Patch file is empty - processing noop operation"); } @@ -487,19 +508,53 @@ ${patchPreview}`; } else { core.info("Skipping patch application (empty patch)"); - // For empty patches, handle if-no-changes configuration - const message = "No changes to apply - noop operation completed successfully"; + // For empty patches with allow-empty, we still need to push the branch + if (allowEmpty) { + core.info("allow-empty is enabled - will create branch and push without changes"); + // Push the branch without any changes + try { + // Check if remote branch already exists (optional precheck) + let remoteBranchExists = false; + try { + const { stdout } = await exec.getExecOutput(`git ls-remote --heads origin ${branchName}`); + if (stdout.trim()) { + remoteBranchExists = true; + } + } catch (checkError) { + core.info(`Remote branch check failed (non-fatal): ${checkError instanceof Error ? checkError.message : String(checkError)}`); + } - switch (ifNoChanges) { - case "error": - throw new Error("No changes to apply - failing as configured by if-no-changes: error"); - case "ignore": - // Silent success - no console output - return; - case "warn": - default: - core.warning(message); + if (remoteBranchExists) { + core.warning(`Remote branch ${branchName} already exists - appending random suffix`); + const extraHex = crypto.randomBytes(4).toString("hex"); + const oldBranch = branchName; + branchName = `${branchName}-${extraHex}`; + // Rename local branch + await exec.exec(`git branch -m ${oldBranch} ${branchName}`); + core.info(`Renamed branch to ${branchName}`); + } + + await exec.exec(`git push origin ${branchName}`); + core.info("Empty branch pushed successfully"); + } catch (pushError) { + core.setFailed(`Failed to push empty branch: ${pushError instanceof Error ? pushError.message : String(pushError)}`); return; + } + } else { + // For empty patches without allow-empty, handle if-no-changes configuration + const message = "No changes to apply - noop operation completed successfully"; + + switch (ifNoChanges) { + case "error": + throw new Error("No changes to apply - failing as configured by if-no-changes: error"); + case "ignore": + // Silent success - no console output + return; + case "warn": + default: + core.warning(message); + return; + } } } From 8ed06d261ff29bc0d50816d083940d3dc606e2e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:48:32 +0000 Subject: [PATCH 4/7] chore: Apply code formatting from make fmt Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/parser/schedule_parser.go | 38 ++++----- pkg/parser/schedule_parser_fuzz_test.go | 104 ++++++++++++------------ pkg/parser/schedule_parser_test.go | 8 +- pkg/workflow/js/create_pull_request.cjs | 4 +- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/pkg/parser/schedule_parser.go b/pkg/parser/schedule_parser.go index d0b713d9a8..542a20d80e 100644 --- a/pkg/parser/schedule_parser.go +++ b/pkg/parser/schedule_parser.go @@ -105,15 +105,15 @@ func (p *ScheduleParser) parseInterval() (string, error) { if len(p.tokens) == 2 || (len(p.tokens) > 2 && p.tokens[2] != "minutes" && p.tokens[2] != "hours" && p.tokens[2] != "minute" && p.tokens[2] != "hour") { // Try to parse as short duration format: "every 2h", "every 30m", "every 1d" durationStr := p.tokens[1] - + // Check if it matches the pattern: number followed by unit letter (h, m, d, w, mo) durationPattern := regexp.MustCompile(`^(\d+)([hdwm]|mo)$`) matches := durationPattern.FindStringSubmatch(durationStr) - + if matches != nil { interval, _ := strconv.Atoi(matches[1]) unit := matches[2] - + // Check for conflicting "at time" clause if len(p.tokens) > 2 { for i := 2; i < len(p.tokens); i++ { @@ -122,7 +122,7 @@ func (p *ScheduleParser) parseInterval() (string, error) { } } } - + // Validate minimum duration of 5 minutes totalMinutes := 0 switch unit { @@ -137,11 +137,11 @@ func (p *ScheduleParser) parseInterval() (string, error) { case "mo": totalMinutes = interval * 30 * 24 * 60 // Approximate month as 30 days } - + if totalMinutes < 5 { return "", fmt.Errorf("minimum schedule interval is 5 minutes, got %d minute(s)", totalMinutes) } - + switch unit { case "m": // every Nm -> */N * * * * @@ -221,7 +221,7 @@ func (p *ScheduleParser) parseInterval() (string, error) { case "hours": totalMinutes = interval * 60 } - + if totalMinutes < 5 { return "", fmt.Errorf("minimum schedule interval is 5 minutes, got %d minute(s)", totalMinutes) } @@ -332,7 +332,7 @@ func (p *ScheduleParser) extractTime(startPos int) (string, error) { } timeStr := p.tokens[startPos] - + // Check if there's a UTC offset in the next token if startPos+1 < len(p.tokens) { nextToken := strings.ToLower(p.tokens[startPos+1]) @@ -341,7 +341,7 @@ func (p *ScheduleParser) extractTime(startPos int) (string, error) { timeStr = timeStr + " " + p.tokens[startPos+1] } } - + return timeStr, nil } @@ -352,11 +352,11 @@ func parseTime(timeStr string) (minute string, hour string) { parts := strings.Split(timeStr, " ") var utcOffset int = 0 var baseTime string - + if len(parts) == 2 && strings.HasPrefix(strings.ToLower(parts[1]), "utc") { baseTime = parts[0] offsetStr := strings.ToLower(parts[1]) - + // Parse UTC offset (e.g., utc+9, utc-5, utc+09:00, utc-05:30) if len(offsetStr) > 3 { offsetPart := offsetStr[3:] // Skip "utc" @@ -367,7 +367,7 @@ func parseTime(timeStr string) (minute string, hour string) { sign = -1 offsetPart = offsetPart[1:] } - + // Check if it's HH:MM format if strings.Contains(offsetPart, ":") { offsetParts := strings.Split(offsetPart, ":") @@ -389,9 +389,9 @@ func parseTime(timeStr string) (minute string, hour string) { } else { baseTime = timeStr } - + var baseMinute, baseHour int - + switch baseTime { case "midnight": baseMinute, baseHour = 0, 0 @@ -404,7 +404,7 @@ func parseTime(timeStr string) (minute string, hour string) { isPM := strings.HasSuffix(lowerTime, "pm") // Remove am/pm suffix hourStr := lowerTime[:len(lowerTime)-2] - + hourNum, err := strconv.Atoi(hourStr) if err == nil && hourNum >= 1 && hourNum <= 12 { // Convert 12-hour to 24-hour format @@ -447,11 +447,11 @@ func parseTime(timeStr string) (minute string, hour string) { } } } - + // Apply UTC offset (convert from local time to UTC) // If utc+9, we subtract 9 hours to get UTC time totalMinutes := baseHour*60 + baseMinute - utcOffset - + // Handle wrap-around (keep within 0-1439 minutes, which is 0:00-23:59) for totalMinutes < 0 { totalMinutes += 24 * 60 @@ -459,10 +459,10 @@ func parseTime(timeStr string) (minute string, hour string) { for totalMinutes >= 24*60 { totalMinutes -= 24 * 60 } - + finalHour := totalMinutes / 60 finalMinute := totalMinutes % 60 - + return strconv.Itoa(finalMinute), strconv.Itoa(finalHour) } diff --git a/pkg/parser/schedule_parser_fuzz_test.go b/pkg/parser/schedule_parser_fuzz_test.go index d584d489eb..0c193616cc 100644 --- a/pkg/parser/schedule_parser_fuzz_test.go +++ b/pkg/parser/schedule_parser_fuzz_test.go @@ -18,26 +18,26 @@ import ( // 7. Minimum duration validation works correctly func FuzzScheduleParser(f *testing.F) { // Seed corpus with valid schedule expressions - + // Daily schedules f.Add("daily") f.Add("daily at 02:00") f.Add("daily at midnight") f.Add("daily at noon") f.Add("daily at 09:30") - + // Weekly schedules f.Add("weekly on monday") f.Add("weekly on monday at 06:30") f.Add("weekly on friday at 17:00") f.Add("weekly on sunday at midnight") - + // Monthly schedules f.Add("monthly on 1") f.Add("monthly on 15") f.Add("monthly on 15 at 09:00") f.Add("monthly on 31 at noon") - + // Interval schedules (long format) f.Add("every 10 minutes") f.Add("every 5 minutes") @@ -46,7 +46,7 @@ func FuzzScheduleParser(f *testing.F) { f.Add("every 2 hours") f.Add("every 6 hours") f.Add("every 12 hours") - + // Interval schedules (short duration format) f.Add("every 5m") f.Add("every 10m") @@ -60,7 +60,7 @@ func FuzzScheduleParser(f *testing.F) { f.Add("every 2w") f.Add("every 1mo") f.Add("every 2mo") - + // UTC offset schedules f.Add("daily at 02:00 utc+9") f.Add("daily at 14:00 utc-5") @@ -68,7 +68,7 @@ func FuzzScheduleParser(f *testing.F) { f.Add("weekly on monday at 08:00 utc+1") f.Add("monthly on 15 at 12:00 utc-8") f.Add("daily at 00:00 utc+0") - + // AM/PM time formats f.Add("daily at 3pm") f.Add("daily at 1am") @@ -87,26 +87,26 @@ func FuzzScheduleParser(f *testing.F) { f.Add("weekly on friday at 6pm utc-7") f.Add("monthly on 15 at 10am utc+2") f.Add("monthly on 1 at 7pm utc-3") - + // Valid cron expressions (passthrough) f.Add("0 0 * * *") f.Add("*/5 * * * *") f.Add("0 */2 * * *") f.Add("30 6 * * 1") f.Add("0 9 15 * *") - + // Case variations f.Add("DAILY") f.Add("Weekly On Monday") f.Add("MONTHLY ON 15") - + // Invalid schedules (should error gracefully) - + // Empty and whitespace f.Add("") f.Add(" ") f.Add("\t\n") - + // Below minimum duration f.Add("every 1m") f.Add("every 2m") @@ -114,54 +114,54 @@ func FuzzScheduleParser(f *testing.F) { f.Add("every 4m") f.Add("every 1 minute") f.Add("every 2 minutes") - + // Invalid interval with time conflict f.Add("every 10 minutes at 06:00") f.Add("every 2h at noon") - + // Invalid interval units f.Add("every 10 days") f.Add("every 2 weeks") f.Add("every 1 month") - + // Invalid numbers f.Add("every abc minutes") f.Add("every -5 minutes") f.Add("every 0 minutes") f.Add("every 1000000 hours") - + // Invalid weekly schedules f.Add("weekly monday") f.Add("weekly on funday") f.Add("weekly on 123") - + // Invalid monthly schedules f.Add("monthly 15") f.Add("monthly on abc") f.Add("monthly on 0") f.Add("monthly on 32") f.Add("monthly on -1") - + // Invalid time formats f.Add("daily at 25:00") f.Add("daily at 12:60") f.Add("daily at 12:30:45") f.Add("daily at abc") f.Add("daily at 12") - + // Invalid UTC offsets f.Add("daily at 12:00 utc+25") f.Add("daily at 12:00 utc-15") f.Add("daily at 12:00 utc+99:99") f.Add("daily at 12:00 utc") f.Add("daily at 12:00 utc+abc") - + // Unsupported schedule types f.Add("hourly") f.Add("yearly on 12/25") f.Add("biweekly") f.Add("quarterly") - + // Malformed expressions f.Add("daily at") f.Add("weekly on") @@ -169,13 +169,13 @@ func FuzzScheduleParser(f *testing.F) { f.Add("every") f.Add("every 10") f.Add("at 12:00") - + // Very long strings longString := strings.Repeat("a", 10000) f.Add(longString) f.Add("daily at " + longString) f.Add("every " + longString + " minutes") - + // Special characters f.Add("daily\x00at\x0012:00") f.Add("daily at 12:00\n\r") @@ -184,56 +184,56 @@ func FuzzScheduleParser(f *testing.F) { f.Add("daily at 12:00") f.Add("daily at 12:00$(whoami)") f.Add("daily at 12:00`id`") - + // Unicode characters f.Add("daily at 午前12Ꙃ") f.Add("ęÆę—„ at 12:00") f.Add("weekly on lundi") f.Add("ęÆŽé€±ęœˆę›œę—„ at 12:00") - + // Multiple spaces and tabs f.Add("daily at 12:00") f.Add("daily\tat\t12:00") f.Add("weekly on monday") f.Add("every 10 minutes") - + // Mixed valid/invalid patterns f.Add("daily at 12:00 weekly on monday") f.Add("every 5 minutes every 10 minutes") f.Add("daily daily") - + // Edge case numbers f.Add("every 2147483647 minutes") f.Add("monthly on 2147483647") f.Add("every -2147483648 hours") - + // Complex UTC offsets f.Add("daily at 12:00 utc+12:30") f.Add("daily at 12:00 utc-11:30") f.Add("daily at 12:00 utc+14") f.Add("daily at 12:00 utc-12") - + // Duplicate keywords f.Add("daily daily at 12:00") f.Add("weekly on monday on tuesday") f.Add("every every 10 minutes") - + // Cron-like but invalid f.Add("0 0 * *") f.Add("0 0 * * * *") f.Add("* * * * * *") f.Add("@daily") f.Add("@weekly") - + // Mixed case with invalid syntax f.Add("DaIlY aT 12:00") f.Add("WEEKLY ON MONDAY AT 12:00") - + // Run the fuzzer f.Fuzz(func(t *testing.T, input string) { // The parser should never panic, even on malformed input cron, original, err := ParseSchedule(input) - + // Basic sanity checks: // 1. Results should be consistent if err != nil { @@ -245,24 +245,24 @@ func FuzzScheduleParser(f *testing.F) { t.Errorf("ParseSchedule returned non-empty original '%s' with error: %v", original, err) } } - + // 2. If successful, cron should not be empty if err == nil && cron == "" { t.Errorf("ParseSchedule succeeded but returned empty cron for input: %q", input) } - + // 3. If error is returned, it should have a meaningful message if err != nil { if err.Error() == "" { t.Errorf("ParseSchedule returned error with empty message for input: %q", input) } - + // Error should not be generic if err.Error() == "error" { t.Errorf("ParseSchedule returned generic 'error' message for input: %q", input) } } - + // 4. Validate cron expression format if successful if err == nil && cron != "" { // Cron should have 5 fields separated by spaces @@ -270,7 +270,7 @@ func FuzzScheduleParser(f *testing.F) { if len(fields) != 5 { t.Errorf("ParseSchedule returned invalid cron format with %d fields (expected 5): %q for input: %q", len(fields), cron, input) } - + // Each field should not be empty for i, field := range fields { if field == "" { @@ -278,7 +278,7 @@ func FuzzScheduleParser(f *testing.F) { } } } - + // 5. If original is returned, it should match the input (after trimming) if original != "" && err == nil { // Original should be the input (for human-friendly formats) @@ -287,20 +287,20 @@ func FuzzScheduleParser(f *testing.F) { t.Errorf("ParseSchedule returned original '%s' that doesn't match input '%s'", original, input) } } - + // 6. Check for known invalid patterns that should error if shouldError(input) && err == nil { // This is informational - the fuzzer might find edge cases // where our simple check is wrong _ = err } - + // 7. Check for known valid patterns that should succeed if looksValid(input) && err != nil { // This is informational - the input might have subtle issues _ = err } - + // 8. Validate minimum duration for interval schedules if strings.HasPrefix(strings.ToLower(strings.TrimSpace(input)), "every") { if err == nil { @@ -320,17 +320,17 @@ func FuzzScheduleParser(f *testing.F) { // shouldError returns true if the input contains obvious invalid patterns func shouldError(input string) bool { input = strings.TrimSpace(input) - + // Empty input should error if input == "" { return true } - + // Control characters should likely error if strings.ContainsAny(input, "\x00\x01\x02\x03") { return true } - + // Minimum duration violations if strings.HasPrefix(strings.ToLower(input), "every 1m") || strings.HasPrefix(strings.ToLower(input), "every 2m") || @@ -342,32 +342,32 @@ func shouldError(input string) bool { strings.HasPrefix(strings.ToLower(input), "every 4 minute") { return true } - + // Known unsupported types if strings.HasPrefix(strings.ToLower(input), "yearly") || strings.HasPrefix(strings.ToLower(input), "hourly") { return true } - + return false } // looksValid returns true if the input looks like it might be valid func looksValid(input string) bool { input = strings.TrimSpace(strings.ToLower(input)) - + // Empty is not valid if input == "" { return false } - + // Check if it's a cron expression (5 fields) fields := strings.Fields(input) if len(fields) == 5 { // Could be a valid cron expression return true } - + // Check for valid patterns validPrefixes := []string{ "daily", @@ -386,12 +386,12 @@ func looksValid(input string) bool { "every 1 hour", "every 2 hours", } - + for _, prefix := range validPrefixes { if strings.HasPrefix(input, prefix) { return true } } - + return false } diff --git a/pkg/parser/schedule_parser_test.go b/pkg/parser/schedule_parser_test.go index 441da57434..049bcd8d5d 100644 --- a/pkg/parser/schedule_parser_test.go +++ b/pkg/parser/schedule_parser_test.go @@ -557,8 +557,8 @@ func TestParseTime(t *testing.T) { // AM/PM formats {"1am", "0", "1"}, {"3pm", "0", "15"}, - {"12am", "0", "0"}, // midnight - {"12pm", "0", "12"}, // noon + {"12am", "0", "0"}, // midnight + {"12pm", "0", "12"}, // noon {"11pm", "0", "23"}, {"6am", "0", "6"}, {"9am", "0", "9"}, @@ -569,8 +569,8 @@ func TestParseTime(t *testing.T) { {"25:00", "0", "0"}, {"12:60", "0", "0"}, {"12", "0", "0"}, - {"13pm", "0", "0"}, // invalid hour for 12-hour format - {"0am", "0", "0"}, // invalid hour for 12-hour format + {"13pm", "0", "0"}, // invalid hour for 12-hour format + {"0am", "0", "0"}, // invalid hour for 12-hour format } for _, tt := range tests { diff --git a/pkg/workflow/js/create_pull_request.cjs b/pkg/workflow/js/create_pull_request.cjs index d490b96ea8..c4d2f286d9 100644 --- a/pkg/workflow/js/create_pull_request.cjs +++ b/pkg/workflow/js/create_pull_request.cjs @@ -121,7 +121,7 @@ async function main() { let patchContent = ""; let isEmpty = true; - + if (fs.existsSync("/tmp/gh-aw/aw.patch")) { patchContent = fs.readFileSync("/tmp/gh-aw/aw.patch", "utf8"); isEmpty = !patchContent || !patchContent.trim(); @@ -194,7 +194,7 @@ async function main() { core.info("Patch size validation passed"); } - + if (isEmpty && !isStaged && !allowEmpty) { const message = "Patch file is empty - no changes to apply (noop operation)"; From 0612eaa278040e8503540b7bc44193c7dd1a77a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 15:54:01 +0000 Subject: [PATCH 5/7] test: Add tests for allow-empty pull request feature - Add TestCreatePullRequestJobWithAllowEmpty to verify GH_AW_PR_ALLOW_EMPTY is set to true - Add TestCreatePullRequestJobWithoutAllowEmpty to verify default behavior (false) - Include updated mcp-inspector.lock.yml from recompile Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/mcp-inspector.lock.yml | 2 +- .../create_pull_request_allow_empty_test.go | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 pkg/workflow/create_pull_request_allow_empty_test.go diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index de5d3d8cf8..ea517f7f84 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -2902,7 +2902,7 @@ jobs: To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls. - **Available tools**: create_discussion, missing_tool, noop, notion-add-comment, post-to-slack-channel + **Available tools**: create_discussion, missing_tool, noop, post-to-slack-channel, notion-add-comment **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped. diff --git a/pkg/workflow/create_pull_request_allow_empty_test.go b/pkg/workflow/create_pull_request_allow_empty_test.go new file mode 100644 index 0000000000..33e298b256 --- /dev/null +++ b/pkg/workflow/create_pull_request_allow_empty_test.go @@ -0,0 +1,65 @@ +package workflow + +import ( + "strings" + "testing" +) + +func TestCreatePullRequestJobWithAllowEmpty(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test with allow-empty configured + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: &SafeOutputsConfig{ + CreatePullRequests: &CreatePullRequestsConfig{ + AllowEmpty: true, + }, + }, + } + + job, err := c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building create pull request job: %v", err) + } + + // Convert steps to a single string for testing + stepsContent := strings.Join(job.Steps, "") + + // Check that GH_AW_PR_ALLOW_EMPTY environment variable is set + if !strings.Contains(stepsContent, `GH_AW_PR_ALLOW_EMPTY: "true"`) { + t.Error("Expected GH_AW_PR_ALLOW_EMPTY environment variable to be set to true") + } + + // Check that the JavaScript code includes allow-empty logic + if !strings.Contains(stepsContent, "allowEmpty") { + t.Error("Expected JavaScript code to include allowEmpty variable") + } +} + +func TestCreatePullRequestJobWithoutAllowEmpty(t *testing.T) { + // Create a compiler instance + c := NewCompiler(false, "", "test") + + // Test without allow-empty (default should be false) + workflowData := &WorkflowData{ + Name: "test-workflow", + SafeOutputs: &SafeOutputsConfig{ + CreatePullRequests: &CreatePullRequestsConfig{}, + }, + } + + job, err := c.buildCreateOutputPullRequestJob(workflowData, "main_job") + if err != nil { + t.Fatalf("Unexpected error building create pull request job: %v", err) + } + + // Convert steps to a single string for testing + stepsContent := strings.Join(job.Steps, "") + + // Check that GH_AW_PR_ALLOW_EMPTY environment variable is set to false + if !strings.Contains(stepsContent, `GH_AW_PR_ALLOW_EMPTY: "false"`) { + t.Error("Expected GH_AW_PR_ALLOW_EMPTY environment variable to be set to false by default") + } +} From 444708e314cb52dbab90218be294722bf17659e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 16:37:31 +0000 Subject: [PATCH 6/7] feat: Handle allow-empty in MCP server and collect ndjson output - Pass allow_empty config from Go to MCP server config - Update createHandlers to accept config parameter - Modify createPullRequestHandler to skip patch generation when allow-empty is true - Update collect_ndjson_output to check for allow-empty config and set has_patch=true when allow-empty is enabled even without a patch file - Recompile all workflows with updated safe output handling Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-moderator.lock.yml | 42 ++++++++++++++++-- .github/workflows/ai-triage-campaign.lock.yml | 42 ++++++++++++++++-- .github/workflows/archie.lock.yml | 42 ++++++++++++++++-- .github/workflows/artifacts-summary.lock.yml | 42 ++++++++++++++++-- .github/workflows/audit-workflows.lock.yml | 42 ++++++++++++++++-- .github/workflows/blog-auditor.lock.yml | 42 ++++++++++++++++-- .github/workflows/brave.lock.yml | 42 ++++++++++++++++-- .../breaking-change-checker.lock.yml | 42 ++++++++++++++++-- .github/workflows/changeset.lock.yml | 42 ++++++++++++++++-- .github/workflows/ci-doctor.lock.yml | 42 ++++++++++++++++-- .../cli-consistency-checker.lock.yml | 42 ++++++++++++++++-- .../workflows/cli-version-checker.lock.yml | 42 ++++++++++++++++-- .github/workflows/cloclo.lock.yml | 42 ++++++++++++++++-- .../workflows/close-old-discussions.lock.yml | 42 ++++++++++++++++-- .../commit-changes-analyzer.lock.yml | 42 ++++++++++++++++-- .../workflows/copilot-agent-analysis.lock.yml | 42 ++++++++++++++++-- .../copilot-pr-merged-report.lock.yml | 42 ++++++++++++++++-- .../copilot-pr-nlp-analysis.lock.yml | 42 ++++++++++++++++-- .../copilot-pr-prompt-analysis.lock.yml | 42 ++++++++++++++++-- .../copilot-session-insights.lock.yml | 42 ++++++++++++++++-- .github/workflows/craft.lock.yml | 42 ++++++++++++++++-- .../daily-assign-issue-to-user.lock.yml | 42 ++++++++++++++++-- .github/workflows/daily-code-metrics.lock.yml | 42 ++++++++++++++++-- .../daily-copilot-token-report.lock.yml | 42 ++++++++++++++++-- .github/workflows/daily-doc-updater.lock.yml | 42 ++++++++++++++++-- .github/workflows/daily-fact.lock.yml | 42 ++++++++++++++++-- .github/workflows/daily-file-diet.lock.yml | 42 ++++++++++++++++-- .../workflows/daily-firewall-report.lock.yml | 42 ++++++++++++++++-- .../workflows/daily-issues-report.lock.yml | 42 ++++++++++++++++-- .../daily-malicious-code-scan.lock.yml | 42 ++++++++++++++++-- .../daily-multi-device-docs-tester.lock.yml | 42 ++++++++++++++++-- .github/workflows/daily-news.lock.yml | 42 ++++++++++++++++-- .../daily-performance-summary.lock.yml | 42 ++++++++++++++++-- .../workflows/daily-repo-chronicle.lock.yml | 42 ++++++++++++++++-- .github/workflows/daily-team-status.lock.yml | 42 ++++++++++++++++-- .../workflows/daily-workflow-updater.lock.yml | 42 ++++++++++++++++-- .github/workflows/deep-report.lock.yml | 42 ++++++++++++++++-- .../workflows/dependabot-go-checker.lock.yml | 42 ++++++++++++++++-- .github/workflows/dev-hawk.lock.yml | 42 ++++++++++++++++-- .github/workflows/dev.lock.yml | 44 +++++++++++++++++-- .../developer-docs-consolidator.lock.yml | 42 ++++++++++++++++-- .github/workflows/dictation-prompt.lock.yml | 42 ++++++++++++++++-- .github/workflows/docs-noob-tester.lock.yml | 42 ++++++++++++++++-- .../duplicate-code-detector.lock.yml | 42 ++++++++++++++++-- .../example-workflow-analyzer.lock.yml | 42 ++++++++++++++++-- .../github-mcp-structural-analysis.lock.yml | 42 ++++++++++++++++-- .../github-mcp-tools-report.lock.yml | 42 ++++++++++++++++-- .../workflows/glossary-maintainer.lock.yml | 42 ++++++++++++++++-- .github/workflows/go-fan.lock.yml | 42 ++++++++++++++++-- .github/workflows/go-logger.lock.yml | 42 ++++++++++++++++-- .../workflows/go-pattern-detector.lock.yml | 42 ++++++++++++++++-- .github/workflows/grumpy-reviewer.lock.yml | 42 ++++++++++++++++-- .../workflows/instructions-janitor.lock.yml | 42 ++++++++++++++++-- .github/workflows/issue-arborist.lock.yml | 42 ++++++++++++++++-- .github/workflows/issue-classifier.lock.yml | 42 ++++++++++++++++-- .github/workflows/issue-monster.lock.yml | 42 ++++++++++++++++-- .github/workflows/issue-triage-agent.lock.yml | 42 ++++++++++++++++-- .../workflows/layout-spec-maintainer.lock.yml | 42 ++++++++++++++++-- .github/workflows/lockfile-stats.lock.yml | 42 ++++++++++++++++-- .github/workflows/mcp-inspector.lock.yml | 44 +++++++++++++++++-- .github/workflows/mergefest.lock.yml | 42 ++++++++++++++++-- .../workflows/notion-issue-summary.lock.yml | 42 ++++++++++++++++-- .github/workflows/org-health-report.lock.yml | 42 ++++++++++++++++-- .github/workflows/pdf-summary.lock.yml | 42 ++++++++++++++++-- .github/workflows/plan.lock.yml | 42 ++++++++++++++++-- .github/workflows/poem-bot.lock.yml | 42 ++++++++++++++++-- .github/workflows/portfolio-analyst.lock.yml | 42 ++++++++++++++++-- .../workflows/pr-nitpick-reviewer.lock.yml | 42 ++++++++++++++++-- .../prompt-clustering-analysis.lock.yml | 42 ++++++++++++++++-- .github/workflows/python-data-charts.lock.yml | 42 ++++++++++++++++-- .github/workflows/q.lock.yml | 42 ++++++++++++++++-- .github/workflows/release.lock.yml | 42 ++++++++++++++++-- .github/workflows/repo-tree-map.lock.yml | 42 ++++++++++++++++-- .../repository-quality-improver.lock.yml | 42 ++++++++++++++++-- .github/workflows/research.lock.yml | 42 ++++++++++++++++-- .github/workflows/safe-output-health.lock.yml | 42 ++++++++++++++++-- .../schema-consistency-checker.lock.yml | 42 ++++++++++++++++-- .github/workflows/scout.lock.yml | 42 ++++++++++++++++-- .github/workflows/security-fix-pr.lock.yml | 42 ++++++++++++++++-- .../semantic-function-refactor.lock.yml | 42 ++++++++++++++++-- .github/workflows/smoke-claude.lock.yml | 42 ++++++++++++++++-- .github/workflows/smoke-codex.lock.yml | 42 ++++++++++++++++-- .../smoke-copilot-no-firewall.lock.yml | 42 ++++++++++++++++-- .../smoke-copilot-playwright.lock.yml | 42 ++++++++++++++++-- .../smoke-copilot-safe-inputs.lock.yml | 42 ++++++++++++++++-- .github/workflows/smoke-copilot.lock.yml | 42 ++++++++++++++++-- .github/workflows/smoke-detector.lock.yml | 42 ++++++++++++++++-- .github/workflows/smoke-srt.lock.yml | 42 ++++++++++++++++-- .github/workflows/spec-kit-execute.lock.yml | 42 ++++++++++++++++-- .github/workflows/spec-kit-executor.lock.yml | 42 ++++++++++++++++-- .github/workflows/speckit-dispatcher.lock.yml | 42 ++++++++++++++++-- .../workflows/stale-repo-identifier.lock.yml | 42 ++++++++++++++++-- .../workflows/static-analysis-report.lock.yml | 42 ++++++++++++++++-- .github/workflows/super-linter.lock.yml | 42 ++++++++++++++++-- .../workflows/technical-doc-writer.lock.yml | 42 ++++++++++++++++-- .../test-discussion-expires.lock.yml | 42 ++++++++++++++++-- .../workflows/test-python-safe-input.lock.yml | 42 ++++++++++++++++-- .github/workflows/tidy.lock.yml | 42 ++++++++++++++++-- .github/workflows/typist.lock.yml | 42 ++++++++++++++++-- .github/workflows/unbloat-docs.lock.yml | 42 ++++++++++++++++-- .github/workflows/video-analyzer.lock.yml | 42 ++++++++++++++++-- .../workflows/weekly-issue-summary.lock.yml | 42 ++++++++++++++++-- pkg/workflow/js/collect_ndjson_output.cjs | 27 +++++++++++- pkg/workflow/js/safe_outputs_handlers.cjs | 26 ++++++++++- pkg/workflow/js/safe_outputs_mcp_server.cjs | 4 +- pkg/workflow/safe_outputs.go | 4 ++ 106 files changed, 4036 insertions(+), 313 deletions(-) diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index e72950a39d..33df27cf8c 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -2516,7 +2516,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2638,6 +2638,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2721,7 +2738,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4607,7 +4624,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index ec6366789b..500192f178 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -1497,7 +1497,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1619,6 +1619,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1702,7 +1719,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3514,7 +3531,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 4f212b96e3..1bc7eaade9 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -2984,7 +2984,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3106,6 +3106,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3189,7 +3206,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5175,7 +5192,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index c5fa07b779..89ac6104e1 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -1568,7 +1568,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1690,6 +1690,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1773,7 +1790,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3672,7 +3689,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 51f6b4a5ab..870d1e0b3c 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -2381,7 +2381,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2503,6 +2503,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2586,7 +2603,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5230,7 +5247,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index 514f62e961..8571b7fa23 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -1884,7 +1884,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2006,6 +2006,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2089,7 +2106,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4292,7 +4309,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 9fbb27add4..3039c24899 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -2869,7 +2869,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2991,6 +2991,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3074,7 +3091,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4965,7 +4982,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/breaking-change-checker.lock.yml b/.github/workflows/breaking-change-checker.lock.yml index 73bca91683..789d1e56dc 100644 --- a/.github/workflows/breaking-change-checker.lock.yml +++ b/.github/workflows/breaking-change-checker.lock.yml @@ -1615,7 +1615,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1737,6 +1737,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1820,7 +1837,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3756,7 +3773,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 5a4959109c..9e6329a746 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -2488,7 +2488,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2610,6 +2610,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2693,7 +2710,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4642,7 +4659,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 46d5894999..3b9bf4a777 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -2297,7 +2297,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2419,6 +2419,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2502,7 +2519,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4451,7 +4468,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 3249129f56..c8387ca555 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -1616,7 +1616,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1738,6 +1738,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1821,7 +1838,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3753,7 +3770,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index c657caa88d..46b7ecdb40 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -1885,7 +1885,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2007,6 +2007,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2090,7 +2107,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4241,7 +4258,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index ce1ce121ef..2acc4c1a34 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -3284,7 +3284,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3406,6 +3406,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3489,7 +3506,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5707,7 +5724,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/close-old-discussions.lock.yml b/.github/workflows/close-old-discussions.lock.yml index 767fbe46c1..ee7b6dc2a1 100644 --- a/.github/workflows/close-old-discussions.lock.yml +++ b/.github/workflows/close-old-discussions.lock.yml @@ -1778,7 +1778,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1900,6 +1900,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1983,7 +2000,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3847,7 +3864,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index cddcb68573..348ac699ea 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -1842,7 +1842,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1964,6 +1964,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2047,7 +2064,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4172,7 +4189,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 7f6c9627e7..cee2c5479a 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -2193,7 +2193,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2315,6 +2315,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2398,7 +2415,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4917,7 +4934,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index b55237256e..db11afffd5 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -1757,7 +1757,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1879,6 +1879,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1962,7 +1979,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5194,7 +5211,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 472be5f200..d9d62378a0 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -2407,7 +2407,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2529,6 +2529,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2612,7 +2629,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5293,7 +5310,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index ffb7e2162b..c101a6d105 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -1908,7 +1908,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2030,6 +2030,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2113,7 +2130,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4316,7 +4333,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 28cffc85bf..ef2690c599 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -2923,7 +2923,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3045,6 +3045,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3128,7 +3145,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -6327,7 +6344,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 74504db959..a0a195e98b 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -3079,7 +3079,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3201,6 +3201,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3284,7 +3301,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5309,7 +5326,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-assign-issue-to-user.lock.yml b/.github/workflows/daily-assign-issue-to-user.lock.yml index 317f503503..a31928cd4d 100644 --- a/.github/workflows/daily-assign-issue-to-user.lock.yml +++ b/.github/workflows/daily-assign-issue-to-user.lock.yml @@ -2061,7 +2061,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2183,6 +2183,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2266,7 +2283,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3951,7 +3968,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index 984935c6a2..c5c4c922e0 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -2425,7 +2425,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2547,6 +2547,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2630,7 +2647,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5368,7 +5385,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml index bb49b18d76..8c38e34243 100644 --- a/.github/workflows/daily-copilot-token-report.lock.yml +++ b/.github/workflows/daily-copilot-token-report.lock.yml @@ -2475,7 +2475,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2597,6 +2597,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2680,7 +2697,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5458,7 +5475,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index 7e6d2cb62c..211b5b6384 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -1737,7 +1737,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1859,6 +1859,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1942,7 +1959,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3964,7 +3981,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-fact.lock.yml b/.github/workflows/daily-fact.lock.yml index 0d35b3688c..8762160281 100644 --- a/.github/workflows/daily-fact.lock.yml +++ b/.github/workflows/daily-fact.lock.yml @@ -2069,7 +2069,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2191,6 +2191,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2274,7 +2291,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4042,7 +4059,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 2e6bc86898..add235f356 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -1766,7 +1766,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1888,6 +1888,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1971,7 +1988,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3996,7 +4013,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 58b44528e3..3066aa45af 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -2177,7 +2177,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2299,6 +2299,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2382,7 +2399,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4741,7 +4758,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml index f96562dee7..88378a466a 100644 --- a/.github/workflows/daily-issues-report.lock.yml +++ b/.github/workflows/daily-issues-report.lock.yml @@ -2570,7 +2570,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2692,6 +2692,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2775,7 +2792,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5580,7 +5597,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml index a8817234f6..8dce5eb092 100644 --- a/.github/workflows/daily-malicious-code-scan.lock.yml +++ b/.github/workflows/daily-malicious-code-scan.lock.yml @@ -1747,7 +1747,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1869,6 +1869,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1952,7 +1969,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3987,7 +4004,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index ae81bc3785..49fac7ea29 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -1699,7 +1699,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1821,6 +1821,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1904,7 +1921,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3875,7 +3892,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index fd28bde900..e44e6d8a27 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -2494,7 +2494,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2616,6 +2616,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2699,7 +2716,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5217,7 +5234,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index 995f82d8c2..dcc3df42ed 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -2332,7 +2332,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2454,6 +2454,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2537,7 +2554,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -6811,7 +6828,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index a3ed1547e9..b05784f5bb 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -2179,7 +2179,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2301,6 +2301,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2384,7 +2401,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4891,7 +4908,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index 52b49b7f0b..c9925d49d6 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -1543,7 +1543,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1665,6 +1665,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1748,7 +1765,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3515,7 +3532,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index 2779a409eb..c862a95e88 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -1608,7 +1608,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1730,6 +1730,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1813,7 +1830,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3679,7 +3696,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index 68f384af56..44c7086ace 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -2051,7 +2051,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2173,6 +2173,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2256,7 +2273,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4458,7 +4475,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index 01b80ccdd8..f2a746c5a4 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -1919,7 +1919,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2041,6 +2041,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2124,7 +2141,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4286,7 +4303,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 9a67b19ede..36f237812e 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -2147,7 +2147,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2269,6 +2269,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2352,7 +2369,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4233,7 +4250,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index d8f4015c41..00ad257431 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -344,7 +344,7 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{"max":0},"noop":{"max":1}} + {"create_pull_request":{"allow_empty":true},"missing_tool":{"max":0},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [ @@ -1455,7 +1455,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1577,6 +1577,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1660,7 +1677,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4460,7 +4477,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 37807751b1..d02c4baa30 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -2313,7 +2313,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2435,6 +2435,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2518,7 +2535,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5119,7 +5136,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 6eaf0e7dd5..807414b380 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -1593,7 +1593,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1715,6 +1715,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1798,7 +1815,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3626,7 +3643,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index ba03d08c1b..a0eecd1399 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -1624,7 +1624,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1746,6 +1746,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1829,7 +1846,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3765,7 +3782,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index d01983f9ae..c4ccf5fa91 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -1672,7 +1672,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1794,6 +1794,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1877,7 +1894,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3832,7 +3849,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index 5851be64f2..a7d824ba96 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -1641,7 +1641,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1763,6 +1763,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1846,7 +1863,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3680,7 +3697,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml index 88869957a9..7da12311ff 100644 --- a/.github/workflows/github-mcp-structural-analysis.lock.yml +++ b/.github/workflows/github-mcp-structural-analysis.lock.yml @@ -2279,7 +2279,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2401,6 +2401,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2484,7 +2501,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5045,7 +5062,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 86691705f9..b1b1401336 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -2164,7 +2164,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2286,6 +2286,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2369,7 +2386,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4822,7 +4839,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index 4e768e201a..c02aa2dbd0 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -2102,7 +2102,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2224,6 +2224,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2307,7 +2324,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4784,7 +4801,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml index ff1fa768a3..db55433f98 100644 --- a/.github/workflows/go-fan.lock.yml +++ b/.github/workflows/go-fan.lock.yml @@ -1954,7 +1954,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2076,6 +2076,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2159,7 +2176,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4394,7 +4411,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index b1b8444e41..182706344a 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -1864,7 +1864,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1986,6 +1986,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2069,7 +2086,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4127,7 +4144,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 8498b0e125..630ee11e34 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -1728,7 +1728,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1850,6 +1850,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1933,7 +1950,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3878,7 +3895,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index 3364baf180..0403dde03c 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -2996,7 +2996,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3118,6 +3118,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3201,7 +3218,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5114,7 +5131,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 3ce4508508..2bb09bdfaa 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -1733,7 +1733,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1855,6 +1855,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1938,7 +1955,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3892,7 +3909,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/issue-arborist.lock.yml b/.github/workflows/issue-arborist.lock.yml index 4e6a81de2f..a3c96ec7a7 100644 --- a/.github/workflows/issue-arborist.lock.yml +++ b/.github/workflows/issue-arborist.lock.yml @@ -1718,7 +1718,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1840,6 +1840,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1923,7 +1940,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3841,7 +3858,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 1d5114c9df..81eb0ae3f0 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2726,7 +2726,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2848,6 +2848,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2931,7 +2948,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4690,7 +4707,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml index 94276e082a..8f6d71dfda 100644 --- a/.github/workflows/issue-monster.lock.yml +++ b/.github/workflows/issue-monster.lock.yml @@ -2281,7 +2281,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2403,6 +2403,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2486,7 +2503,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4390,7 +4407,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/issue-triage-agent.lock.yml b/.github/workflows/issue-triage-agent.lock.yml index 1e635fd68d..7dc5f110bf 100644 --- a/.github/workflows/issue-triage-agent.lock.yml +++ b/.github/workflows/issue-triage-agent.lock.yml @@ -1914,7 +1914,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2036,6 +2036,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2119,7 +2136,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3858,7 +3875,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index 9f804be9da..8101f084bd 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -1731,7 +1731,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1853,6 +1853,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1936,7 +1953,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3917,7 +3934,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 09d5aad77a..927cf96096 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -1959,7 +1959,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2081,6 +2081,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2164,7 +2181,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4405,7 +4422,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index ea517f7f84..b5364c5867 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -1799,7 +1799,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1921,6 +1921,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2004,7 +2021,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -2902,7 +2919,7 @@ jobs: To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls. - **Available tools**: create_discussion, missing_tool, noop, post-to-slack-channel, notion-add-comment + **Available tools**: create_discussion, missing_tool, noop, notion-add-comment, post-to-slack-channel **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped. @@ -4295,7 +4312,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 0df0973dfe..a1558de25b 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -2146,7 +2146,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2268,6 +2268,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2351,7 +2368,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4459,7 +4476,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index c8c25c18fb..2f22413882 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -1382,7 +1382,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1504,6 +1504,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1587,7 +1604,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3361,7 +3378,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml index 52ed3cf85d..35e1b15cd6 100644 --- a/.github/workflows/org-health-report.lock.yml +++ b/.github/workflows/org-health-report.lock.yml @@ -2388,7 +2388,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2510,6 +2510,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2593,7 +2610,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5156,7 +5173,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index b0b6ff9ded..803b81aac5 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -2981,7 +2981,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3103,6 +3103,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3186,7 +3203,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5139,7 +5156,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index 0a6ee1d923..56d674f48b 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -2449,7 +2449,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2571,6 +2571,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2654,7 +2671,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4595,7 +4612,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index e0b22c8b2b..6734f29ba3 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -4110,7 +4110,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -4232,6 +4232,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -4315,7 +4332,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -6191,7 +6208,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml index 7f36b1186e..bdf93189da 100644 --- a/.github/workflows/portfolio-analyst.lock.yml +++ b/.github/workflows/portfolio-analyst.lock.yml @@ -1968,7 +1968,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2090,6 +2090,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2173,7 +2190,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4507,7 +4524,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 11a02c55ba..1cf3c7d05d 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -3032,7 +3032,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3154,6 +3154,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3237,7 +3254,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5459,7 +5476,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index a3c7ea4bd2..88e0a3144a 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -2644,7 +2644,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2766,6 +2766,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2849,7 +2866,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5680,7 +5697,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 240d69eab7..a97d18862b 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -2480,7 +2480,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2602,6 +2602,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2685,7 +2702,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5523,7 +5540,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index a88c260f43..be956a4721 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -3299,7 +3299,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3421,6 +3421,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3504,7 +3521,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5721,7 +5738,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 5ffd229b0d..2af8942051 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -1735,7 +1735,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1857,6 +1857,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1940,7 +1957,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3819,7 +3836,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 6667a16276..2edafc41e5 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -1622,7 +1622,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1744,6 +1744,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1827,7 +1844,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3700,7 +3717,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index b625ccd937..7aaf6488a5 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -2077,7 +2077,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2199,6 +2199,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2282,7 +2299,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4737,7 +4754,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 37efa982dd..ebee3a82d4 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -1543,7 +1543,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1665,6 +1665,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1748,7 +1765,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3614,7 +3631,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 2d4610a57b..385694246e 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -2084,7 +2084,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2206,6 +2206,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2289,7 +2306,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4702,7 +4719,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 0c0d869048..43ddc52a85 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -1969,7 +1969,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2091,6 +2091,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2174,7 +2191,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4350,7 +4367,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 9e879395f3..9ae101f3d6 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -3285,7 +3285,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3407,6 +3407,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3490,7 +3507,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5755,7 +5772,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index f369cb4dcd..6b8b769395 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -1711,7 +1711,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1833,6 +1833,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1916,7 +1933,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3900,7 +3917,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 47e8031070..2245e26f04 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -2118,7 +2118,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2240,6 +2240,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2323,7 +2340,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4738,7 +4755,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 5ec14f2c1e..53c5dc31d9 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -3396,7 +3396,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3518,6 +3518,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3601,7 +3618,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5636,7 +5653,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index a7015d5d7c..e5b05178a6 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -3188,7 +3188,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3310,6 +3310,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3393,7 +3410,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5206,7 +5223,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-copilot-no-firewall.lock.yml b/.github/workflows/smoke-copilot-no-firewall.lock.yml index 60aef8dc59..db2be9b059 100644 --- a/.github/workflows/smoke-copilot-no-firewall.lock.yml +++ b/.github/workflows/smoke-copilot-no-firewall.lock.yml @@ -3270,7 +3270,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3392,6 +3392,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3475,7 +3492,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -6627,7 +6644,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-copilot-playwright.lock.yml b/.github/workflows/smoke-copilot-playwright.lock.yml index f21b5f58a9..809883d322 100644 --- a/.github/workflows/smoke-copilot-playwright.lock.yml +++ b/.github/workflows/smoke-copilot-playwright.lock.yml @@ -3261,7 +3261,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3383,6 +3383,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3466,7 +3483,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -6607,7 +6624,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-copilot-safe-inputs.lock.yml b/.github/workflows/smoke-copilot-safe-inputs.lock.yml index c413f6b53f..2b6d67715e 100644 --- a/.github/workflows/smoke-copilot-safe-inputs.lock.yml +++ b/.github/workflows/smoke-copilot-safe-inputs.lock.yml @@ -3166,7 +3166,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3288,6 +3288,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3371,7 +3388,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -6332,7 +6349,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index ef89f79ebe..43a5c70e49 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -3153,7 +3153,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3275,6 +3275,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3358,7 +3375,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5157,7 +5174,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index b79f208809..6d84fa1b23 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -3005,7 +3005,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3127,6 +3127,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3210,7 +3227,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5379,7 +5396,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/smoke-srt.lock.yml b/.github/workflows/smoke-srt.lock.yml index 212143c00b..466809b273 100644 --- a/.github/workflows/smoke-srt.lock.yml +++ b/.github/workflows/smoke-srt.lock.yml @@ -1416,7 +1416,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1538,6 +1538,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1621,7 +1638,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3510,7 +3527,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/spec-kit-execute.lock.yml b/.github/workflows/spec-kit-execute.lock.yml index d51ed39039..29edf4d9d7 100644 --- a/.github/workflows/spec-kit-execute.lock.yml +++ b/.github/workflows/spec-kit-execute.lock.yml @@ -1884,7 +1884,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2006,6 +2006,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2089,7 +2106,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4228,7 +4245,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/spec-kit-executor.lock.yml b/.github/workflows/spec-kit-executor.lock.yml index 4cc0f6b12d..b26dd98b50 100644 --- a/.github/workflows/spec-kit-executor.lock.yml +++ b/.github/workflows/spec-kit-executor.lock.yml @@ -1730,7 +1730,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1852,6 +1852,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1935,7 +1952,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3918,7 +3935,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/speckit-dispatcher.lock.yml b/.github/workflows/speckit-dispatcher.lock.yml index aa56216215..07b8f21faa 100644 --- a/.github/workflows/speckit-dispatcher.lock.yml +++ b/.github/workflows/speckit-dispatcher.lock.yml @@ -3293,7 +3293,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3415,6 +3415,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3498,7 +3515,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5634,7 +5651,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index 40c827628d..5eb0465ad6 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -2478,7 +2478,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2600,6 +2600,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2683,7 +2700,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5392,7 +5409,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index 99cb339d12..920b54f596 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -1993,7 +1993,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2115,6 +2115,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2198,7 +2215,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4441,7 +4458,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 69c81f767b..3845ab0b55 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -1732,7 +1732,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1854,6 +1854,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1937,7 +1954,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3915,7 +3932,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 3d31a4ae20..93ffabe475 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -2590,7 +2590,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2712,6 +2712,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2795,7 +2812,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4972,7 +4989,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/test-discussion-expires.lock.yml b/.github/workflows/test-discussion-expires.lock.yml index 9f18c5754c..aa6b2c5a95 100644 --- a/.github/workflows/test-discussion-expires.lock.yml +++ b/.github/workflows/test-discussion-expires.lock.yml @@ -1420,7 +1420,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1542,6 +1542,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1625,7 +1642,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3299,7 +3316,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/test-python-safe-input.lock.yml b/.github/workflows/test-python-safe-input.lock.yml index 58ec7e2865..ffa888b585 100644 --- a/.github/workflows/test-python-safe-input.lock.yml +++ b/.github/workflows/test-python-safe-input.lock.yml @@ -1518,7 +1518,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1640,6 +1640,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1723,7 +1740,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4910,7 +4927,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 338d6a30da..31fc11f19a 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -2025,7 +2025,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2147,6 +2147,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2230,7 +2247,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4032,7 +4049,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 93869e1e6d..dec6113adf 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -2102,7 +2102,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2224,6 +2224,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2307,7 +2324,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4768,7 +4785,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index eb4470d995..a5ef232157 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -3047,7 +3047,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -3169,6 +3169,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -3252,7 +3269,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -5501,7 +5518,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index e3c7055a11..6dee5803aa 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -1729,7 +1729,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -1851,6 +1851,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -1934,7 +1951,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -3956,7 +3973,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index c782da4d34..f82dec323f 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -2081,7 +2081,7 @@ jobs: const { getCurrentBranch } = require("./get_current_branch.cjs"); const { getBaseBranch } = require("./get_base_branch.cjs"); const { generateGitPatch } = require("./generate_git_patch.cjs"); - function createHandlers(server, appendSafeOutput) { + function createHandlers(server, appendSafeOutput, config = {}) { const defaultHandler = type => args => { const entry = { ...(args || {}), type }; let largeContent = null; @@ -2203,6 +2203,23 @@ jobs: } entry.branch = detectedBranch; } + const allowEmpty = config.create_pull_request?.allow_empty === true; + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); if (!patchResult.success) { @@ -2286,7 +2303,7 @@ jobs: const server = createServer(SERVER_INFO, { logDir: MCP_LOG_DIR }); const { config: safeOutputsConfig, outputFile, tools: ALL_TOOLS } = bootstrapSafeOutputsServer(server); const appendSafeOutput = createAppendFunction(outputFile); - const handlers = createHandlers(server, appendSafeOutput); + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; const toolsWithHandlers = attachHandlers(ALL_TOOLS, handlers); server.debug(` output file: ${outputFile}`); @@ -4748,7 +4765,26 @@ jobs: const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); - name: Upload sanitized agent output diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index 95e74c6610..8c189c8849 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -336,6 +336,31 @@ async function main() { const patchPath = "/tmp/gh-aw/aw.patch"; const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - core.setOutput("has_patch", hasPatch ? "true" : "false"); + + // Load safe outputs config to check for allow-empty on create_pull_request + let allowEmptyPR = false; + const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; + try { + if (fs.existsSync(configPath)) { + const configContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configContent); + // Check if create-pull-request has allow-empty enabled + if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); + } + } + } catch (error) { + core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); + } + + // If allow-empty is enabled for create_pull_request and there's no patch, that's OK + // Set has_patch to true so the create_pull_request job will run + if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { + core.info(`allow-empty is enabled and no patch exists - will create empty PR`); + core.setOutput("has_patch", "true"); + } else { + core.setOutput("has_patch", hasPatch ? "true" : "false"); + } } await main(); diff --git a/pkg/workflow/js/safe_outputs_handlers.cjs b/pkg/workflow/js/safe_outputs_handlers.cjs index 517de6e7a2..b7fb027ffd 100644 --- a/pkg/workflow/js/safe_outputs_handlers.cjs +++ b/pkg/workflow/js/safe_outputs_handlers.cjs @@ -15,9 +15,10 @@ const { generateGitPatch } = require("./generate_git_patch.cjs"); * Create handlers for safe output tools * @param {Object} server - The MCP server instance for logging * @param {Function} appendSafeOutput - Function to append entries to the output file + * @param {Object} [config] - Optional configuration object with safe output settings * @returns {Object} An object containing all handler functions */ -function createHandlers(server, appendSafeOutput) { +function createHandlers(server, appendSafeOutput, config = {}) { /** * Default handler for safe output tools * @param {string} type - The tool type @@ -185,7 +186,7 @@ function createHandlers(server, appendSafeOutput) { /** * Handler for create_pull_request tool * Resolves the current branch if branch is not provided or is the base branch - * Generates git patch for the changes + * Generates git patch for the changes (unless allow-empty is true) */ const createPullRequestHandler = args => { const entry = { ...args, type: "create_pull_request" }; @@ -205,6 +206,27 @@ function createHandlers(server, appendSafeOutput) { entry.branch = detectedBranch; } + // Check if allow-empty is enabled in configuration + const allowEmpty = config.create_pull_request?.allow_empty === true; + + if (allowEmpty) { + server.debug(`allow-empty is enabled for create_pull_request - skipping patch generation`); + // Append the safe output entry without generating a patch + appendSafeOutput(entry); + return { + content: [ + { + type: "text", + text: JSON.stringify({ + result: "success", + message: "Pull request prepared (allow-empty mode - no patch generated)", + branch: entry.branch, + }), + }, + ], + }; + } + // Generate git patch server.debug(`Generating patch for create_pull_request with branch: ${entry.branch}`); const patchResult = generateGitPatch(entry.branch); diff --git a/pkg/workflow/js/safe_outputs_mcp_server.cjs b/pkg/workflow/js/safe_outputs_mcp_server.cjs index 2d0db87bd4..0abd29c73a 100644 --- a/pkg/workflow/js/safe_outputs_mcp_server.cjs +++ b/pkg/workflow/js/safe_outputs_mcp_server.cjs @@ -38,8 +38,8 @@ function startSafeOutputsServer(options = {}) { // Create append function const appendSafeOutput = createAppendFunction(outputFile); - // Create handlers - const handlers = createHandlers(server, appendSafeOutput); + // Create handlers with configuration + const handlers = createHandlers(server, appendSafeOutput, safeOutputsConfig); const { defaultHandler } = handlers; // Attach handlers to tools diff --git a/pkg/workflow/safe_outputs.go b/pkg/workflow/safe_outputs.go index 189a0f0f60..f6ad9bcae8 100644 --- a/pkg/workflow/safe_outputs.go +++ b/pkg/workflow/safe_outputs.go @@ -1003,6 +1003,10 @@ func generateSafeOutputsConfig(data *WorkflowData) string { if len(data.SafeOutputs.CreatePullRequests.AllowedLabels) > 0 { prConfig["allowed_labels"] = data.SafeOutputs.CreatePullRequests.AllowedLabels } + // Pass allow_empty flag to MCP server so it can skip patch generation + if data.SafeOutputs.CreatePullRequests.AllowEmpty { + prConfig["allow_empty"] = true + } safeOutputsConfig["create_pull_request"] = prConfig } if data.SafeOutputs.CreatePullRequestReviewComments != nil { From 12b6941ce48e1bd1bd3f710c57cef18f2fa406de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 22:34:03 +0000 Subject: [PATCH 7/7] fix: Remove duplicate configPath declaration in collect_ndjson_output Fixed SyntaxError "Identifier 'configPath' has already been declared" by reusing the already-loaded safeOutputsConfig instead of reading the config file again. The config is loaded at the beginning of the main function, so we can directly check it for the allow-empty setting without redeclaring configPath. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-moderator.lock.yml | 18 ++++++--------- .github/workflows/ai-triage-campaign.lock.yml | 18 ++++++--------- .github/workflows/archie.lock.yml | 18 ++++++--------- .github/workflows/artifacts-summary.lock.yml | 18 ++++++--------- .github/workflows/audit-workflows.lock.yml | 18 ++++++--------- .github/workflows/blog-auditor.lock.yml | 18 ++++++--------- .github/workflows/brave.lock.yml | 18 ++++++--------- .../breaking-change-checker.lock.yml | 18 ++++++--------- .github/workflows/changeset.lock.yml | 18 ++++++--------- .github/workflows/ci-doctor.lock.yml | 18 ++++++--------- .../cli-consistency-checker.lock.yml | 18 ++++++--------- .../workflows/cli-version-checker.lock.yml | 18 ++++++--------- .github/workflows/cloclo.lock.yml | 18 ++++++--------- .../workflows/close-old-discussions.lock.yml | 18 ++++++--------- .../commit-changes-analyzer.lock.yml | 18 ++++++--------- .../workflows/copilot-agent-analysis.lock.yml | 18 ++++++--------- .../copilot-pr-merged-report.lock.yml | 18 ++++++--------- .../copilot-pr-nlp-analysis.lock.yml | 18 ++++++--------- .../copilot-pr-prompt-analysis.lock.yml | 18 ++++++--------- .../copilot-session-insights.lock.yml | 18 ++++++--------- .github/workflows/craft.lock.yml | 18 ++++++--------- .../daily-assign-issue-to-user.lock.yml | 18 ++++++--------- .github/workflows/daily-code-metrics.lock.yml | 18 ++++++--------- .../daily-copilot-token-report.lock.yml | 18 ++++++--------- .github/workflows/daily-doc-updater.lock.yml | 18 ++++++--------- .github/workflows/daily-fact.lock.yml | 18 ++++++--------- .github/workflows/daily-file-diet.lock.yml | 18 ++++++--------- .../workflows/daily-firewall-report.lock.yml | 18 ++++++--------- .../workflows/daily-issues-report.lock.yml | 18 ++++++--------- .../daily-malicious-code-scan.lock.yml | 18 ++++++--------- .../daily-multi-device-docs-tester.lock.yml | 18 ++++++--------- .github/workflows/daily-news.lock.yml | 18 ++++++--------- .../daily-performance-summary.lock.yml | 18 ++++++--------- .../workflows/daily-repo-chronicle.lock.yml | 18 ++++++--------- .github/workflows/daily-team-status.lock.yml | 18 ++++++--------- .../workflows/daily-workflow-updater.lock.yml | 18 ++++++--------- .github/workflows/deep-report.lock.yml | 18 ++++++--------- .../workflows/dependabot-go-checker.lock.yml | 18 ++++++--------- .github/workflows/dev-hawk.lock.yml | 18 ++++++--------- .github/workflows/dev.lock.yml | 18 ++++++--------- .../developer-docs-consolidator.lock.yml | 18 ++++++--------- .github/workflows/dictation-prompt.lock.yml | 18 ++++++--------- .github/workflows/docs-noob-tester.lock.yml | 18 ++++++--------- .../duplicate-code-detector.lock.yml | 18 ++++++--------- .../example-workflow-analyzer.lock.yml | 18 ++++++--------- .../github-mcp-structural-analysis.lock.yml | 18 ++++++--------- .../github-mcp-tools-report.lock.yml | 18 ++++++--------- .../workflows/glossary-maintainer.lock.yml | 18 ++++++--------- .github/workflows/go-fan.lock.yml | 18 ++++++--------- .github/workflows/go-logger.lock.yml | 18 ++++++--------- .../workflows/go-pattern-detector.lock.yml | 18 ++++++--------- .github/workflows/grumpy-reviewer.lock.yml | 18 ++++++--------- .../workflows/instructions-janitor.lock.yml | 18 ++++++--------- .github/workflows/issue-arborist.lock.yml | 18 ++++++--------- .github/workflows/issue-classifier.lock.yml | 18 ++++++--------- .github/workflows/issue-monster.lock.yml | 18 ++++++--------- .github/workflows/issue-triage-agent.lock.yml | 18 ++++++--------- .../workflows/layout-spec-maintainer.lock.yml | 18 ++++++--------- .github/workflows/lockfile-stats.lock.yml | 18 ++++++--------- .github/workflows/mcp-inspector.lock.yml | 18 ++++++--------- .github/workflows/mergefest.lock.yml | 18 ++++++--------- .../workflows/notion-issue-summary.lock.yml | 18 ++++++--------- .github/workflows/org-health-report.lock.yml | 18 ++++++--------- .github/workflows/pdf-summary.lock.yml | 18 ++++++--------- .github/workflows/plan.lock.yml | 18 ++++++--------- .github/workflows/poem-bot.lock.yml | 18 ++++++--------- .github/workflows/portfolio-analyst.lock.yml | 18 ++++++--------- .../workflows/pr-nitpick-reviewer.lock.yml | 18 ++++++--------- .../prompt-clustering-analysis.lock.yml | 18 ++++++--------- .github/workflows/python-data-charts.lock.yml | 18 ++++++--------- .github/workflows/q.lock.yml | 18 ++++++--------- .github/workflows/release.lock.yml | 18 ++++++--------- .github/workflows/repo-tree-map.lock.yml | 18 ++++++--------- .../repository-quality-improver.lock.yml | 18 ++++++--------- .github/workflows/research.lock.yml | 18 ++++++--------- .github/workflows/safe-output-health.lock.yml | 18 ++++++--------- .../schema-consistency-checker.lock.yml | 18 ++++++--------- .github/workflows/scout.lock.yml | 18 ++++++--------- .github/workflows/security-fix-pr.lock.yml | 18 ++++++--------- .../semantic-function-refactor.lock.yml | 18 ++++++--------- .github/workflows/smoke-claude.lock.yml | 18 ++++++--------- .github/workflows/smoke-codex.lock.yml | 18 ++++++--------- .../smoke-copilot-no-firewall.lock.yml | 18 ++++++--------- .../smoke-copilot-playwright.lock.yml | 18 ++++++--------- .../smoke-copilot-safe-inputs.lock.yml | 18 ++++++--------- .github/workflows/smoke-copilot.lock.yml | 18 ++++++--------- .github/workflows/smoke-detector.lock.yml | 18 ++++++--------- .github/workflows/smoke-srt.lock.yml | 18 ++++++--------- .github/workflows/spec-kit-execute.lock.yml | 18 ++++++--------- .github/workflows/spec-kit-executor.lock.yml | 18 ++++++--------- .github/workflows/speckit-dispatcher.lock.yml | 18 ++++++--------- .../workflows/stale-repo-identifier.lock.yml | 18 ++++++--------- .../workflows/static-analysis-report.lock.yml | 18 ++++++--------- .github/workflows/super-linter.lock.yml | 18 ++++++--------- .../workflows/technical-doc-writer.lock.yml | 18 ++++++--------- .../test-discussion-expires.lock.yml | 18 ++++++--------- .../workflows/test-python-safe-input.lock.yml | 18 ++++++--------- .github/workflows/tidy.lock.yml | 18 ++++++--------- .github/workflows/typist.lock.yml | 18 ++++++--------- .github/workflows/unbloat-docs.lock.yml | 18 ++++++--------- .github/workflows/video-analyzer.lock.yml | 18 ++++++--------- .../workflows/weekly-issue-summary.lock.yml | 18 ++++++--------- pkg/workflow/js/collect_ndjson_output.cjs | 22 ++++++++----------- 103 files changed, 723 insertions(+), 1135 deletions(-) diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index 33df27cf8c..2705dd88bb 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -4625,18 +4625,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index 500192f178..e32b14f62c 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -3532,18 +3532,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 1bc7eaade9..6b8a8bba6b 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -5193,18 +5193,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 89ac6104e1..3ac781f82a 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -3690,18 +3690,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 870d1e0b3c..8becba42b6 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -5248,18 +5248,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index 8571b7fa23..cdeee9fa66 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -4310,18 +4310,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 3039c24899..a2ac04ec88 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -4983,18 +4983,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/breaking-change-checker.lock.yml b/.github/workflows/breaking-change-checker.lock.yml index 789d1e56dc..eeef619e55 100644 --- a/.github/workflows/breaking-change-checker.lock.yml +++ b/.github/workflows/breaking-change-checker.lock.yml @@ -3774,18 +3774,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 9e6329a746..f58be02c72 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -4660,18 +4660,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 3b9bf4a777..ac870cfe96 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -4469,18 +4469,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index c8387ca555..7c23eee172 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -3771,18 +3771,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index 46b7ecdb40..a104a8fbf6 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -4259,18 +4259,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 2acc4c1a34..ffc27e3377 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -5725,18 +5725,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/close-old-discussions.lock.yml b/.github/workflows/close-old-discussions.lock.yml index ee7b6dc2a1..7b769a9581 100644 --- a/.github/workflows/close-old-discussions.lock.yml +++ b/.github/workflows/close-old-discussions.lock.yml @@ -3865,18 +3865,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 348ac699ea..accd99cb6b 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -4190,18 +4190,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index cee2c5479a..3c2bb442d6 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -4935,18 +4935,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index db11afffd5..865761467c 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -5212,18 +5212,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index d9d62378a0..0133954602 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -5311,18 +5311,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index c101a6d105..06d566dc71 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -4334,18 +4334,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index ef2690c599..0cbd3e2c13 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -6345,18 +6345,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index a0a195e98b..b22e2f43d3 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -5327,18 +5327,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-assign-issue-to-user.lock.yml b/.github/workflows/daily-assign-issue-to-user.lock.yml index a31928cd4d..216585344a 100644 --- a/.github/workflows/daily-assign-issue-to-user.lock.yml +++ b/.github/workflows/daily-assign-issue-to-user.lock.yml @@ -3969,18 +3969,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index c5c4c922e0..3cd458274c 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -5386,18 +5386,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml index 8c38e34243..3dea0685bb 100644 --- a/.github/workflows/daily-copilot-token-report.lock.yml +++ b/.github/workflows/daily-copilot-token-report.lock.yml @@ -5476,18 +5476,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index 211b5b6384..53292ad9f5 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -3982,18 +3982,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-fact.lock.yml b/.github/workflows/daily-fact.lock.yml index 8762160281..9731fdf849 100644 --- a/.github/workflows/daily-fact.lock.yml +++ b/.github/workflows/daily-fact.lock.yml @@ -4060,18 +4060,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index add235f356..3b4e573f08 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -4014,18 +4014,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 3066aa45af..fc0ea34bea 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -4759,18 +4759,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml index 88378a466a..1d535c4c97 100644 --- a/.github/workflows/daily-issues-report.lock.yml +++ b/.github/workflows/daily-issues-report.lock.yml @@ -5598,18 +5598,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml index 8dce5eb092..062da39e1b 100644 --- a/.github/workflows/daily-malicious-code-scan.lock.yml +++ b/.github/workflows/daily-malicious-code-scan.lock.yml @@ -4005,18 +4005,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index 49fac7ea29..9362ee725f 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -3893,18 +3893,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index e44e6d8a27..035420bf2f 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -5235,18 +5235,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index dcc3df42ed..0732053a69 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -6829,18 +6829,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index b05784f5bb..ab9ebb0f60 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -4909,18 +4909,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index c9925d49d6..4788ba4487 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -3533,18 +3533,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index c862a95e88..0a559becac 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -3697,18 +3697,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index 44c7086ace..497e2d91b4 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -4476,18 +4476,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index f2a746c5a4..605e485fcf 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -4304,18 +4304,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 36f237812e..afbf8c6f17 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -4251,18 +4251,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 00ad257431..dc2b09f75d 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -4478,18 +4478,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index d02c4baa30..67f138a5d3 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -5137,18 +5137,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 807414b380..327af2c8af 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -3644,18 +3644,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index a0eecd1399..a67ce4f2a9 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -3783,18 +3783,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index c4ccf5fa91..b01a075077 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -3850,18 +3850,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index a7d824ba96..790d98b757 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -3698,18 +3698,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml index 7da12311ff..e4c061fd26 100644 --- a/.github/workflows/github-mcp-structural-analysis.lock.yml +++ b/.github/workflows/github-mcp-structural-analysis.lock.yml @@ -5063,18 +5063,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index b1b1401336..8c79cdd041 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -4840,18 +4840,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index c02aa2dbd0..7acb2fe6d8 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -4802,18 +4802,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml index db55433f98..f2328831ec 100644 --- a/.github/workflows/go-fan.lock.yml +++ b/.github/workflows/go-fan.lock.yml @@ -4412,18 +4412,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 182706344a..9a7dbdd854 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -4145,18 +4145,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 630ee11e34..8cf6877a98 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -3896,18 +3896,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index 0403dde03c..75c60191e3 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -5132,18 +5132,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 2bb09bdfaa..a01387e54c 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -3910,18 +3910,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/issue-arborist.lock.yml b/.github/workflows/issue-arborist.lock.yml index a3c96ec7a7..0dfed9b07e 100644 --- a/.github/workflows/issue-arborist.lock.yml +++ b/.github/workflows/issue-arborist.lock.yml @@ -3859,18 +3859,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 81eb0ae3f0..d34120c9ae 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -4708,18 +4708,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml index 8f6d71dfda..058b74d3bf 100644 --- a/.github/workflows/issue-monster.lock.yml +++ b/.github/workflows/issue-monster.lock.yml @@ -4408,18 +4408,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/issue-triage-agent.lock.yml b/.github/workflows/issue-triage-agent.lock.yml index 7dc5f110bf..0e7607ff94 100644 --- a/.github/workflows/issue-triage-agent.lock.yml +++ b/.github/workflows/issue-triage-agent.lock.yml @@ -3876,18 +3876,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index 8101f084bd..51e49ad077 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -3935,18 +3935,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 927cf96096..a9084f42ff 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -4423,18 +4423,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index b5364c5867..20ba1e37ff 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -4313,18 +4313,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index a1558de25b..9674c50ddb 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -4477,18 +4477,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 2f22413882..0a26b9804c 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -3379,18 +3379,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml index 35e1b15cd6..d523b4c0e1 100644 --- a/.github/workflows/org-health-report.lock.yml +++ b/.github/workflows/org-health-report.lock.yml @@ -5174,18 +5174,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 803b81aac5..a586fb5b97 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -5157,18 +5157,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index 56d674f48b..8d590d7851 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -4613,18 +4613,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 6734f29ba3..29b8e38296 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -6209,18 +6209,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml index bdf93189da..18695e839d 100644 --- a/.github/workflows/portfolio-analyst.lock.yml +++ b/.github/workflows/portfolio-analyst.lock.yml @@ -4525,18 +4525,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 1cf3c7d05d..5ea733937e 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -5477,18 +5477,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 88e0a3144a..53f3e17b9d 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -5698,18 +5698,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index a97d18862b..77bfd73240 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -5541,18 +5541,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index be956a4721..bd0fdc5cfd 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -5739,18 +5739,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 2af8942051..9e6a69ffe8 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -3837,18 +3837,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 2edafc41e5..9f15d6eb32 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -3718,18 +3718,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 7aaf6488a5..5a45fe6e6c 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -4755,18 +4755,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index ebee3a82d4..7dffa957e3 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -3632,18 +3632,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 385694246e..d7b1206c31 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -4720,18 +4720,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 43ddc52a85..740b540b26 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -4368,18 +4368,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 9ae101f3d6..89ac03249f 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -5773,18 +5773,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 6b8b769395..259f6c0bf2 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -3918,18 +3918,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 2245e26f04..e12f6b830c 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -4756,18 +4756,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 53c5dc31d9..e265bfe644 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -5654,18 +5654,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index e5b05178a6..720f193e68 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -5224,18 +5224,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-copilot-no-firewall.lock.yml b/.github/workflows/smoke-copilot-no-firewall.lock.yml index db2be9b059..feb046af6e 100644 --- a/.github/workflows/smoke-copilot-no-firewall.lock.yml +++ b/.github/workflows/smoke-copilot-no-firewall.lock.yml @@ -6645,18 +6645,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-copilot-playwright.lock.yml b/.github/workflows/smoke-copilot-playwright.lock.yml index 809883d322..e60e85eada 100644 --- a/.github/workflows/smoke-copilot-playwright.lock.yml +++ b/.github/workflows/smoke-copilot-playwright.lock.yml @@ -6625,18 +6625,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-copilot-safe-inputs.lock.yml b/.github/workflows/smoke-copilot-safe-inputs.lock.yml index 2b6d67715e..31536ef2ff 100644 --- a/.github/workflows/smoke-copilot-safe-inputs.lock.yml +++ b/.github/workflows/smoke-copilot-safe-inputs.lock.yml @@ -6350,18 +6350,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 43a5c70e49..54028893b2 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -5175,18 +5175,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index 6d84fa1b23..b81eb88e08 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -5397,18 +5397,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/smoke-srt.lock.yml b/.github/workflows/smoke-srt.lock.yml index 466809b273..be18eca3f2 100644 --- a/.github/workflows/smoke-srt.lock.yml +++ b/.github/workflows/smoke-srt.lock.yml @@ -3528,18 +3528,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/spec-kit-execute.lock.yml b/.github/workflows/spec-kit-execute.lock.yml index 29edf4d9d7..4a7222cc59 100644 --- a/.github/workflows/spec-kit-execute.lock.yml +++ b/.github/workflows/spec-kit-execute.lock.yml @@ -4246,18 +4246,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/spec-kit-executor.lock.yml b/.github/workflows/spec-kit-executor.lock.yml index b26dd98b50..158c21af5d 100644 --- a/.github/workflows/spec-kit-executor.lock.yml +++ b/.github/workflows/spec-kit-executor.lock.yml @@ -3936,18 +3936,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/speckit-dispatcher.lock.yml b/.github/workflows/speckit-dispatcher.lock.yml index 07b8f21faa..e4f77124b7 100644 --- a/.github/workflows/speckit-dispatcher.lock.yml +++ b/.github/workflows/speckit-dispatcher.lock.yml @@ -5652,18 +5652,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index 5eb0465ad6..c6c54865dc 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -5410,18 +5410,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index 920b54f596..98367cfdac 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -4459,18 +4459,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 3845ab0b55..74e9032d64 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -3933,18 +3933,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 93ffabe475..d8b3b1d815 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -4990,18 +4990,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/test-discussion-expires.lock.yml b/.github/workflows/test-discussion-expires.lock.yml index aa6b2c5a95..77c4e3ff0f 100644 --- a/.github/workflows/test-discussion-expires.lock.yml +++ b/.github/workflows/test-discussion-expires.lock.yml @@ -3317,18 +3317,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/test-python-safe-input.lock.yml b/.github/workflows/test-python-safe-input.lock.yml index ffa888b585..5dc3bbdcb7 100644 --- a/.github/workflows/test-python-safe-input.lock.yml +++ b/.github/workflows/test-python-safe-input.lock.yml @@ -4928,18 +4928,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 31fc11f19a..772857cb1e 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -4050,18 +4050,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index dec6113adf..145ce0e4fb 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -4786,18 +4786,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index a5ef232157..6e698ce46a 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -5519,18 +5519,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index 6dee5803aa..1c4418a923 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -3974,18 +3974,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index f82dec323f..845f814d49 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -4766,18 +4766,14 @@ jobs: const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } if (allowEmptyPR && !hasPatch && outputTypes.includes("create_pull_request")) { core.info(`allow-empty is enabled and no patch exists - will create empty PR`); diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index 8c189c8849..9d23cc25ad 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -337,21 +337,17 @@ async function main() { const hasPatch = fs.existsSync(patchPath); core.info(`Patch file ${hasPatch ? "exists" : "does not exist"} at: ${patchPath}`); - // Load safe outputs config to check for allow-empty on create_pull_request + // Check if allow-empty is enabled for create_pull_request (reuse already loaded config) let allowEmptyPR = false; - const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json"; - try { - if (fs.existsSync(configPath)) { - const configContent = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(configContent); - // Check if create-pull-request has allow-empty enabled - if (config["create-pull-request"]?.["allow-empty"] === true || config["create_pull_request"]?.["allow_empty"] === true) { - allowEmptyPR = true; - core.info(`allow-empty is enabled for create-pull-request`); - } + if (safeOutputsConfig) { + // Check if create-pull-request has allow-empty enabled + if ( + safeOutputsConfig["create-pull-request"]?.["allow-empty"] === true || + safeOutputsConfig["create_pull_request"]?.["allow_empty"] === true + ) { + allowEmptyPR = true; + core.info(`allow-empty is enabled for create-pull-request`); } - } catch (error) { - core.debug(`Failed to load config for allow-empty check: ${error instanceof Error ? error.message : String(error)}`); } // If allow-empty is enabled for create_pull_request and there's no patch, that's OK