From c1323e195e83a9464842ec8b69ce7f75548d84ff Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:00:57 +0000 Subject: [PATCH 01/13] Improve error handling in parseClaudeLog and add detailed function documentation --- .../github-script.instructions.md | 25 ++++++++++++ pkg/workflow/js/parse_claude_log.cjs | 39 +++++++++++++++++-- pkg/workflow/js/parse_codex_log.cjs | 25 ++++++++++-- 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 .github/instructions/github-script.instructions.md diff --git a/.github/instructions/github-script.instructions.md b/.github/instructions/github-script.instructions.md new file mode 100644 index 00000000000..efaa08c33e3 --- /dev/null +++ b/.github/instructions/github-script.instructions.md @@ -0,0 +1,25 @@ +--- +description: GitHub Action Script Source Code +applyTo: "pkg/workflow/js/*.cjs" +--- + +This JavaScript file will be run using the GitHub Action `actions/github-script@v7` which provides the `@actions/core`, `@actions/github` packages for logging errors and setting action status. + +- do not add import or require for `@actions/core` +- reference: + - https://github.com/actions/toolkit/blob/main/packages/core/README.md + - https://github.com/actions/toolkit/blob/main/packages/github/README.md + +## Common errors + +- catch handler: check if error is an instance of Error before accessing message property + +```js +catch (error) { + core.setFailed(error instanceof Error ? error : String(error)); +} +``` + +## Typechecking + +Run `make js` to run the typescript compiler. \ No newline at end of file diff --git a/pkg/workflow/js/parse_claude_log.cjs b/pkg/workflow/js/parse_claude_log.cjs index 3288b3a7911..c4230bcec9a 100644 --- a/pkg/workflow/js/parse_claude_log.cjs +++ b/pkg/workflow/js/parse_claude_log.cjs @@ -20,11 +20,16 @@ function main() { // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } +/** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -180,10 +185,17 @@ function parseClaudeLog(logContent) { return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } +/** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -285,6 +297,11 @@ function formatToolUse(toolUse, toolResult) { return markdown; } +/** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -298,6 +315,11 @@ function formatMcpName(toolName) { return toolName; } +/** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -316,6 +338,11 @@ function formatMcpParameters(input) { return paramStrs.join(", "); } +/** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; @@ -340,6 +367,12 @@ function formatBashCommand(command) { return formatted; } +/** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/workflow/js/parse_codex_log.cjs b/pkg/workflow/js/parse_codex_log.cjs index 8db41e27968..970218ba01f 100644 --- a/pkg/workflow/js/parse_codex_log.cjs +++ b/pkg/workflow/js/parse_codex_log.cjs @@ -23,10 +23,15 @@ function main() { core.error("Failed to parse Codex log"); } } catch (error) { - core.setFailed(error.message); + core.setFailed(error instanceof Error ? error : String(error)); } } +/** + * Parse codex log content and format as markdown + * @param {string} logContent - The raw log content to parse + * @returns {string} Formatted markdown content + */ function parseCodexLog(logContent) { try { const lines = logContent.split("\n"); @@ -118,8 +123,11 @@ function parseCodexLog(logContent) { const tokenMatches = logContent.match(/tokens used: (\d+)/g); if (tokenMatches) { for (const match of tokenMatches) { - const tokens = parseInt(match.match(/(\d+)/)[1]); - totalTokens += tokens; + const numberMatch = match.match(/(\d+)/); + if (numberMatch) { + const tokens = parseInt(numberMatch[1]); + totalTokens += tokens; + } } } @@ -252,6 +260,11 @@ function parseCodexLog(logContent) { } } +/** + * Format bash command for display + * @param {string} command - The command to format + * @returns {string} Formatted command string + */ function formatBashCommand(command) { if (!command) return ""; @@ -276,6 +289,12 @@ function formatBashCommand(command) { return formatted; } +/** + * Truncate string to maximum length + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum length allowed + * @returns {string} Truncated string + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; From 9072e3c69b1459e8d480d75ee67409cbe839dee6 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:09:56 +0000 Subject: [PATCH 02/13] Enhance logging and error handling across multiple scripts, update type annotations, and improve best practices documentation for GitHub Actions. --- .../github-script.instructions.md | 15 ++++++++++- .../js/add_reaction_and_edit_comment.cjs | 3 +-- pkg/workflow/js/check_permissions.cjs | 6 ++--- pkg/workflow/js/collect_ndjson_output.cjs | 26 ++++++++++++------- .../js/create_code_scanning_alert.cjs | 1 + pkg/workflow/js/create_discussion.cjs | 2 +- pkg/workflow/js/create_pr_review_comment.cjs | 6 ++--- pkg/workflow/js/missing_tool.cjs | 1 + 8 files changed, 41 insertions(+), 19 deletions(-) diff --git a/.github/instructions/github-script.instructions.md b/.github/instructions/github-script.instructions.md index efaa08c33e3..34a4d38ad67 100644 --- a/.github/instructions/github-script.instructions.md +++ b/.github/instructions/github-script.instructions.md @@ -10,6 +10,15 @@ This JavaScript file will be run using the GitHub Action `actions/github-script@ - https://github.com/actions/toolkit/blob/main/packages/core/README.md - https://github.com/actions/toolkit/blob/main/packages/github/README.md +## Best practices + +- use `core.info`, `core.warning`, `core.error` for logging, not `console.log` or `console.error` +- use `core.debug` for verbose debug logging, which can be enabled in action settings +- use `core.setOutput` to set action outputs +- use `core.exportVariable` to set environment variables for subsequent steps +- use `core.getInput` to get action inputs, with `required: true` for mandatory inputs +- use `core.setFailed` to mark the action as failed with an error message + ## Common errors - catch handler: check if error is an instance of Error before accessing message property @@ -20,6 +29,10 @@ catch (error) { } ``` +- `core.setFailed` also calls `core.error`, so do not call both + ## Typechecking -Run `make js` to run the typescript compiler. \ No newline at end of file +Run `make js` to run the typescript compiler. + +Run `make fmt:cjs` after editing to format the file. \ No newline at end of file diff --git a/pkg/workflow/js/add_reaction_and_edit_comment.cjs b/pkg/workflow/js/add_reaction_and_edit_comment.cjs index 398fc83be48..46ece9d958e 100644 --- a/pkg/workflow/js/add_reaction_and_edit_comment.cjs +++ b/pkg/workflow/js/add_reaction_and_edit_comment.cjs @@ -183,8 +183,7 @@ async function editCommentWithWorkflowLink(endpoint, runUrl) { // Don't fail the entire job if comment editing fails - just log it const errorMessage = error instanceof Error ? error.message : String(error); core.warning( - "Failed to edit comment with workflow link (This is not critical - the reaction was still added successfully):", - errorMessage + "Failed to edit comment with workflow link (This is not critical - the reaction was still added successfully): " + errorMessage ); } } diff --git a/pkg/workflow/js/check_permissions.cjs b/pkg/workflow/js/check_permissions.cjs index e2ec20060bb..8884c5fbe1a 100644 --- a/pkg/workflow/js/check_permissions.cjs +++ b/pkg/workflow/js/check_permissions.cjs @@ -19,7 +19,7 @@ async function main() { core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( + core.setFailed( "Configuration error: Required permissions not specified" ); return; @@ -60,7 +60,7 @@ async function main() { const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } @@ -68,7 +68,7 @@ async function main() { core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index c1210a2a4eb..45944ece279 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -149,7 +149,7 @@ async function main() { /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -202,6 +202,7 @@ async function main() { // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -289,8 +290,10 @@ async function main() { } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = originalError instanceof Error ? originalError.message : String(originalError); + const repairMsg = repairError instanceof Error ? repairError.message : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -321,15 +324,17 @@ async function main() { console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); console.log( "Warning: Could not parse safe-outputs config:", - error.message + errorMsg ); } } @@ -343,6 +348,7 @@ async function main() { const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line @@ -398,7 +404,7 @@ async function main() { item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => + item.labels = item.labels.map(/** @param {any} label */ label => typeof label === "string" ? sanitizeContent(label) : label ); } @@ -437,7 +443,7 @@ async function main() { } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => + item.labels = item.labels.map(/** @param {any} label */ label => typeof label === "string" ? sanitizeContent(label) : label ); } @@ -450,14 +456,14 @@ async function main() { ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if (item.labels.some(/** @param {any} label */ label => typeof label !== "string")) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map(/** @param {any} label */ label => sanitizeContent(label)); break; case "update-issue": @@ -778,7 +784,8 @@ async function main() { console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } @@ -817,7 +824,8 @@ async function main() { // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); diff --git a/pkg/workflow/js/create_code_scanning_alert.cjs b/pkg/workflow/js/create_code_scanning_alert.cjs index 248f6f877c0..7f6ab54ccef 100644 --- a/pkg/workflow/js/create_code_scanning_alert.cjs +++ b/pkg/workflow/js/create_code_scanning_alert.cjs @@ -191,6 +191,7 @@ async function main() { } // Validate severity level and map to SARIF level + /** @type {Record} */ const severityMap = { error: "error", warning: "warning", diff --git a/pkg/workflow/js/create_discussion.cjs b/pkg/workflow/js/create_discussion.cjs index 673561a2940..fbb21e63ac1 100644 --- a/pkg/workflow/js/create_discussion.cjs +++ b/pkg/workflow/js/create_discussion.cjs @@ -97,7 +97,7 @@ async function main() { queryResult.repository.discussionCategories.nodes || []; console.log( "Available categories:", - discussionCategories.map(cat => ({ name: cat.name, id: cat.id })) + discussionCategories.map(/** @param {any} cat */ cat => ({ name: cat.name, id: cat.id })) ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); diff --git a/pkg/workflow/js/create_pr_review_comment.cjs b/pkg/workflow/js/create_pr_review_comment.cjs index 2fb02685299..a235e7d55f2 100644 --- a/pkg/workflow/js/create_pr_review_comment.cjs +++ b/pkg/workflow/js/create_pr_review_comment.cjs @@ -99,7 +99,7 @@ async function main() { //No, github.event.issue.pull_request does not contain the full pull request data like head.sha. It only includes a minimal object with a url pointing to the pull request API resource. //To get full PR details (like head.sha, base.ref, etc.), you need to make an API call using that URL. - if (context.payload.issue.pull_request) { + if (context.payload.issue && context.payload.issue.pull_request) { // Fetch full pull request details using the GitHub API const prUrl = context.payload.issue.pull_request.url; try { @@ -126,7 +126,7 @@ async function main() { } // Check if we have the commit SHA needed for creating review comments - if (!pullRequest.head || !pullRequest.head.sha) { + if (!pullRequest || !pullRequest.head || !pullRequest.head.sha) { console.log( "Pull request head commit SHA not found in payload - cannot create review comments" ); @@ -223,7 +223,7 @@ async function main() { pull_number: pullRequestNumber, body: body, path: commentItem.path, - commit_id: pullRequest.head.sha, // Required for creating review comments + commit_id: pullRequest && pullRequest.head ? pullRequest.head.sha : "", // Required for creating review comments line: line, side: side, }; diff --git a/pkg/workflow/js/missing_tool.cjs b/pkg/workflow/js/missing_tool.cjs index 144e1db6ed2..2d4ba42bd85 100644 --- a/pkg/workflow/js/missing_tool.cjs +++ b/pkg/workflow/js/missing_tool.cjs @@ -13,6 +13,7 @@ async function main() { core.info(`Maximum reports allowed: ${maxReports}`); } + /** @type {any[]} */ const missingTools = []; // Return early if no agent output From 37b865023db592a1b55aa3cdb85a59de5798fa16 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:15:04 +0000 Subject: [PATCH 03/13] Improve error handling and type usage in workflow scripts; add guidance on avoiding 'any' type in documentation --- .../github-script.instructions.md | 5 ++- .../js/add_reaction_and_edit_comment.cjs | 3 +- pkg/workflow/js/check_permissions.cjs | 4 +-- pkg/workflow/js/collect_ndjson_output.cjs | 35 ++++++++++++------- pkg/workflow/js/create_discussion.cjs | 4 ++- pkg/workflow/js/create_pr_review_comment.cjs | 1 + pkg/workflow/js/push_to_pr_branch.cjs | 2 +- pkg/workflow/js/update_issue.cjs | 1 + pkg/workflow/js/validate_errors.cjs | 27 ++++++++++++-- 9 files changed, 61 insertions(+), 21 deletions(-) diff --git a/.github/instructions/github-script.instructions.md b/.github/instructions/github-script.instructions.md index 34a4d38ad67..104c9c709de 100644 --- a/.github/instructions/github-script.instructions.md +++ b/.github/instructions/github-script.instructions.md @@ -21,6 +21,7 @@ This JavaScript file will be run using the GitHub Action `actions/github-script@ ## Common errors +- avoid `any` type as much as possible, use specific types or `unknown` instead - catch handler: check if error is an instance of Error before accessing message property ```js @@ -35,4 +36,6 @@ catch (error) { Run `make js` to run the typescript compiler. -Run `make fmt:cjs` after editing to format the file. \ No newline at end of file +Run `make lint-cjs` to lint the files. + +Run `make fmt-cjs` after editing to format the file. \ No newline at end of file diff --git a/pkg/workflow/js/add_reaction_and_edit_comment.cjs b/pkg/workflow/js/add_reaction_and_edit_comment.cjs index 46ece9d958e..28fdf2a4618 100644 --- a/pkg/workflow/js/add_reaction_and_edit_comment.cjs +++ b/pkg/workflow/js/add_reaction_and_edit_comment.cjs @@ -183,7 +183,8 @@ async function editCommentWithWorkflowLink(endpoint, runUrl) { // Don't fail the entire job if comment editing fails - just log it const errorMessage = error instanceof Error ? error.message : String(error); core.warning( - "Failed to edit comment with workflow link (This is not critical - the reaction was still added successfully): " + errorMessage + "Failed to edit comment with workflow link (This is not critical - the reaction was still added successfully): " + + errorMessage ); } } diff --git a/pkg/workflow/js/check_permissions.cjs b/pkg/workflow/js/check_permissions.cjs index 8884c5fbe1a..6f496986d65 100644 --- a/pkg/workflow/js/check_permissions.cjs +++ b/pkg/workflow/js/check_permissions.cjs @@ -19,9 +19,7 @@ async function main() { core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setFailed( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index 45944ece279..ff2bba17ed4 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -290,8 +290,14 @@ async function main() { } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); - const originalMsg = originalError instanceof Error ? originalError.message : String(originalError); - const repairMsg = repairError instanceof Error ? repairError.message : String(repairError); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); @@ -332,10 +338,7 @@ async function main() { console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log( - "Warning: Could not parse safe-outputs config:", - errorMsg - ); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } @@ -404,8 +407,9 @@ async function main() { item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(/** @param {any} label */ label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -443,8 +447,9 @@ async function main() { } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(/** @param {any} label */ label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -456,14 +461,20 @@ async function main() { ); continue; } - if (item.labels.some(/** @param {any} label */ label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(/** @param {any} label */ label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": diff --git a/pkg/workflow/js/create_discussion.cjs b/pkg/workflow/js/create_discussion.cjs index fbb21e63ac1..a2418ea0e86 100644 --- a/pkg/workflow/js/create_discussion.cjs +++ b/pkg/workflow/js/create_discussion.cjs @@ -97,7 +97,9 @@ async function main() { queryResult.repository.discussionCategories.nodes || []; console.log( "Available categories:", - discussionCategories.map(/** @param {any} cat */ cat => ({ name: cat.name, id: cat.id })) + discussionCategories.map( + /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) + ) ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); diff --git a/pkg/workflow/js/create_pr_review_comment.cjs b/pkg/workflow/js/create_pr_review_comment.cjs index a235e7d55f2..feeb4a45793 100644 --- a/pkg/workflow/js/create_pr_review_comment.cjs +++ b/pkg/workflow/js/create_pr_review_comment.cjs @@ -217,6 +217,7 @@ async function main() { try { // Prepare the request parameters + /** @type {any} */ const requestParams = { owner: context.repo.owner, repo: context.repo.repo, diff --git a/pkg/workflow/js/push_to_pr_branch.cjs b/pkg/workflow/js/push_to_pr_branch.cjs index e6aed1cc9c4..39630ee4301 100644 --- a/pkg/workflow/js/push_to_pr_branch.cjs +++ b/pkg/workflow/js/push_to_pr_branch.cjs @@ -185,7 +185,7 @@ async function main() { } } catch (error) { console.log( - `Warning: Could not fetch PR ${pullNumber} details: ${error.message}` + `Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}` ); // Exit with failure if we cannot determine the branch name core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/pkg/workflow/js/update_issue.cjs b/pkg/workflow/js/update_issue.cjs index 3ba6e75142d..683d4ca274e 100644 --- a/pkg/workflow/js/update_issue.cjs +++ b/pkg/workflow/js/update_issue.cjs @@ -158,6 +158,7 @@ async function main() { console.log(`Updating issue #${issueNumber}`); // Build the update object based on allowed fields and provided values + /** @type {any} */ const updateData = {}; let hasUpdates = false; diff --git a/pkg/workflow/js/validate_errors.cjs b/pkg/workflow/js/validate_errors.cjs index ebeb88901e6..5320a38530a 100644 --- a/pkg/workflow/js/validate_errors.cjs +++ b/pkg/workflow/js/validate_errors.cjs @@ -31,7 +31,9 @@ function main() { } } catch (error) { console.debug(error); - core.setFailed(`Error validating log: ${error.message}`); + core.setFailed( + `Error validating log: ${error instanceof Error ? error.message : String(error)}` + ); } } @@ -51,11 +53,16 @@ function getErrorPatternsFromEnv() { return patterns; } catch (e) { throw new Error( - `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e.message}` + `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e instanceof Error ? e.message : String(e)}` ); } } +/** + * @param {string} logContent + * @param {any[]} patterns + * @returns {boolean} + */ function validateErrors(logContent, patterns) { const lines = logContent.split("\n"); let hasErrors = false; @@ -86,6 +93,11 @@ function validateErrors(logContent, patterns) { return hasErrors; } +/** + * @param {any} match + * @param {any} pattern + * @returns {string} + */ function extractLevel(match, pattern) { if ( pattern.level_group && @@ -106,6 +118,12 @@ function extractLevel(match, pattern) { return "unknown"; } +/** + * @param {any} match + * @param {any} pattern + * @param {any} fullLine + * @returns {string} + */ function extractMessage(match, pattern, fullLine) { if ( pattern.message_group && @@ -119,6 +137,11 @@ function extractMessage(match, pattern, fullLine) { return match[0] || fullLine.trim(); } +/** + * @param {any} str + * @param {any} maxLength + * @returns {string} + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; From d48e94662b15e643031fb6e3172cfe6bec4adfb5 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:22:46 +0000 Subject: [PATCH 04/13] Refactor logging to use core methods for consistency across workflow scripts --- pkg/workflow/js/compute_text.cjs | 4 +- pkg/workflow/js/create_pull_request.cjs | 76 ++++++++++++------------- pkg/workflow/js/parse_codex_log.cjs | 6 +- pkg/workflow/js/sanitize_output.cjs | 12 ++-- pkg/workflow/js/validate_errors.cjs | 2 +- 5 files changed, 46 insertions(+), 54 deletions(-) diff --git a/pkg/workflow/js/compute_text.cjs b/pkg/workflow/js/compute_text.cjs index d0100a81e45..e9b3f4a0392 100644 --- a/pkg/workflow/js/compute_text.cjs +++ b/pkg/workflow/js/compute_text.cjs @@ -200,7 +200,7 @@ async function main() { ); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); if (permission !== "admin" && permission !== "maintain") { core.setOutput("text", ""); @@ -267,7 +267,7 @@ async function main() { const sanitizedText = sanitizeContent(text); // Display sanitized text in logs - console.log(`text: ${sanitizedText}`); + core.debug(`text: ${sanitizedText}`); // Set the sanitized text as output core.setOutput("text", sanitizedText); diff --git a/pkg/workflow/js/create_pull_request.cjs b/pkg/workflow/js/create_pull_request.cjs index 591bb9623d0..f5f9dbc2844 100644 --- a/pkg/workflow/js/create_pull_request.cjs +++ b/pkg/workflow/js/create_pull_request.cjs @@ -21,7 +21,7 @@ async function main() { const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT || ""; if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); } const ifNoChanges = process.env.GITHUB_AW_PR_IF_NO_CHANGES || "warn"; @@ -41,7 +41,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( + core.info( "📝 Pull request creation preview written to step summary (no patch file)" ); return; @@ -55,7 +55,7 @@ async function main() { return; case "warn": default: - console.log(message); + core.warning(message); return; } } @@ -77,7 +77,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( + core.info( "📝 Pull request creation preview written to step summary (patch error)" ); return; @@ -91,7 +91,7 @@ async function main() { return; case "warn": default: - console.log(message); + core.warning(message); return; } } @@ -112,16 +112,16 @@ async function main() { return; case "warn": default: - console.log(message); + core.warning(message); return; } } - console.log("Agent output content length:", outputContent.length); + core.debug(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { - console.log("Patch content validation passed"); + core.info("Patch content validation passed"); } else { - console.log("Patch file is empty - processing noop operation"); + core.info("Patch file is empty - processing noop operation"); } // Parse the validated output JSON @@ -129,15 +129,14 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.error( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.warning("No valid items found in agent output"); return; } @@ -146,14 +145,11 @@ async function main() { /** @param {any} item */ item => item.type === "create-pull-request" ); if (!pullRequestItem) { - console.log("No create-pull-request item found in agent output"); + core.warning("No create-pull-request item found in agent output"); return; } - console.log("Found create-pull-request item:", { - title: pullRequestItem.title, - bodyLength: pullRequestItem.body.length, - }); + core.debug(`Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}`); // If in staged mode, emit step summary instead of creating PR if (isStaged) { @@ -181,7 +177,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Pull request creation preview written to step summary"); + core.info("📝 Pull request creation preview written to step summary"); return; } @@ -231,57 +227,55 @@ async function main() { const draftEnv = process.env.GITHUB_AW_PR_DRAFT; const draft = draftEnv ? draftEnv.toLowerCase() === "true" : true; - console.log("Creating pull request with title:", title); - console.log("Labels:", labels); - console.log("Draft:", draft); - console.log("Body length:", body.length); + core.info(`Creating pull request with title: ${title}`); + core.debug(`Labels: ${JSON.stringify(labels)}`); + core.debug(`Draft: ${draft}`); + core.debug(`Body length: ${body.length}`); const randomHex = crypto.randomBytes(8).toString("hex"); // Use branch name from JSONL if provided, otherwise generate unique branch name if (!branchName) { - console.log( + core.debug( "No branch name provided in JSONL, generating unique branch name" ); // Generate unique branch name using cryptographic random hex branchName = `${workflowId}-${randomHex}`; } else { branchName = `${branchName}-${randomHex}`; - console.log("Using branch name from JSONL with added salt:", branchName); + core.debug(`Using branch name from JSONL with added salt: ${branchName}`); } - console.log("Generated branch name:", branchName); - console.log("Base branch:", baseBranch); + core.info(`Generated branch name: ${branchName}`); + core.debug(`Base branch: ${baseBranch}`); // Create a new branch using git CLI, ensuring it's based on the correct base branch // First, fetch latest changes and checkout the base branch - console.log( - "Fetching latest changes and checking out base branch:", - baseBranch + core.debug( + `Fetching latest changes and checking out base branch: ${baseBranch}` ); execSync("git fetch origin", { stdio: "inherit" }); execSync(`git checkout ${baseBranch}`, { stdio: "inherit" }); // Handle branch creation/checkout - console.log( - "Branch should not exist locally, creating new branch from base:", - branchName + core.debug( + `Branch should not exist locally, creating new branch from base: ${branchName}` ); execSync(`git checkout -b ${branchName}`, { stdio: "inherit" }); - console.log("Created new branch from base:", branchName); + core.info(`Created new branch from base: ${branchName}`); // Apply the patch using git CLI (skip if empty) if (!isEmpty) { - console.log("Applying patch..."); + core.info("Applying patch..."); // Patches are created with git format-patch, so use git am to apply them execSync("git am /tmp/aw.patch", { stdio: "inherit" }); - console.log("Patch applied successfully"); + core.info("Patch applied successfully"); // Push the applied commits to the branch execSync(`git push origin ${branchName}`, { stdio: "inherit" }); - console.log("Changes pushed to branch"); + core.info("Changes pushed to branch"); } else { - console.log("Skipping patch application (empty patch)"); + core.info("Skipping patch application (empty patch)"); // For empty patches, handle if-no-changes configuration const message = @@ -297,7 +291,7 @@ async function main() { return; case "warn": default: - console.log(message); + core.warning(message); return; } } @@ -313,8 +307,8 @@ async function main() { draft: draft, }); - console.log( - "Created pull request #" + pullRequest.number + ": " + pullRequest.html_url + core.info( + `Created pull request #${pullRequest.number}: ${pullRequest.html_url}` ); // Add labels if specified diff --git a/pkg/workflow/js/parse_codex_log.cjs b/pkg/workflow/js/parse_codex_log.cjs index 970218ba01f..4f97a15e51f 100644 --- a/pkg/workflow/js/parse_codex_log.cjs +++ b/pkg/workflow/js/parse_codex_log.cjs @@ -4,12 +4,12 @@ function main() { try { const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } @@ -18,7 +18,7 @@ function main() { if (parsedLog) { core.summary.addRaw(parsedLog).write(); - console.log("Codex log parsed successfully"); + core.info("Codex log parsed successfully"); } else { core.error("Failed to parse Codex log"); } diff --git a/pkg/workflow/js/sanitize_output.cjs b/pkg/workflow/js/sanitize_output.cjs index 7d4166d3b11..5e65c4d92ba 100644 --- a/pkg/workflow/js/sanitize_output.cjs +++ b/pkg/workflow/js/sanitize_output.cjs @@ -188,27 +188,25 @@ async function main() { const fs = require("fs"); const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); } else { const sanitizedContent = sanitizeContent(outputContent); - console.log( - "Collected agentic output (sanitized):", - sanitizedContent.substring(0, 200) + - (sanitizedContent.length > 200 ? "..." : "") + core.info( + `Collected agentic output (sanitized): ${sanitizedContent.substring(0, 200)}${sanitizedContent.length > 200 ? "..." : ""}` ); core.setOutput("output", sanitizedContent); } diff --git a/pkg/workflow/js/validate_errors.cjs b/pkg/workflow/js/validate_errors.cjs index 5320a38530a..8bce08765d6 100644 --- a/pkg/workflow/js/validate_errors.cjs +++ b/pkg/workflow/js/validate_errors.cjs @@ -27,7 +27,7 @@ function main() { if (hasErrors) { core.setFailed("Errors detected in agent logs - failing workflow step"); } else { - console.log("Error validation completed successfully"); + core.info("Error validation completed successfully"); } } catch (error) { console.debug(error); From 6007fc2da6613c791588d32b4e3eef7d35aaa8f4 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:23:55 +0000 Subject: [PATCH 05/13] Disable noImplicitAny in tsconfig.json for improved compatibility with existing code --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 9fe8bd76711..22fd626d9d1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "outDir": "./dist/js", "rootDir": "./pkg/workflow/js", "strict": true, - "noImplicitAny": true, + "noImplicitAny": false, "strictNullChecks": true, "strictFunctionTypes": false, "noImplicitThis": false, From 39b9835ae0acbfb68025e67651102ad1bc3a94e4 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:26:06 +0000 Subject: [PATCH 06/13] Enable strict type checks by setting noImplicitAny, strictFunctionTypes, noImplicitThis, and noImplicitReturns to true in tsconfig.json --- tsconfig.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 22fd626d9d1..13c27d751b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,9 +12,9 @@ "strict": true, "noImplicitAny": false, "strictNullChecks": true, - "strictFunctionTypes": false, - "noImplicitThis": false, - "noImplicitReturns": false, + "strictFunctionTypes": true, + "noImplicitThis": true, + "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, From b289750c00cc9bbc33bae048e16bd60e9c4b2967 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:27:08 +0000 Subject: [PATCH 07/13] Refactor error handling and add JSDoc comments across workflow files - Improved error handling in Claude and Codex workflows by ensuring error messages are properly formatted and checked for instance type. - Added JSDoc comments to various functions to enhance code documentation and maintainability, including: - `parseClaudeLog` - `formatToolUse` - `formatMcpName` - `formatMcpParameters` - `formatBashCommand` - `truncateString` - `parseCodexLog` - `validateErrors` - `extractLevel` - `extractMessage` - Updated logging statements to use `core.info` for consistency and clarity in output. --- .github/workflows/ci-doctor.lock.yml | 86 +++++++++--- ...est-safe-output-add-issue-comment.lock.yml | 55 +++++--- .../test-safe-output-add-issue-label.lock.yml | 55 +++++--- ...output-create-code-scanning-alert.lock.yml | 56 +++++--- ...est-safe-output-create-discussion.lock.yml | 59 +++++--- .../test-safe-output-create-issue.lock.yml | 63 +++++---- ...reate-pull-request-review-comment.lock.yml | 62 ++++++--- ...t-safe-output-create-pull-request.lock.yml | 131 ++++++++++-------- .../test-safe-output-missing-tool.lock.yml | 48 +++++-- ...est-safe-output-push-to-pr-branch.lock.yml | 57 +++++--- .../test-safe-output-update-issue.lock.yml | 56 +++++--- .../test-ai-inference-github-models.lock.yml | 39 +++++- .../test-claude-add-issue-comment.lock.yml | 39 +++++- .../test-claude-add-issue-labels.lock.yml | 39 +++++- .../workflows/test-claude-command.lock.yml | 39 +++++- .../test-claude-create-issue.lock.yml | 39 +++++- ...reate-pull-request-review-comment.lock.yml | 39 +++++- .../test-claude-create-pull-request.lock.yml | 39 +++++- ...eate-repository-security-advisory.lock.yml | 39 +++++- pkg/cli/workflows/test-claude-mcp.lock.yml | 39 +++++- .../test-claude-push-to-pr-branch.lock.yml | 39 +++++- .../test-claude-update-issue.lock.yml | 39 +++++- .../test-codex-add-issue-comment.lock.yml | 60 ++++++-- .../test-codex-add-issue-labels.lock.yml | 60 ++++++-- pkg/cli/workflows/test-codex-command.lock.yml | 60 ++++++-- 25 files changed, 1024 insertions(+), 313 deletions(-) diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 534c08c6db9..a5a5be1a0e7 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -617,7 +617,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -667,6 +667,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -742,8 +743,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -768,16 +777,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -788,6 +796,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -838,8 +847,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -875,8 +885,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -887,14 +898,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1205,7 +1222,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1236,7 +1254,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1292,10 +1311,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -1435,9 +1459,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -1524,6 +1555,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -1536,6 +1572,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -1550,6 +1591,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -1569,6 +1615,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/.github/workflows/test-safe-output-add-issue-comment.lock.yml b/.github/workflows/test-safe-output-add-issue-comment.lock.yml index b33ef09f785..e7e4ed23232 100644 --- a/.github/workflows/test-safe-output-add-issue-comment.lock.yml +++ b/.github/workflows/test-safe-output-add-issue-comment.lock.yml @@ -52,9 +52,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -88,14 +86,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -450,7 +448,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -500,6 +498,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -575,8 +574,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -601,16 +608,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -621,6 +627,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -671,8 +678,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -708,8 +716,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -720,14 +729,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1038,7 +1053,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1069,7 +1085,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); diff --git a/.github/workflows/test-safe-output-add-issue-label.lock.yml b/.github/workflows/test-safe-output-add-issue-label.lock.yml index bff150a66fd..d57af8ebe40 100644 --- a/.github/workflows/test-safe-output-add-issue-label.lock.yml +++ b/.github/workflows/test-safe-output-add-issue-label.lock.yml @@ -54,9 +54,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -90,14 +88,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -454,7 +452,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -504,6 +502,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -579,8 +578,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -605,16 +612,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -625,6 +631,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -675,8 +682,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -712,8 +720,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -724,14 +733,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1042,7 +1057,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1073,7 +1089,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); diff --git a/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml b/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml index fee2be52feb..b0c4eaae2a8 100644 --- a/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml +++ b/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml @@ -56,9 +56,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -92,14 +90,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -476,7 +474,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -526,6 +524,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -601,8 +600,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -627,16 +634,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -647,6 +653,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -697,8 +704,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -734,8 +742,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -746,14 +755,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1064,7 +1079,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1095,7 +1111,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1319,6 +1336,7 @@ jobs: ruleIdSuffix = trimmedSuffix; } // Validate severity level and map to SARIF level + /** @type {Record} */ const severityMap = { error: "error", warning: "warning", diff --git a/.github/workflows/test-safe-output-create-discussion.lock.yml b/.github/workflows/test-safe-output-create-discussion.lock.yml index dc242b54875..d5721a91a41 100644 --- a/.github/workflows/test-safe-output-create-discussion.lock.yml +++ b/.github/workflows/test-safe-output-create-discussion.lock.yml @@ -51,9 +51,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -87,14 +85,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -441,7 +439,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -491,6 +489,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -566,8 +565,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -592,16 +599,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -612,6 +618,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -662,8 +669,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -699,8 +707,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -711,14 +720,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1029,7 +1044,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1060,7 +1076,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1196,7 +1213,9 @@ jobs: queryResult.repository.discussionCategories.nodes || []; console.log( "Available categories:", - discussionCategories.map(cat => ({ name: cat.name, id: cat.id })) + discussionCategories.map( + /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) + ) ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); diff --git a/.github/workflows/test-safe-output-create-issue.lock.yml b/.github/workflows/test-safe-output-create-issue.lock.yml index 7ed149ea4fa..f2b0efe530d 100644 --- a/.github/workflows/test-safe-output-create-issue.lock.yml +++ b/.github/workflows/test-safe-output-create-issue.lock.yml @@ -48,9 +48,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -84,14 +82,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -445,7 +443,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -495,6 +493,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -570,8 +569,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -596,16 +603,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -616,6 +622,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -666,8 +673,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -703,8 +711,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -715,14 +724,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1033,7 +1048,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1064,7 +1080,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1129,9 +1146,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -1165,14 +1180,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } diff --git a/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml b/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml index 4c51a1c98a5..b7299793fbc 100644 --- a/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml +++ b/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml @@ -50,9 +50,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -86,14 +84,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -458,7 +456,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -508,6 +506,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -583,8 +582,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -609,16 +616,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -629,6 +635,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -679,8 +686,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -716,8 +724,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -728,14 +737,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1046,7 +1061,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1077,7 +1093,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1213,7 +1230,7 @@ jobs: if (!pullRequest) { //No, github.event.issue.pull_request does not contain the full pull request data like head.sha. It only includes a minimal object with a url pointing to the pull request API resource. //To get full PR details (like head.sha, base.ref, etc.), you need to make an API call using that URL. - if (context.payload.issue.pull_request) { + if (context.payload.issue && context.payload.issue.pull_request) { // Fetch full pull request details using the GitHub API const prUrl = context.payload.issue.pull_request.url; try { @@ -1239,7 +1256,7 @@ jobs: } } // Check if we have the commit SHA needed for creating review comments - if (!pullRequest.head || !pullRequest.head.sha) { + if (!pullRequest || !pullRequest.head || !pullRequest.head.sha) { console.log( "Pull request head commit SHA not found in payload - cannot create review comments" ); @@ -1317,13 +1334,14 @@ jobs: console.log("Comment content length:", body.length); try { // Prepare the request parameters + /** @type {any} */ const requestParams = { owner: context.repo.owner, repo: context.repo.repo, pull_number: pullRequestNumber, body: body, path: commentItem.path, - commit_id: pullRequest.head.sha, // Required for creating review comments + commit_id: pullRequest && pullRequest.head ? pullRequest.head.sha : "", // Required for creating review comments line: line, side: side, }; diff --git a/.github/workflows/test-safe-output-create-pull-request.lock.yml b/.github/workflows/test-safe-output-create-pull-request.lock.yml index 4b5a8933cf2..d928c8668a0 100644 --- a/.github/workflows/test-safe-output-create-pull-request.lock.yml +++ b/.github/workflows/test-safe-output-create-pull-request.lock.yml @@ -49,9 +49,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -85,14 +83,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -474,7 +472,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -524,6 +522,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -599,8 +598,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -625,16 +632,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -645,6 +651,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -695,8 +702,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -732,8 +740,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -744,14 +753,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1062,7 +1077,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1093,7 +1109,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1297,7 +1314,7 @@ jobs: } const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT || ""; if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); } const ifNoChanges = process.env.GITHUB_AW_PR_IF_NO_CHANGES || "warn"; // Check if patch file exists and has valid content @@ -1313,7 +1330,7 @@ jobs: summaryContent += `**Message:** ${message}\n\n`; // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( + core.info( "📝 Pull request creation preview written to step summary (no patch file)" ); return; @@ -1326,7 +1343,7 @@ jobs: return; case "warn": default: - console.log(message); + core.warning(message); return; } } @@ -1344,7 +1361,7 @@ jobs: summaryContent += `**Message:** ${message}\n\n`; // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( + core.info( "📝 Pull request creation preview written to step summary (patch error)" ); return; @@ -1357,7 +1374,7 @@ jobs: return; case "warn": default: - console.log(message); + core.warning(message); return; } } @@ -1376,29 +1393,28 @@ jobs: return; case "warn": default: - console.log(message); + core.warning(message); return; } } - console.log("Agent output content length:", outputContent.length); + core.debug(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { - console.log("Patch content validation passed"); + core.info("Patch content validation passed"); } else { - console.log("Patch file is empty - processing noop operation"); + core.info("Patch file is empty - processing noop operation"); } // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.error( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.warning("No valid items found in agent output"); return; } // Find the create-pull-request item @@ -1406,13 +1422,10 @@ jobs: /** @param {any} item */ item => item.type === "create-pull-request" ); if (!pullRequestItem) { - console.log("No create-pull-request item found in agent output"); + core.warning("No create-pull-request item found in agent output"); return; } - console.log("Found create-pull-request item:", { - title: pullRequestItem.title, - bodyLength: pullRequestItem.body.length, - }); + core.debug(`Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}`); // If in staged mode, emit step summary instead of creating PR if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Create Pull Request Preview\n\n"; @@ -1435,7 +1448,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Pull request creation preview written to step summary"); + core.info("📝 Pull request creation preview written to step summary"); return; } // Extract title, body, and branch from the JSON item @@ -1477,50 +1490,48 @@ jobs: // Parse draft setting from environment variable (defaults to true) const draftEnv = process.env.GITHUB_AW_PR_DRAFT; const draft = draftEnv ? draftEnv.toLowerCase() === "true" : true; - console.log("Creating pull request with title:", title); - console.log("Labels:", labels); - console.log("Draft:", draft); - console.log("Body length:", body.length); + core.info(`Creating pull request with title: ${title}`); + core.debug(`Labels: ${JSON.stringify(labels)}`); + core.debug(`Draft: ${draft}`); + core.debug(`Body length: ${body.length}`); const randomHex = crypto.randomBytes(8).toString("hex"); // Use branch name from JSONL if provided, otherwise generate unique branch name if (!branchName) { - console.log( + core.debug( "No branch name provided in JSONL, generating unique branch name" ); // Generate unique branch name using cryptographic random hex branchName = `${workflowId}-${randomHex}`; } else { branchName = `${branchName}-${randomHex}`; - console.log("Using branch name from JSONL with added salt:", branchName); + core.debug(`Using branch name from JSONL with added salt: ${branchName}`); } - console.log("Generated branch name:", branchName); - console.log("Base branch:", baseBranch); + core.info(`Generated branch name: ${branchName}`); + core.debug(`Base branch: ${baseBranch}`); // Create a new branch using git CLI, ensuring it's based on the correct base branch // First, fetch latest changes and checkout the base branch - console.log( - "Fetching latest changes and checking out base branch:", - baseBranch + core.debug( + `Fetching latest changes and checking out base branch: ${baseBranch}` ); execSync("git fetch origin", { stdio: "inherit" }); execSync(`git checkout ${baseBranch}`, { stdio: "inherit" }); // Handle branch creation/checkout - console.log( - "Branch should not exist locally, creating new branch from base:", - branchName + core.debug( + `Branch should not exist locally, creating new branch from base: ${branchName}` ); execSync(`git checkout -b ${branchName}`, { stdio: "inherit" }); - console.log("Created new branch from base:", branchName); + core.info(`Created new branch from base: ${branchName}`); // Apply the patch using git CLI (skip if empty) if (!isEmpty) { - console.log("Applying patch..."); + core.info("Applying patch..."); // Patches are created with git format-patch, so use git am to apply them execSync("git am /tmp/aw.patch", { stdio: "inherit" }); - console.log("Patch applied successfully"); + core.info("Patch applied successfully"); // Push the applied commits to the branch execSync(`git push origin ${branchName}`, { stdio: "inherit" }); - console.log("Changes pushed to branch"); + core.info("Changes pushed to branch"); } else { - console.log("Skipping patch application (empty patch)"); + 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"; @@ -1534,7 +1545,7 @@ jobs: return; case "warn": default: - console.log(message); + core.warning(message); return; } } @@ -1548,8 +1559,8 @@ jobs: base: baseBranch, draft: draft, }); - console.log( - "Created pull request #" + pullRequest.number + ": " + pullRequest.html_url + core.info( + `Created pull request #${pullRequest.number}: ${pullRequest.html_url}` ); // Add labels if specified if (labels.length > 0) { diff --git a/.github/workflows/test-safe-output-missing-tool.lock.yml b/.github/workflows/test-safe-output-missing-tool.lock.yml index b0396cfb60e..59a978af4af 100644 --- a/.github/workflows/test-safe-output-missing-tool.lock.yml +++ b/.github/workflows/test-safe-output-missing-tool.lock.yml @@ -381,7 +381,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -431,6 +431,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -506,8 +507,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -532,16 +541,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -552,6 +560,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -602,8 +611,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -639,8 +649,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -651,14 +662,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -969,7 +986,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1000,7 +1018,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1060,6 +1079,7 @@ jobs: if (maxReports) { core.info(`Maximum reports allowed: ${maxReports}`); } + /** @type {any[]} */ const missingTools = []; // Return early if no agent output if (!agentOutput.trim()) { diff --git a/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml b/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml index bfda88579f3..f1e7a1666a2 100644 --- a/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml +++ b/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml @@ -50,9 +50,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -86,14 +84,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -478,7 +476,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -528,6 +526,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -603,8 +602,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -629,16 +636,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -649,6 +655,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -699,8 +706,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -736,8 +744,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -748,14 +757,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1066,7 +1081,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1097,7 +1113,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1444,7 +1461,7 @@ jobs: } } catch (error) { console.log( - `Warning: Could not fetch PR ${pullNumber} details: ${error.message}` + `Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}` ); // Exit with failure if we cannot determine the branch name core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/.github/workflows/test-safe-output-update-issue.lock.yml b/.github/workflows/test-safe-output-update-issue.lock.yml index be62dddc14c..0df2bba33f4 100644 --- a/.github/workflows/test-safe-output-update-issue.lock.yml +++ b/.github/workflows/test-safe-output-update-issue.lock.yml @@ -49,9 +49,7 @@ jobs: core.error( "❌ Configuration error: Required permissions not specified. Contact repository administrator." ); - core.setCancelled( - "Configuration error: Required permissions not specified" - ); + core.setFailed("Configuration error: Required permissions not specified"); return; } // Check if the actor has the required repository permissions @@ -85,14 +83,14 @@ jobs: const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); core.error(`Repository permission check failed: ${errorMessage}`); - core.setCancelled(`Repository permission check failed: ${errorMessage}`); + core.setFailed(`Repository permission check failed: ${errorMessage}`); return; } // Cancel the job when permission check fails core.warning( `❌ Access denied: Only authorized users can trigger this workflow. User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); - core.setCancelled( + core.setFailed( `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` ); } @@ -450,7 +448,7 @@ jobs: /** * Gets the maximum allowed count for a given output type * @param {string} itemType - The output item type - * @param {Object} config - The safe-outputs configuration + * @param {any} config - The safe-outputs configuration * @returns {number} The maximum allowed count */ function getMaxAllowedForType(itemType, config) { @@ -500,6 +498,7 @@ jobs: // U+0014 (DC4) — represented here as "\u0014" // Escape control characters not allowed in JSON strings (U+0000 through U+001F) // Preserve common JSON escapes for \b, \f, \n, \r, \t and use \uXXXX for the rest. + /** @type {Record} */ const _ctrl = { 8: "\\b", 9: "\\t", 10: "\\n", 12: "\\f", 13: "\\r" }; repaired = repaired.replace(/[\u0000-\u001F]/g, ch => { const c = ch.charCodeAt(0); @@ -575,8 +574,16 @@ jobs: } catch (repairError) { // If repair also fails, throw the error console.log(`invalid input json: ${jsonStr}`); + const originalMsg = + originalError instanceof Error + ? originalError.message + : String(originalError); + const repairMsg = + repairError instanceof Error + ? repairError.message + : String(repairError); throw new Error( - `JSON parsing failed. Original: ${originalError.message}. After attempted repair: ${repairError.message}` + `JSON parsing failed. Original: ${originalMsg}. After attempted repair: ${repairMsg}` ); } } @@ -601,16 +608,15 @@ jobs: } console.log("Raw output content length:", outputContent.length); // Parse the safe-outputs configuration + /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); console.log("Expected output types:", Object.keys(expectedOutputTypes)); } catch (error) { - console.log( - "Warning: Could not parse safe-outputs config:", - error.message - ); + const errorMsg = error instanceof Error ? error.message : String(error); + console.log("Warning: Could not parse safe-outputs config:", errorMsg); } } // Parse JSONL content @@ -621,6 +627,7 @@ jobs: const line = lines[i].trim(); if (line === "") continue; // Skip empty lines try { + /** @type {any} */ const item = parseJsonWithRepair(line); // If item is undefined (failed to parse), add error and process next line if (item === undefined) { @@ -671,8 +678,9 @@ jobs: item.body = sanitizeContent(item.body); // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -708,8 +716,9 @@ jobs: } // Sanitize labels if present if (item.labels && Array.isArray(item.labels)) { - item.labels = item.labels.map(label => - typeof label === "string" ? sanitizeContent(label) : label + item.labels = item.labels.map( + /** @param {any} label */ label => + typeof label === "string" ? sanitizeContent(label) : label ); } break; @@ -720,14 +729,20 @@ jobs: ); continue; } - if (item.labels.some(label => typeof label !== "string")) { + if ( + item.labels.some( + /** @param {any} label */ label => typeof label !== "string" + ) + ) { errors.push( `Line ${i + 1}: add-issue-label labels array must contain only strings` ); continue; } // Sanitize label strings - item.labels = item.labels.map(label => sanitizeContent(label)); + item.labels = item.labels.map( + /** @param {any} label */ label => sanitizeContent(label) + ); break; case "update-issue": // Check that at least one updateable field is provided @@ -1038,7 +1053,8 @@ jobs: console.log(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { - errors.push(`Line ${i + 1}: Invalid JSON - ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + errors.push(`Line ${i + 1}: Invalid JSON - ${errorMsg}`); } } // Report validation results @@ -1069,7 +1085,8 @@ jobs: // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { - core.error(`Failed to write agent output file: ${error.message}`); + const errorMsg = error instanceof Error ? error.message : String(error); + core.error(`Failed to write agent output file: ${errorMsg}`); } core.setOutput("output", JSON.stringify(validatedOutput)); core.setOutput("raw_output", outputContent); @@ -1259,6 +1276,7 @@ jobs: } console.log(`Updating issue #${issueNumber}`); // Build the update object based on allowed fields and provided values + /** @type {any} */ const updateData = {}; let hasUpdates = false; if (canUpdateStatus && updateItem.status !== undefined) { diff --git a/pkg/cli/workflows/test-ai-inference-github-models.lock.yml b/pkg/cli/workflows/test-ai-inference-github-models.lock.yml index 116108a0a7f..23880c0f022 100644 --- a/pkg/cli/workflows/test-ai-inference-github-models.lock.yml +++ b/pkg/cli/workflows/test-ai-inference-github-models.lock.yml @@ -328,10 +328,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -471,9 +476,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -560,6 +572,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -572,6 +589,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -586,6 +608,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -605,6 +632,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml b/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml index 1a26818fc9f..ea042419e21 100644 --- a/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml +++ b/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml @@ -325,10 +325,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -468,9 +473,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -557,6 +569,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -569,6 +586,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -583,6 +605,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -602,6 +629,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml b/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml index c028c79e6a9..c19dc109455 100644 --- a/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml +++ b/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml @@ -325,10 +325,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -468,9 +473,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -557,6 +569,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -569,6 +586,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -583,6 +605,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -602,6 +629,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-command.lock.yml b/pkg/cli/workflows/test-claude-command.lock.yml index 0684114a273..71857cc5e8d 100644 --- a/pkg/cli/workflows/test-claude-command.lock.yml +++ b/pkg/cli/workflows/test-claude-command.lock.yml @@ -325,10 +325,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -468,9 +473,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -557,6 +569,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -569,6 +586,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -583,6 +605,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -602,6 +629,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-create-issue.lock.yml b/pkg/cli/workflows/test-claude-create-issue.lock.yml index 10891bc8ef0..16045d212e9 100644 --- a/pkg/cli/workflows/test-claude-create-issue.lock.yml +++ b/pkg/cli/workflows/test-claude-create-issue.lock.yml @@ -325,10 +325,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -468,9 +473,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -557,6 +569,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -569,6 +586,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -583,6 +605,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -602,6 +629,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml b/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml index d79287e8af2..c59d326b3cf 100644 --- a/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml +++ b/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml @@ -325,10 +325,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -468,9 +473,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -557,6 +569,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -569,6 +586,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -583,6 +605,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -602,6 +629,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-create-pull-request.lock.yml b/pkg/cli/workflows/test-claude-create-pull-request.lock.yml index 3dad6655270..83c606b68ab 100644 --- a/pkg/cli/workflows/test-claude-create-pull-request.lock.yml +++ b/pkg/cli/workflows/test-claude-create-pull-request.lock.yml @@ -330,10 +330,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -473,9 +478,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -562,6 +574,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -574,6 +591,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -588,6 +610,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -607,6 +634,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml b/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml index d6b169aea2e..6a5875a3567 100644 --- a/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml +++ b/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml @@ -328,10 +328,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -471,9 +476,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -560,6 +572,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -572,6 +589,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -586,6 +608,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -605,6 +632,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-mcp.lock.yml b/pkg/cli/workflows/test-claude-mcp.lock.yml index 6b11c8eb98c..75f96ecbd35 100644 --- a/pkg/cli/workflows/test-claude-mcp.lock.yml +++ b/pkg/cli/workflows/test-claude-mcp.lock.yml @@ -328,10 +328,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -471,9 +476,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -560,6 +572,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -572,6 +589,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -586,6 +608,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -605,6 +632,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml b/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml index 86673712683..7cab44dec9d 100644 --- a/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml +++ b/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml @@ -330,10 +330,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -473,9 +478,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -562,6 +574,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -574,6 +591,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -588,6 +610,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -607,6 +634,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-claude-update-issue.lock.yml b/pkg/cli/workflows/test-claude-update-issue.lock.yml index 414cc3131cc..c5a019379b9 100644 --- a/pkg/cli/workflows/test-claude-update-issue.lock.yml +++ b/pkg/cli/workflows/test-claude-update-issue.lock.yml @@ -328,10 +328,15 @@ jobs: // Append to GitHub step summary core.summary.addRaw(markdown).write(); } catch (error) { - core.error(`Error parsing Claude log: ${error.message}`); - core.setFailed(error.message); + const errorMessage = error instanceof Error ? error.message : String(error); + core.setFailed(errorMessage); } } + /** + * Parses Claude log content and converts it to markdown format + * @param {string} logContent - The raw log content as a string + * @returns {string} Formatted markdown content + */ function parseClaudeLog(logContent) { try { const logEntries = JSON.parse(logContent); @@ -471,9 +476,16 @@ jobs: } return markdown; } catch (error) { - return `## Agent Log Summary\n\nError parsing Claude log: ${error.message}\n`; + const errorMessage = error instanceof Error ? error.message : String(error); + return `## Agent Log Summary\n\nError parsing Claude log: ${errorMessage}\n`; } } + /** + * Formats a tool use entry with its result into markdown + * @param {any} toolUse - The tool use object containing name, input, etc. + * @param {any} toolResult - The corresponding tool result object + * @returns {string} Formatted markdown string + */ function formatToolUse(toolUse, toolResult) { const toolName = toolUse.name; const input = toolUse.input || {}; @@ -560,6 +572,11 @@ jobs: } return markdown; } + /** + * Formats MCP tool name from internal format to display format + * @param {string} toolName - The raw tool name (e.g., mcp__github__search_issues) + * @returns {string} Formatted tool name (e.g., github::search_issues) + */ function formatMcpName(toolName) { // Convert mcp__github__search_issues to github::search_issues if (toolName.startsWith("mcp__")) { @@ -572,6 +589,11 @@ jobs: } return toolName; } + /** + * Formats MCP parameters into a human-readable string + * @param {Record} input - The input object containing parameters + * @returns {string} Formatted parameters string + */ function formatMcpParameters(input) { const keys = Object.keys(input); if (keys.length === 0) return ""; @@ -586,6 +608,11 @@ jobs: } return paramStrs.join(", "); } + /** + * Formats a bash command by normalizing whitespace and escaping + * @param {string} command - The raw bash command string + * @returns {string} Formatted and escaped command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -605,6 +632,12 @@ jobs: } return formatted; } + /** + * Truncates a string to a maximum length with ellipsis + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum allowed length + * @returns {string} Truncated string with ellipsis if needed + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-codex-add-issue-comment.lock.yml b/pkg/cli/workflows/test-codex-add-issue-comment.lock.yml index d47e523d1dd..d8768b05a6c 100644 --- a/pkg/cli/workflows/test-codex-add-issue-comment.lock.yml +++ b/pkg/cli/workflows/test-codex-add-issue-comment.lock.yml @@ -137,25 +137,30 @@ jobs: try { const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const content = fs.readFileSync(logFile, "utf8"); const parsedLog = parseCodexLog(content); if (parsedLog) { core.summary.addRaw(parsedLog).write(); - console.log("Codex log parsed successfully"); + core.info("Codex log parsed successfully"); } else { core.error("Failed to parse Codex log"); } } catch (error) { - core.setFailed(error.message); + core.setFailed(error instanceof Error ? error : String(error)); } } + /** + * Parse codex log content and format as markdown + * @param {string} logContent - The raw log content to parse + * @returns {string} Formatted markdown content + */ function parseCodexLog(logContent) { try { const lines = logContent.split("\n"); @@ -237,8 +242,11 @@ jobs: const tokenMatches = logContent.match(/tokens used: (\d+)/g); if (tokenMatches) { for (const match of tokenMatches) { - const tokens = parseInt(match.match(/(\d+)/)[1]); - totalTokens += tokens; + const numberMatch = match.match(/(\d+)/); + if (numberMatch) { + const tokens = parseInt(numberMatch[1]); + totalTokens += tokens; + } } } if (totalTokens > 0) { @@ -353,6 +361,11 @@ jobs: return "## 🤖 Commands and Tools\n\nError parsing log content.\n\n## 🤖 Reasoning\n\nUnable to parse reasoning from log.\n\n"; } } + /** + * Format bash command for display + * @param {string} command - The command to format + * @returns {string} Formatted command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -372,6 +385,12 @@ jobs: } return formatted; } + /** + * Truncate string to maximum length + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum length allowed + * @returns {string} Truncated string + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; @@ -421,11 +440,13 @@ jobs: if (hasErrors) { core.setFailed("Errors detected in agent logs - failing workflow step"); } else { - console.log("Error validation completed successfully"); + core.info("Error validation completed successfully"); } } catch (error) { console.debug(error); - core.setFailed(`Error validating log: ${error.message}`); + core.setFailed( + `Error validating log: ${error instanceof Error ? error.message : String(error)}` + ); } } function getErrorPatternsFromEnv() { @@ -443,10 +464,15 @@ jobs: return patterns; } catch (e) { throw new Error( - `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e.message}` + `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e instanceof Error ? e.message : String(e)}` ); } } + /** + * @param {string} logContent + * @param {any[]} patterns + * @returns {boolean} + */ function validateErrors(logContent, patterns) { const lines = logContent.split("\n"); let hasErrors = false; @@ -470,6 +496,11 @@ jobs: } return hasErrors; } + /** + * @param {any} match + * @param {any} pattern + * @returns {string} + */ function extractLevel(match, pattern) { if ( pattern.level_group && @@ -487,6 +518,12 @@ jobs: } return "unknown"; } + /** + * @param {any} match + * @param {any} pattern + * @param {any} fullLine + * @returns {string} + */ function extractMessage(match, pattern, fullLine) { if ( pattern.message_group && @@ -498,6 +535,11 @@ jobs: // Fallback to the full match or line return match[0] || fullLine.trim(); } + /** + * @param {any} str + * @param {any} maxLength + * @returns {string} + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-codex-add-issue-labels.lock.yml b/pkg/cli/workflows/test-codex-add-issue-labels.lock.yml index 1729380f519..3266ae21564 100644 --- a/pkg/cli/workflows/test-codex-add-issue-labels.lock.yml +++ b/pkg/cli/workflows/test-codex-add-issue-labels.lock.yml @@ -137,25 +137,30 @@ jobs: try { const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const content = fs.readFileSync(logFile, "utf8"); const parsedLog = parseCodexLog(content); if (parsedLog) { core.summary.addRaw(parsedLog).write(); - console.log("Codex log parsed successfully"); + core.info("Codex log parsed successfully"); } else { core.error("Failed to parse Codex log"); } } catch (error) { - core.setFailed(error.message); + core.setFailed(error instanceof Error ? error : String(error)); } } + /** + * Parse codex log content and format as markdown + * @param {string} logContent - The raw log content to parse + * @returns {string} Formatted markdown content + */ function parseCodexLog(logContent) { try { const lines = logContent.split("\n"); @@ -237,8 +242,11 @@ jobs: const tokenMatches = logContent.match(/tokens used: (\d+)/g); if (tokenMatches) { for (const match of tokenMatches) { - const tokens = parseInt(match.match(/(\d+)/)[1]); - totalTokens += tokens; + const numberMatch = match.match(/(\d+)/); + if (numberMatch) { + const tokens = parseInt(numberMatch[1]); + totalTokens += tokens; + } } } if (totalTokens > 0) { @@ -353,6 +361,11 @@ jobs: return "## 🤖 Commands and Tools\n\nError parsing log content.\n\n## 🤖 Reasoning\n\nUnable to parse reasoning from log.\n\n"; } } + /** + * Format bash command for display + * @param {string} command - The command to format + * @returns {string} Formatted command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -372,6 +385,12 @@ jobs: } return formatted; } + /** + * Truncate string to maximum length + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum length allowed + * @returns {string} Truncated string + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; @@ -421,11 +440,13 @@ jobs: if (hasErrors) { core.setFailed("Errors detected in agent logs - failing workflow step"); } else { - console.log("Error validation completed successfully"); + core.info("Error validation completed successfully"); } } catch (error) { console.debug(error); - core.setFailed(`Error validating log: ${error.message}`); + core.setFailed( + `Error validating log: ${error instanceof Error ? error.message : String(error)}` + ); } } function getErrorPatternsFromEnv() { @@ -443,10 +464,15 @@ jobs: return patterns; } catch (e) { throw new Error( - `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e.message}` + `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e instanceof Error ? e.message : String(e)}` ); } } + /** + * @param {string} logContent + * @param {any[]} patterns + * @returns {boolean} + */ function validateErrors(logContent, patterns) { const lines = logContent.split("\n"); let hasErrors = false; @@ -470,6 +496,11 @@ jobs: } return hasErrors; } + /** + * @param {any} match + * @param {any} pattern + * @returns {string} + */ function extractLevel(match, pattern) { if ( pattern.level_group && @@ -487,6 +518,12 @@ jobs: } return "unknown"; } + /** + * @param {any} match + * @param {any} pattern + * @param {any} fullLine + * @returns {string} + */ function extractMessage(match, pattern, fullLine) { if ( pattern.message_group && @@ -498,6 +535,11 @@ jobs: // Fallback to the full match or line return match[0] || fullLine.trim(); } + /** + * @param {any} str + * @param {any} maxLength + * @returns {string} + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; diff --git a/pkg/cli/workflows/test-codex-command.lock.yml b/pkg/cli/workflows/test-codex-command.lock.yml index 97a68429415..bca20703e84 100644 --- a/pkg/cli/workflows/test-codex-command.lock.yml +++ b/pkg/cli/workflows/test-codex-command.lock.yml @@ -137,25 +137,30 @@ jobs: try { const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const content = fs.readFileSync(logFile, "utf8"); const parsedLog = parseCodexLog(content); if (parsedLog) { core.summary.addRaw(parsedLog).write(); - console.log("Codex log parsed successfully"); + core.info("Codex log parsed successfully"); } else { core.error("Failed to parse Codex log"); } } catch (error) { - core.setFailed(error.message); + core.setFailed(error instanceof Error ? error : String(error)); } } + /** + * Parse codex log content and format as markdown + * @param {string} logContent - The raw log content to parse + * @returns {string} Formatted markdown content + */ function parseCodexLog(logContent) { try { const lines = logContent.split("\n"); @@ -237,8 +242,11 @@ jobs: const tokenMatches = logContent.match(/tokens used: (\d+)/g); if (tokenMatches) { for (const match of tokenMatches) { - const tokens = parseInt(match.match(/(\d+)/)[1]); - totalTokens += tokens; + const numberMatch = match.match(/(\d+)/); + if (numberMatch) { + const tokens = parseInt(numberMatch[1]); + totalTokens += tokens; + } } } if (totalTokens > 0) { @@ -353,6 +361,11 @@ jobs: return "## 🤖 Commands and Tools\n\nError parsing log content.\n\n## 🤖 Reasoning\n\nUnable to parse reasoning from log.\n\n"; } } + /** + * Format bash command for display + * @param {string} command - The command to format + * @returns {string} Formatted command string + */ function formatBashCommand(command) { if (!command) return ""; // Convert multi-line commands to single line by replacing newlines with spaces @@ -372,6 +385,12 @@ jobs: } return formatted; } + /** + * Truncate string to maximum length + * @param {string} str - The string to truncate + * @param {number} maxLength - Maximum length allowed + * @returns {string} Truncated string + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; @@ -421,11 +440,13 @@ jobs: if (hasErrors) { core.setFailed("Errors detected in agent logs - failing workflow step"); } else { - console.log("Error validation completed successfully"); + core.info("Error validation completed successfully"); } } catch (error) { console.debug(error); - core.setFailed(`Error validating log: ${error.message}`); + core.setFailed( + `Error validating log: ${error instanceof Error ? error.message : String(error)}` + ); } } function getErrorPatternsFromEnv() { @@ -443,10 +464,15 @@ jobs: return patterns; } catch (e) { throw new Error( - `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e.message}` + `Failed to parse GITHUB_AW_ERROR_PATTERNS as JSON: ${e instanceof Error ? e.message : String(e)}` ); } } + /** + * @param {string} logContent + * @param {any[]} patterns + * @returns {boolean} + */ function validateErrors(logContent, patterns) { const lines = logContent.split("\n"); let hasErrors = false; @@ -470,6 +496,11 @@ jobs: } return hasErrors; } + /** + * @param {any} match + * @param {any} pattern + * @returns {string} + */ function extractLevel(match, pattern) { if ( pattern.level_group && @@ -487,6 +518,12 @@ jobs: } return "unknown"; } + /** + * @param {any} match + * @param {any} pattern + * @param {any} fullLine + * @returns {string} + */ function extractMessage(match, pattern, fullLine) { if ( pattern.message_group && @@ -498,6 +535,11 @@ jobs: // Fallback to the full match or line return match[0] || fullLine.trim(); } + /** + * @param {any} str + * @param {any} maxLength + * @returns {string} + */ function truncateString(str, maxLength) { if (!str) return ""; if (str.length <= maxLength) return str; From 2ba7285ad5438e27e54980e21fb9d04c740e407f Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:36:46 +0000 Subject: [PATCH 08/13] more instructions --- .github/instructions/github-script.instructions.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/instructions/github-script.instructions.md b/.github/instructions/github-script.instructions.md index 104c9c709de..027e8c08e74 100644 --- a/.github/instructions/github-script.instructions.md +++ b/.github/instructions/github-script.instructions.md @@ -19,6 +19,14 @@ This JavaScript file will be run using the GitHub Action `actions/github-script@ - use `core.getInput` to get action inputs, with `required: true` for mandatory inputs - use `core.setFailed` to mark the action as failed with an error message +## Step summary + +Use `core.summary.*` function to write output the step summary file. + +- use `core.summary.addRaw()` to add raw Markdown content (GitHub Flavored Markdown supported) +- make sure to call `core.summary.write()` to flush pending writes +- summary function calls can be chained, e.g. `core.summary.addRaw(...).addRaw(...).write()` + ## Common errors - avoid `any` type as much as possible, use specific types or `unknown` instead From 09a88c90b4496bc21c9488529b285f5a53c79911 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:42:10 +0000 Subject: [PATCH 09/13] Refactor logging to use core.info, core.debug, and core.error in workflow scripts - Updated all instances of console.log to core.info for consistent logging across create_code_scanning_alert, create_comment, create_discussion, create_issue, create_pr_review_comment, create_pull_request, push_to_pr_branch, update_issue, and other workflow scripts. - Replaced console.error with core.error for error logging in parse_claude_log and other scripts. - Changed console.warn to core.warning where applicable to provide clearer logging semantics. - Enhanced log messages to include more context and structured information for better traceability. --- pkg/workflow/js/add_labels.cjs | 42 +++++------ pkg/workflow/js/add_reaction.cjs | 8 +- .../js/add_reaction_and_edit_comment.cjs | 28 ++++--- pkg/workflow/js/check_permissions.cjs | 12 +-- pkg/workflow/js/check_team_member.cjs | 6 +- pkg/workflow/js/collect_ndjson_output.cjs | 22 +++--- .../js/create_code_scanning_alert.cjs | 74 ++++++++----------- pkg/workflow/js/create_comment.cjs | 48 ++++++------ pkg/workflow/js/create_discussion.cjs | 54 ++++++-------- pkg/workflow/js/create_issue.cjs | 47 ++++++------ pkg/workflow/js/create_pr_review_comment.cjs | 70 ++++++++---------- pkg/workflow/js/create_pull_request.cjs | 6 +- pkg/workflow/js/parse_claude_log.cjs | 4 +- pkg/workflow/js/push_to_pr_branch.cjs | 56 +++++++------- pkg/workflow/js/update_issue.cjs | 61 ++++++++------- 15 files changed, 247 insertions(+), 291 deletions(-) diff --git a/pkg/workflow/js/add_labels.cjs b/pkg/workflow/js/add_labels.cjs index 6868949ca5b..d7f8c8a567d 100644 --- a/pkg/workflow/js/add_labels.cjs +++ b/pkg/workflow/js/add_labels.cjs @@ -2,31 +2,30 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.debug(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.error( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.warning("No valid items found in agent output"); return; } @@ -35,13 +34,13 @@ async function main() { /** @param {any} item */ item => item.type === "add-issue-label" ); if (!labelsItem) { - console.log("No add-issue-label item found in agent output"); + core.warning("No add-issue-label item found in agent output"); return; } - console.log("Found add-issue-label item:", { - labelsCount: labelsItem.labels.length, - }); + core.debug( + `Found add-issue-label item with ${labelsItem.labels.length} labels` + ); // If in staged mode, emit step summary instead of adding labels if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { @@ -61,7 +60,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Label addition preview written to step summary"); + core.info("📝 Label addition preview written to step summary"); return; } @@ -80,9 +79,9 @@ async function main() { } if (allowedLabels) { - console.log("Allowed labels:", allowedLabels); + core.debug(`Allowed labels: ${JSON.stringify(allowedLabels)}`); } else { - console.log("No label restrictions - any labels are allowed"); + core.debug("No label restrictions - any labels are allowed"); } // Read the max limit from environment variable (default: 3) @@ -95,7 +94,7 @@ async function main() { return; } - console.log("Max count:", maxCount); + core.debug(`Max count: ${maxCount}`); // Check if we're in an issue or pull request context const isIssueContext = @@ -143,7 +142,7 @@ async function main() { // Extract labels from the JSON item const requestedLabels = labelsItem.labels || []; - console.log("Requested labels:", requestedLabels); + core.debug(`Requested labels: ${JSON.stringify(requestedLabels)}`); // Check for label removal attempts (labels starting with '-') for (const label of requestedLabels) { @@ -171,12 +170,12 @@ async function main() { // Enforce max limit if (uniqueLabels.length > maxCount) { - console.log(`too many labels, keep ${maxCount}`); + core.debug(`too many labels, keep ${maxCount}`); uniqueLabels = uniqueLabels.slice(0, maxCount); } if (uniqueLabels.length === 0) { - console.log("No labels to add"); + core.info("No labels to add"); core.setOutput("labels_added", ""); await core.summary .addRaw( @@ -190,9 +189,8 @@ No labels were added (no valid labels found in agent output). return; } - console.log( - `Adding ${uniqueLabels.length} labels to ${contextType} #${issueNumber}:`, - uniqueLabels + core.info( + `Adding ${uniqueLabels.length} labels to ${contextType} #${issueNumber}: ${JSON.stringify(uniqueLabels)}` ); try { @@ -204,7 +202,7 @@ No labels were added (no valid labels found in agent output). labels: uniqueLabels, }); - console.log( + core.info( `Successfully added ${uniqueLabels.length} labels to ${contextType} #${issueNumber}` ); diff --git a/pkg/workflow/js/add_reaction.cjs b/pkg/workflow/js/add_reaction.cjs index a4594fa6f7a..e39ac5db8ad 100644 --- a/pkg/workflow/js/add_reaction.cjs +++ b/pkg/workflow/js/add_reaction.cjs @@ -2,7 +2,7 @@ async function main() { // Read inputs from environment variables const reaction = process.env.GITHUB_AW_REACTION || "eyes"; - console.log("Reaction type:", reaction); + core.info(`Reaction type:: ${reaction}`); // Validate reaction type const validReactions = [ @@ -73,7 +73,7 @@ async function main() { return; } - console.log("API endpoint:", endpoint); + core.info(`API endpoint:: ${endpoint}`); await addReaction(endpoint, reaction); } catch (error) { @@ -98,10 +98,10 @@ async function addReaction(endpoint, reaction) { const reactionId = response.data?.id; if (reactionId) { - console.log(`Successfully added reaction: ${reaction} (id: ${reactionId})`); + core.info(`Successfully added reaction: ${reaction} (id: ${reactionId})`); core.setOutput("reaction-id", reactionId.toString()); } else { - console.log(`Successfully added reaction: ${reaction}`); + core.info(`Successfully added reaction: ${reaction}`); core.setOutput("reaction-id", ""); } } diff --git a/pkg/workflow/js/add_reaction_and_edit_comment.cjs b/pkg/workflow/js/add_reaction_and_edit_comment.cjs index 28fdf2a4618..365d9aee0dd 100644 --- a/pkg/workflow/js/add_reaction_and_edit_comment.cjs +++ b/pkg/workflow/js/add_reaction_and_edit_comment.cjs @@ -7,10 +7,10 @@ async function main() { ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; - console.log("Reaction type:", reaction); - console.log("Command name:", command || "none"); - console.log("Run ID:", runId); - console.log("Run URL:", runUrl); + core.info(`Reaction type:: ${reaction}`); + core.info(`Command name:: ${command || "none"}`); + core.info(`Run ID:: ${runId}`); + core.info(`Run URL:: ${runUrl}`); // Validate reaction type const validReactions = [ @@ -92,22 +92,22 @@ async function main() { return; } - console.log("Reaction API endpoint:", reactionEndpoint); + core.info(`Reaction API endpoint:: ${reactionEndpoint}`); // Add reaction first await addReaction(reactionEndpoint, reaction); // Then edit comment if applicable and if it's a comment event if (shouldEditComment && commentUpdateEndpoint) { - console.log("Comment update endpoint:", commentUpdateEndpoint); + core.info(`Comment update endpoint:: ${commentUpdateEndpoint}`); await editCommentWithWorkflowLink(commentUpdateEndpoint, runUrl); } else { if (!command && commentUpdateEndpoint) { - console.log( + core.info( "Skipping comment edit - only available for command workflows" ); } else { - console.log("Skipping comment edit for event type:", eventName); + core.info(`Skipping comment edit for event type:: ${eventName}`); } } } catch (error) { @@ -134,10 +134,10 @@ async function addReaction(endpoint, reaction) { const reactionId = response.data?.id; if (reactionId) { - console.log(`Successfully added reaction: ${reaction} (id: ${reactionId})`); + core.info(`Successfully added reaction: ${reaction} (id: ${reactionId})`); core.setOutput("reaction-id", reactionId.toString()); } else { - console.log(`Successfully added reaction: ${reaction}`); + core.info(`Successfully added reaction: ${reaction}`); core.setOutput("reaction-id", ""); } } @@ -161,9 +161,7 @@ async function editCommentWithWorkflowLink(endpoint, runUrl) { // Check if we've already added a workflow link to avoid duplicates if (originalBody.includes("*🤖 [Workflow run](")) { - console.log( - "Comment already contains a workflow run link, skipping edit" - ); + core.info("Comment already contains a workflow run link, skipping edit"); return; } @@ -177,8 +175,8 @@ async function editCommentWithWorkflowLink(endpoint, runUrl) { }, }); - console.log(`Successfully updated comment with workflow link`); - console.log(`Comment ID: ${updateResponse.data.id}`); + core.info(`Successfully updated comment with workflow link`); + core.info(`Comment ID: ${updateResponse.data.id}`); } catch (error) { // Don't fail the entire job if comment editing fails - just log it const errorMessage = error instanceof Error ? error.message : String(error); diff --git a/pkg/workflow/js/check_permissions.cjs b/pkg/workflow/js/check_permissions.cjs index 6f496986d65..176271d4653 100644 --- a/pkg/workflow/js/check_permissions.cjs +++ b/pkg/workflow/js/check_permissions.cjs @@ -4,7 +4,7 @@ async function main() { // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } @@ -25,10 +25,10 @@ async function main() { // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ @@ -38,7 +38,7 @@ async function main() { }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { @@ -46,12 +46,12 @@ async function main() { permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { diff --git a/pkg/workflow/js/check_team_member.cjs b/pkg/workflow/js/check_team_member.cjs index 3a342bae627..ca8a1c43334 100644 --- a/pkg/workflow/js/check_team_member.cjs +++ b/pkg/workflow/js/check_team_member.cjs @@ -4,7 +4,7 @@ async function main() { // Check if the actor has repository access (admin, maintain permissions) try { - console.log( + core.info( `Checking if user '${actor}' is admin or maintainer of ${owner}/${repo}` ); @@ -16,10 +16,10 @@ async function main() { }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.info(`Repository permission level: ${permission}`); if (permission === "admin" || permission === "maintain") { - console.log(`User has ${permission} access to repository`); + core.info(`User has ${permission} access to repository`); core.setOutput("is_team_member", "true"); return; } diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index ff2bba17ed4..fc43fdac295 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -289,7 +289,7 @@ async function main() { return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -309,25 +309,25 @@ async function main() { const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist:: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length:: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ @@ -335,10 +335,12 @@ async function main() { if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } @@ -792,7 +794,7 @@ async function main() { continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -814,7 +816,7 @@ async function main() { // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { @@ -830,7 +832,7 @@ async function main() { // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/pkg/workflow/js/create_code_scanning_alert.cjs b/pkg/workflow/js/create_code_scanning_alert.cjs index 7f6ab54ccef..b1c906c9847 100644 --- a/pkg/workflow/js/create_code_scanning_alert.cjs +++ b/pkg/workflow/js/create_code_scanning_alert.cjs @@ -2,31 +2,30 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length:: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.info( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } @@ -35,13 +34,11 @@ async function main() { /** @param {any} item */ item => item.type === "create-code-scanning-alert" ); if (securityItems.length === 0) { - console.log("No create-code-scanning-alert items found in agent output"); + core.info("No create-code-scanning-alert items found in agent output"); return; } - console.log( - `Found ${securityItems.length} create-code-scanning-alert item(s)` - ); + core.info(`Found ${securityItems.length} create-code-scanning-alert item(s)`); // If in staged mode, emit step summary instead of creating code scanning alerts if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { @@ -62,7 +59,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( + core.info( "📝 Code scanning alert creation preview written to step summary" ); return; @@ -72,7 +69,7 @@ async function main() { const maxFindings = process.env.GITHUB_AW_SECURITY_REPORT_MAX ? parseInt(process.env.GITHUB_AW_SECURITY_REPORT_MAX) : 0; // 0 means unlimited - console.log( + core.info( `Max findings configuration: ${maxFindings === 0 ? "unlimited" : maxFindings}` ); @@ -80,34 +77,25 @@ async function main() { const driverName = process.env.GITHUB_AW_SECURITY_REPORT_DRIVER || "GitHub Agentic Workflows Security Scanner"; - console.log(`Driver name: ${driverName}`); + core.info(`Driver name: ${driverName}`); // Get the workflow filename for rule ID prefix const workflowFilename = process.env.GITHUB_AW_WORKFLOW_FILENAME || "workflow"; - console.log(`Workflow filename for rule ID prefix: ${workflowFilename}`); + core.info(`Workflow filename for rule ID prefix: ${workflowFilename}`); const validFindings = []; // Process each security item and validate the findings for (let i = 0; i < securityItems.length; i++) { const securityItem = securityItems[i]; - console.log( - `Processing create-code-scanning-alert item ${i + 1}/${securityItems.length}:`, - { - file: securityItem.file, - line: securityItem.line, - severity: securityItem.severity, - messageLength: securityItem.message - ? securityItem.message.length - : "undefined", - ruleIdSuffix: securityItem.ruleIdSuffix || "not specified", - } + core.info( + `Processing create-code-scanning-alert item ${i + 1}/${securityItems.length}: file=${securityItem.file}, line=${securityItem.line}, severity=${securityItem.severity}, messageLength=${securityItem.message ? securityItem.message.length : "undefined"}, ruleIdSuffix=${securityItem.ruleIdSuffix || "not specified"}` ); // Validate required fields if (!securityItem.file) { - console.log('Missing required field "file" in code scanning alert item'); + core.info('Missing required field "file" in code scanning alert item'); continue; } @@ -116,21 +104,21 @@ async function main() { (typeof securityItem.line !== "number" && typeof securityItem.line !== "string") ) { - console.log( + core.info( 'Missing or invalid required field "line" in code scanning alert item' ); continue; } if (!securityItem.severity || typeof securityItem.severity !== "string") { - console.log( + core.info( 'Missing or invalid required field "severity" in code scanning alert item' ); continue; } if (!securityItem.message || typeof securityItem.message !== "string") { - console.log( + core.info( 'Missing or invalid required field "message" in code scanning alert item' ); continue; @@ -139,7 +127,7 @@ async function main() { // Parse line number const line = parseInt(securityItem.line, 10); if (isNaN(line) || line <= 0) { - console.log(`Invalid line number: ${securityItem.line}`); + core.info(`Invalid line number: ${securityItem.line}`); continue; } @@ -150,14 +138,14 @@ async function main() { typeof securityItem.column !== "number" && typeof securityItem.column !== "string" ) { - console.log( + core.info( 'Invalid field "column" in code scanning alert item (must be number or string)' ); continue; } const parsedColumn = parseInt(securityItem.column, 10); if (isNaN(parsedColumn) || parsedColumn <= 0) { - console.log(`Invalid column number: ${securityItem.column}`); + core.info(`Invalid column number: ${securityItem.column}`); continue; } column = parsedColumn; @@ -167,7 +155,7 @@ async function main() { let ruleIdSuffix = null; if (securityItem.ruleIdSuffix !== undefined) { if (typeof securityItem.ruleIdSuffix !== "string") { - console.log( + core.info( 'Invalid field "ruleIdSuffix" in code scanning alert item (must be string)' ); continue; @@ -175,14 +163,14 @@ async function main() { // Validate that the suffix doesn't contain invalid characters const trimmedSuffix = securityItem.ruleIdSuffix.trim(); if (trimmedSuffix.length === 0) { - console.log( + core.info( 'Invalid field "ruleIdSuffix" in code scanning alert item (cannot be empty)' ); continue; } // Check for characters that would be problematic in rule IDs if (!/^[a-zA-Z0-9_-]+$/.test(trimmedSuffix)) { - console.log( + core.info( `Invalid ruleIdSuffix "${trimmedSuffix}" (must contain only alphanumeric characters, hyphens, and underscores)` ); continue; @@ -201,7 +189,7 @@ async function main() { const normalizedSeverity = securityItem.severity.toLowerCase(); if (!severityMap[normalizedSeverity]) { - console.log( + core.info( `Invalid severity level: ${securityItem.severity} (must be error, warning, info, or note)` ); continue; @@ -222,17 +210,17 @@ async function main() { // Check if we've reached the max limit if (maxFindings > 0 && validFindings.length >= maxFindings) { - console.log(`Reached maximum findings limit: ${maxFindings}`); + core.info(`Reached maximum findings limit: ${maxFindings}`); break; } } if (validFindings.length === 0) { - console.log("No valid security findings to report"); + core.info("No valid security findings to report"); return; } - console.log(`Processing ${validFindings.length} valid security finding(s)`); + core.info(`Processing ${validFindings.length} valid security finding(s)`); // Generate SARIF file const sarifContent = { @@ -278,8 +266,8 @@ async function main() { try { fs.writeFileSync(sarifFilePath, JSON.stringify(sarifContent, null, 2)); - console.log(`✓ Created SARIF file: ${sarifFilePath}`); - console.log(`SARIF file size: ${fs.statSync(sarifFilePath).size} bytes`); + core.info(`✓ Created SARIF file: ${sarifFilePath}`); + core.info(`SARIF file size: ${fs.statSync(sarifFilePath).size} bytes`); // Set outputs for the GitHub Action core.setOutput("sarif_file", sarifFilePath); @@ -312,7 +300,7 @@ async function main() { throw error; } - console.log( + core.info( `Successfully created code scanning alert with ${validFindings.length} finding(s)` ); return { diff --git a/pkg/workflow/js/create_comment.cjs b/pkg/workflow/js/create_comment.cjs index 7ed0fe27663..f27c526e886 100644 --- a/pkg/workflow/js/create_comment.cjs +++ b/pkg/workflow/js/create_comment.cjs @@ -5,31 +5,30 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length:: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.info( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } @@ -38,11 +37,11 @@ async function main() { /** @param {any} item */ item => item.type === "add-issue-comment" ); if (commentItems.length === 0) { - console.log("No add-issue-comment items found in agent output"); + core.info("No add-issue-comment items found in agent output"); return; } - console.log(`Found ${commentItems.length} add-issue-comment item(s)`); + core.info(`Found ${commentItems.length} add-issue-comment item(s)`); // If in staged mode, emit step summary instead of creating comments if (isStaged) { @@ -64,13 +63,13 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Comment creation preview written to step summary"); + core.info("📝 Comment creation preview written to step summary"); return; } // Get the target configuration from environment variable const commentTarget = process.env.GITHUB_AW_COMMENT_TARGET || "triggering"; - console.log(`Comment target configuration: ${commentTarget}`); + core.info(`Comment target configuration: ${commentTarget}`); // Check if we're in an issue or pull request context const isIssueContext = @@ -82,7 +81,7 @@ async function main() { // Validate context based on target configuration if (commentTarget === "triggering" && !isIssueContext && !isPRContext) { - console.log( + core.info( 'Target is "triggering" but not running in issue or pull request context, skipping comment creation' ); return; @@ -93,9 +92,8 @@ async function main() { // Process each comment item for (let i = 0; i < commentItems.length; i++) { const commentItem = commentItems[i]; - console.log( - `Processing add-issue-comment item ${i + 1}/${commentItems.length}:`, - { bodyLength: commentItem.body.length } + core.info( + `Processing add-issue-comment item ${i + 1}/${commentItems.length}: bodyLength=${commentItem.body.length}` ); // Determine the issue/PR number and comment endpoint for this comment @@ -107,14 +105,14 @@ async function main() { if (commentItem.issue_number) { issueNumber = parseInt(commentItem.issue_number, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number specified: ${commentItem.issue_number}` ); continue; } commentEndpoint = "issues"; } else { - console.log( + core.info( 'Target is "*" but no issue_number specified in comment item' ); continue; @@ -123,7 +121,7 @@ async function main() { // Explicit issue number specified in target issueNumber = parseInt(commentTarget, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number in target configuration: ${commentTarget}` ); continue; @@ -136,7 +134,7 @@ async function main() { issueNumber = context.payload.issue.number; commentEndpoint = "issues"; } else { - console.log("Issue context detected but no issue found in payload"); + core.info("Issue context detected but no issue found in payload"); continue; } } else if (isPRContext) { @@ -144,7 +142,7 @@ async function main() { issueNumber = context.payload.pull_request.number; commentEndpoint = "issues"; // PR comments use the issues API endpoint } else { - console.log( + core.info( "Pull request context detected but no pull request found in payload" ); continue; @@ -153,7 +151,7 @@ async function main() { } if (!issueNumber) { - console.log("Could not determine issue or pull request number"); + core.info("Could not determine issue or pull request number"); continue; } @@ -166,8 +164,8 @@ async function main() { : `https://github.com/actions/runs/${runId}`; body += `\n\n> Generated by Agentic Workflow [Run](${runUrl})\n`; - console.log(`Creating comment on ${commentEndpoint} #${issueNumber}`); - console.log("Comment content length:", body.length); + core.info(`Creating comment on ${commentEndpoint} #${issueNumber}`); + core.info(`Comment content length:: ${body.length}`); try { // Create the comment using GitHub API @@ -178,7 +176,7 @@ async function main() { body: body, }); - console.log("Created comment #" + comment.id + ": " + comment.html_url); + core.info("Created comment #" + comment.id + ": " + comment.html_url); createdComments.push(comment); // Set output for the last created comment (for backward compatibility) @@ -203,7 +201,7 @@ async function main() { await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully created ${createdComments.length} comment(s)`); + core.info(`Successfully created ${createdComments.length} comment(s)`); return createdComments; } await main(); diff --git a/pkg/workflow/js/create_discussion.cjs b/pkg/workflow/js/create_discussion.cjs index a2418ea0e86..6c0fc0fcdfe 100644 --- a/pkg/workflow/js/create_discussion.cjs +++ b/pkg/workflow/js/create_discussion.cjs @@ -2,30 +2,29 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.debug(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.error( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.warning("No valid items found in agent output"); return; } @@ -34,13 +33,11 @@ async function main() { /** @param {any} item */ item => item.type === "create-discussion" ); if (createDiscussionItems.length === 0) { - console.log("No create-discussion items found in agent output"); + core.warning("No create-discussion items found in agent output"); return; } - console.log( - `Found ${createDiscussionItems.length} create-discussion item(s)` - ); + core.debug(`Found ${createDiscussionItems.length} create-discussion item(s)`); // If in staged mode, emit step summary instead of creating discussions if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { @@ -63,7 +60,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Discussion creation preview written to step summary"); + core.info("📝 Discussion creation preview written to step summary"); return; } @@ -95,11 +92,10 @@ async function main() { repositoryId = queryResult.repository.id; discussionCategories = queryResult.repository.discussionCategories.nodes || []; - console.log( - "Available categories:", - discussionCategories.map( + core.info( + `Available categories: ${JSON.stringify(discussionCategories.map( /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) - ) + ))}` ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); @@ -110,10 +106,10 @@ async function main() { errorMessage.includes("not found") || errorMessage.includes("Could not resolve to a Repository") ) { - console.log( + core.info( "⚠ Cannot create discussions: Discussions are not enabled for this repository" ); - console.log( + core.info( "Consider enabling discussions in repository settings if you want to create discussions automatically" ); return; // Exit gracefully without creating discussions @@ -128,7 +124,7 @@ async function main() { if (!categoryId && discussionCategories.length > 0) { // Default to the first category if none specified categoryId = discussionCategories[0].id; - console.log( + core.info( `No category-id specified, using default category: ${discussionCategories[0].name} (${categoryId})` ); } @@ -149,12 +145,8 @@ async function main() { // Process each create-discussion item for (let i = 0; i < createDiscussionItems.length; i++) { const createDiscussionItem = createDiscussionItems[i]; - console.log( - `Processing create-discussion item ${i + 1}/${createDiscussionItems.length}:`, - { - title: createDiscussionItem.title, - bodyLength: createDiscussionItem.body.length, - } + core.info( + `Processing create-discussion item ${i + 1}/${createDiscussionItems.length}: title=${createDiscussionItem.title}, bodyLength=${createDiscussionItem.body.length}` ); // Extract title and body from the JSON item @@ -189,9 +181,9 @@ async function main() { // Prepare the body content const body = bodyLines.join("\n").trim(); - console.log("Creating discussion with title:", title); - console.log("Category ID:", categoryId); - console.log("Body length:", body.length); + core.info(`Creating discussion with title:: ${title}`); + core.info(`Category ID:: ${categoryId}`); + core.info(`Body length:: ${body.length}`); try { // Create the discussion using GraphQL API with parameterized mutation @@ -222,7 +214,7 @@ async function main() { const discussion = mutationResult.createDiscussion.discussion; - console.log( + core.info( "Created discussion #" + discussion.number + ": " + discussion.url ); createdDiscussions.push(discussion); @@ -249,8 +241,6 @@ async function main() { await core.summary.addRaw(summaryContent).write(); } - console.log( - `Successfully created ${createdDiscussions.length} discussion(s)` - ); + core.info(`Successfully created ${createdDiscussions.length} discussion(s)`); } await main(); diff --git a/pkg/workflow/js/create_issue.cjs b/pkg/workflow/js/create_issue.cjs index fa4deef9ec5..a960dbe0a4b 100644 --- a/pkg/workflow/js/create_issue.cjs +++ b/pkg/workflow/js/create_issue.cjs @@ -5,30 +5,29 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length:: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.info( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } @@ -37,11 +36,11 @@ async function main() { /** @param {any} item */ item => item.type === "create-issue" ); if (createIssueItems.length === 0) { - console.log("No create-issue items found in agent output"); + core.info("No create-issue items found in agent output"); return; } - console.log(`Found ${createIssueItems.length} create-issue item(s)`); + core.info(`Found ${createIssueItems.length} create-issue item(s)`); // If in staged mode, emit step summary instead of creating issues if (isStaged) { @@ -64,7 +63,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Issue creation preview written to step summary"); + core.info("📝 Issue creation preview written to step summary"); return; } @@ -85,9 +84,8 @@ async function main() { // Process each create-issue item for (let i = 0; i < createIssueItems.length; i++) { const createIssueItem = createIssueItems[i]; - console.log( - `Processing create-issue item ${i + 1}/${createIssueItems.length}:`, - { title: createIssueItem.title, bodyLength: createIssueItem.body.length } + core.info( + `Processing create-issue item ${i + 1}/${createIssueItems.length}: title=${createIssueItem.title}, bodyLength=${createIssueItem.body.length}` ); // Merge environment labels with item-specific labels @@ -112,7 +110,7 @@ async function main() { } if (parentIssueNumber) { - console.log("Detected issue context, parent issue #" + parentIssueNumber); + core.info("Detected issue context, parent issue #" + parentIssueNumber); // Add reference to parent issue in the child issue body bodyLines.push(`Related to #${parentIssueNumber}`); @@ -134,9 +132,9 @@ async function main() { // Prepare the body content const body = bodyLines.join("\n").trim(); - console.log("Creating issue with title:", title); - console.log("Labels:", labels); - console.log("Body length:", body.length); + core.info(`Creating issue with title:: ${title}`); + core.info(`Labels:: ${labels}`); + core.info(`Body length:: ${body.length}`); try { // Create the issue using GitHub API @@ -148,7 +146,7 @@ async function main() { labels: labels, }); - console.log("Created issue #" + issue.number + ": " + issue.html_url); + core.info("Created issue #" + issue.number + ": " + issue.html_url); createdIssues.push(issue); // If we have a parent issue, add a comment to it referencing the new child issue @@ -160,11 +158,10 @@ async function main() { issue_number: parentIssueNumber, body: `Created related issue: #${issue.number}`, }); - console.log("Added comment to parent issue #" + parentIssueNumber); + core.info("Added comment to parent issue #" + parentIssueNumber); } catch (error) { - console.log( - "Warning: Could not add comment to parent issue:", - error instanceof Error ? error.message : String(error) + core.info( + `Warning: Could not add comment to parent issue: ${error instanceof Error ? error.message : String(error)}` ); } } @@ -182,10 +179,10 @@ async function main() { if ( errorMessage.includes("Issues has been disabled in this repository") ) { - console.log( + core.info( `⚠ Cannot create issue "${title}": Issues are disabled for this repository` ); - console.log( + core.info( "Consider enabling issues in repository settings if you want to create issues automatically" ); continue; // Skip this issue but continue processing others @@ -205,6 +202,6 @@ async function main() { await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully created ${createdIssues.length} issue(s)`); + core.info(`Successfully created ${createdIssues.length} issue(s)`); } await main(); diff --git a/pkg/workflow/js/create_pr_review_comment.cjs b/pkg/workflow/js/create_pr_review_comment.cjs index feeb4a45793..d97c0f4287a 100644 --- a/pkg/workflow/js/create_pr_review_comment.cjs +++ b/pkg/workflow/js/create_pr_review_comment.cjs @@ -2,31 +2,30 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length:: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.info( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } @@ -36,13 +35,13 @@ async function main() { item.type === "create-pull-request-review-comment" ); if (reviewCommentItems.length === 0) { - console.log( + core.info( "No create-pull-request-review-comment items found in agent output" ); return; } - console.log( + core.info( `Found ${reviewCommentItems.length} create-pull-request-review-comment item(s)` ); @@ -68,15 +67,13 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( - "📝 PR review comment creation preview written to step summary" - ); + core.info("📝 PR review comment creation preview written to step summary"); return; } // Get the side configuration from environment variable const defaultSide = process.env.GITHUB_AW_PR_REVIEW_COMMENT_SIDE || "RIGHT"; - console.log(`Default comment side configuration: ${defaultSide}`); + core.info(`Default comment side configuration: ${defaultSide}`); // Check if we're in a pull request context, or an issue comment context on a PR const isPRContext = @@ -88,7 +85,7 @@ async function main() { context.payload.issue.pull_request); if (!isPRContext) { - console.log( + core.info( "Not running in pull request context, skipping review comment creation" ); return; @@ -109,16 +106,15 @@ async function main() { }, }); pullRequest = fullPR; - console.log("Fetched full pull request details from API"); + core.info("Fetched full pull request details from API"); } catch (error) { - console.log( - "Failed to fetch full pull request details:", - error instanceof Error ? error.message : String(error) + core.info( + `Failed to fetch full pull request details: ${error instanceof Error ? error.message : String(error)}` ); return; } } else { - console.log( + core.info( "Pull request data not found in payload - cannot create review comments" ); return; @@ -127,33 +123,27 @@ async function main() { // Check if we have the commit SHA needed for creating review comments if (!pullRequest || !pullRequest.head || !pullRequest.head.sha) { - console.log( + core.info( "Pull request head commit SHA not found in payload - cannot create review comments" ); return; } const pullRequestNumber = pullRequest.number; - console.log(`Creating review comments on PR #${pullRequestNumber}`); + core.info(`Creating review comments on PR #${pullRequestNumber}`); const createdComments = []; // Process each review comment item for (let i = 0; i < reviewCommentItems.length; i++) { const commentItem = reviewCommentItems[i]; - console.log( - `Processing create-pull-request-review-comment item ${i + 1}/${reviewCommentItems.length}:`, - { - bodyLength: commentItem.body ? commentItem.body.length : "undefined", - path: commentItem.path, - line: commentItem.line, - startLine: commentItem.start_line, - } + core.info( + `Processing create-pull-request-review-comment item ${i + 1}/${reviewCommentItems.length}: bodyLength=${commentItem.body ? commentItem.body.length : "undefined"}, path=${commentItem.path}, line=${commentItem.line}, startLine=${commentItem.start_line}` ); // Validate required fields if (!commentItem.path) { - console.log('Missing required field "path" in review comment item'); + core.info('Missing required field "path" in review comment item'); continue; } @@ -162,14 +152,14 @@ async function main() { (typeof commentItem.line !== "number" && typeof commentItem.line !== "string") ) { - console.log( + core.info( 'Missing or invalid required field "line" in review comment item' ); continue; } if (!commentItem.body || typeof commentItem.body !== "string") { - console.log( + core.info( 'Missing or invalid required field "body" in review comment item' ); continue; @@ -178,7 +168,7 @@ async function main() { // Parse line numbers const line = parseInt(commentItem.line, 10); if (isNaN(line) || line <= 0) { - console.log(`Invalid line number: ${commentItem.line}`); + core.info(`Invalid line number: ${commentItem.line}`); continue; } @@ -186,7 +176,7 @@ async function main() { if (commentItem.start_line) { startLine = parseInt(commentItem.start_line, 10); if (isNaN(startLine) || startLine <= 0 || startLine > line) { - console.log( + core.info( `Invalid start_line number: ${commentItem.start_line} (must be <= line: ${line})` ); continue; @@ -196,7 +186,7 @@ async function main() { // Determine side (LEFT or RIGHT) const side = commentItem.side || defaultSide; if (side !== "LEFT" && side !== "RIGHT") { - console.log(`Invalid side value: ${side} (must be LEFT or RIGHT)`); + core.info(`Invalid side value: ${side} (must be LEFT or RIGHT)`); continue; } @@ -210,10 +200,10 @@ async function main() { : `https://github.com/actions/runs/${runId}`; body += `\n\n> Generated by Agentic Workflow [Run](${runUrl})\n`; - console.log( + core.info( `Creating review comment on PR #${pullRequestNumber} at ${commentItem.path}:${line}${startLine ? ` (lines ${startLine}-${line})` : ""} [${side}]` ); - console.log("Comment content length:", body.length); + core.info(`Comment content length:: ${body.length}`); try { // Prepare the request parameters @@ -239,7 +229,7 @@ async function main() { const { data: comment } = await github.rest.pulls.createReviewComment(requestParams); - console.log( + core.info( "Created review comment #" + comment.id + ": " + comment.html_url ); createdComments.push(comment); @@ -266,9 +256,7 @@ async function main() { await core.summary.addRaw(summaryContent).write(); } - console.log( - `Successfully created ${createdComments.length} review comment(s)` - ); + core.info(`Successfully created ${createdComments.length} review comment(s)`); return createdComments; } await main(); diff --git a/pkg/workflow/js/create_pull_request.cjs b/pkg/workflow/js/create_pull_request.cjs index f5f9dbc2844..b0ea9bd04af 100644 --- a/pkg/workflow/js/create_pull_request.cjs +++ b/pkg/workflow/js/create_pull_request.cjs @@ -149,7 +149,9 @@ async function main() { return; } - core.debug(`Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}`); + core.debug( + `Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}` + ); // If in staged mode, emit step summary instead of creating PR if (isStaged) { @@ -319,7 +321,7 @@ async function main() { issue_number: pullRequest.number, labels: labels, }); - console.log("Added labels to pull request:", labels); + core.info(`Added labels to pull request: ${JSON.stringify(labels)}`); } // Set output for other jobs to use diff --git a/pkg/workflow/js/parse_claude_log.cjs b/pkg/workflow/js/parse_claude_log.cjs index c4230bcec9a..b04e3e60885 100644 --- a/pkg/workflow/js/parse_claude_log.cjs +++ b/pkg/workflow/js/parse_claude_log.cjs @@ -5,12 +5,12 @@ function main() { // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } diff --git a/pkg/workflow/js/push_to_pr_branch.cjs b/pkg/workflow/js/push_to_pr_branch.cjs index 39630ee4301..d3cf6b112aa 100644 --- a/pkg/workflow/js/push_to_pr_branch.cjs +++ b/pkg/workflow/js/push_to_pr_branch.cjs @@ -6,7 +6,7 @@ async function main() { // Environment validation - fail early if required variables are missing const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT || ""; if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } @@ -26,7 +26,7 @@ async function main() { return; case "warn": default: - console.log(message); + core.info(message); return; } } @@ -47,7 +47,7 @@ async function main() { return; case "warn": default: - console.log(message); + core.info(message); return; } } @@ -69,31 +69,30 @@ async function main() { break; case "warn": default: - console.log(message); + core.info(message); break; } } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length:: ${outputContent.length}`); if (!isEmpty) { - console.log("Patch content validation passed"); + core.info("Patch content validation passed"); } - console.log("Target configuration:", target); + core.info(`Target configuration:: ${target}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.info( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } @@ -102,11 +101,11 @@ async function main() { /** @param {any} item */ item => item.type === "push-to-pr-branch" ); if (!pushItem) { - console.log("No push-to-pr-branch item found in agent output"); + core.info("No push-to-pr-branch item found in agent output"); return; } - console.log("Found push-to-pr-branch item"); + core.info("Found push-to-pr-branch item"); // If in staged mode, emit step summary instead of pushing changes if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { @@ -132,7 +131,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Push to PR branch preview written to step summary"); + core.info("📝 Push to PR branch preview written to step summary"); return; } @@ -184,7 +183,7 @@ async function main() { throw new Error("No head branch found for PR"); } } catch (error) { - console.log( + core.info( `Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}` ); // Exit with failure if we cannot determine the branch name @@ -192,13 +191,13 @@ async function main() { return; } - console.log("Target branch:", branchName); + core.info(`Target branch:: ${branchName}`); // Check if patch has actual changes (not just empty) const hasChanges = !isEmpty; // Switch to or create the target branch - console.log("Switching to branch:", branchName); + core.info(`Switching to branch:: ${branchName}`); try { // Try to checkout existing branch first execSync("git fetch origin", { stdio: "inherit" }); @@ -212,19 +211,18 @@ async function main() { execSync(`git checkout -B ${branchName} origin/${branchName}`, { stdio: "inherit", }); - console.log("Checked out existing branch from origin:", branchName); + core.info(`Checked out existing branch from origin:: ${branchName}`); } catch (originError) { // Branch doesn't exist on origin, check if it exists locally try { execSync(`git rev-parse --verify ${branchName}`, { stdio: "pipe" }); // Branch exists locally, check it out execSync(`git checkout ${branchName}`, { stdio: "inherit" }); - console.log("Checked out existing local branch:", branchName); + core.info(`Checked out existing local branch:: ${branchName}`); } catch (localError) { // Branch doesn't exist locally or on origin, create it from default branch - console.log( - "Branch does not exist, creating new branch from default branch:", - branchName + core.info( + `Branch does not exist, creating new branch from default branch: ${branchName}` ); // Get the default branch name @@ -232,7 +230,7 @@ async function main() { "git remote show origin | grep 'HEAD branch' | cut -d' ' -f5", { encoding: "utf8" } ).trim(); - console.log("Default branch:", defaultBranch); + core.info(`Default branch:: ${defaultBranch}`); // Ensure we have the latest default branch execSync(`git checkout ${defaultBranch}`, { stdio: "inherit" }); @@ -240,7 +238,7 @@ async function main() { // Create new branch from default branch execSync(`git checkout -b ${branchName}`, { stdio: "inherit" }); - console.log("Created new branch from default branch:", branchName); + core.info(`Created new branch from default branch:: ${branchName}`); } } } catch (error) { @@ -252,15 +250,15 @@ async function main() { // Apply the patch using git CLI (skip if empty) if (!isEmpty) { - console.log("Applying patch..."); + core.info("Applying patch..."); try { // Patches are created with git format-patch, so use git am to apply them execSync("git am /tmp/aw.patch", { stdio: "inherit" }); - console.log("Patch applied successfully"); + core.info("Patch applied successfully"); // Push the applied commits to the branch execSync(`git push origin ${branchName}`, { stdio: "inherit" }); - console.log("Changes committed and pushed to branch:", branchName); + core.info(`Changes committed and pushed to branch:: ${branchName}`); } catch (error) { core.error( `Failed to apply patch: ${error instanceof Error ? error.message : String(error)}` @@ -269,7 +267,7 @@ async function main() { return; } } else { - console.log("Skipping patch application (empty patch)"); + core.info("Skipping patch application (empty patch)"); // Handle if-no-changes configuration for empty patches const message = @@ -286,7 +284,7 @@ async function main() { break; case "warn": default: - console.log(message); + core.info(message); break; } } diff --git a/pkg/workflow/js/update_issue.cjs b/pkg/workflow/js/update_issue.cjs index 683d4ca274e..efbb01e87bf 100644 --- a/pkg/workflow/js/update_issue.cjs +++ b/pkg/workflow/js/update_issue.cjs @@ -5,31 +5,30 @@ async function main() { // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length:: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.info( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } @@ -38,11 +37,11 @@ async function main() { /** @param {any} item */ item => item.type === "update-issue" ); if (updateItems.length === 0) { - console.log("No update-issue items found in agent output"); + core.info("No update-issue items found in agent output"); return; } - console.log(`Found ${updateItems.length} update-issue item(s)`); + core.info(`Found ${updateItems.length} update-issue item(s)`); // If in staged mode, emit step summary instead of updating issues if (isStaged) { @@ -73,7 +72,7 @@ async function main() { // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Issue update preview written to step summary"); + core.info("📝 Issue update preview written to step summary"); return; } @@ -83,8 +82,8 @@ async function main() { const canUpdateTitle = process.env.GITHUB_AW_UPDATE_TITLE === "true"; const canUpdateBody = process.env.GITHUB_AW_UPDATE_BODY === "true"; - console.log(`Update target configuration: ${updateTarget}`); - console.log( + core.info(`Update target configuration: ${updateTarget}`); + core.info( `Can update status: ${canUpdateStatus}, title: ${canUpdateTitle}, body: ${canUpdateBody}` ); @@ -94,7 +93,7 @@ async function main() { // Validate context based on target configuration if (updateTarget === "triggering" && !isIssueContext) { - console.log( + core.info( 'Target is "triggering" but not running in issue context, skipping issue update' ); return; @@ -105,7 +104,7 @@ async function main() { // Process each update item for (let i = 0; i < updateItems.length; i++) { const updateItem = updateItems[i]; - console.log(`Processing update-issue item ${i + 1}/${updateItems.length}`); + core.info(`Processing update-issue item ${i + 1}/${updateItems.length}`); // Determine the issue number for this update let issueNumber; @@ -115,22 +114,20 @@ async function main() { if (updateItem.issue_number) { issueNumber = parseInt(updateItem.issue_number, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number specified: ${updateItem.issue_number}` ); continue; } } else { - console.log( - 'Target is "*" but no issue_number specified in update item' - ); + core.info('Target is "*" but no issue_number specified in update item'); continue; } } else if (updateTarget && updateTarget !== "triggering") { // Explicit issue number specified in target issueNumber = parseInt(updateTarget, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number in target configuration: ${updateTarget}` ); continue; @@ -141,21 +138,21 @@ async function main() { if (context.payload.issue) { issueNumber = context.payload.issue.number; } else { - console.log("Issue context detected but no issue found in payload"); + core.info("Issue context detected but no issue found in payload"); continue; } } else { - console.log("Could not determine issue number"); + core.info("Could not determine issue number"); continue; } } if (!issueNumber) { - console.log("Could not determine issue number"); + core.info("Could not determine issue number"); continue; } - console.log(`Updating issue #${issueNumber}`); + core.info(`Updating issue #${issueNumber}`); // Build the update object based on allowed fields and provided values /** @type {any} */ @@ -167,9 +164,9 @@ async function main() { if (updateItem.status === "open" || updateItem.status === "closed") { updateData.state = updateItem.status; hasUpdates = true; - console.log(`Will update status to: ${updateItem.status}`); + core.info(`Will update status to: ${updateItem.status}`); } else { - console.log( + core.info( `Invalid status value: ${updateItem.status}. Must be 'open' or 'closed'` ); } @@ -182,9 +179,9 @@ async function main() { ) { updateData.title = updateItem.title.trim(); hasUpdates = true; - console.log(`Will update title to: ${updateItem.title.trim()}`); + core.info(`Will update title to: ${updateItem.title.trim()}`); } else { - console.log("Invalid title value: must be a non-empty string"); + core.info("Invalid title value: must be a non-empty string"); } } @@ -192,14 +189,14 @@ async function main() { if (typeof updateItem.body === "string") { updateData.body = updateItem.body; hasUpdates = true; - console.log(`Will update body (length: ${updateItem.body.length})`); + core.info(`Will update body (length: ${updateItem.body.length})`); } else { - console.log("Invalid body value: must be a string"); + core.info("Invalid body value: must be a string"); } } if (!hasUpdates) { - console.log("No valid updates to apply for this item"); + core.info("No valid updates to apply for this item"); continue; } @@ -212,7 +209,7 @@ async function main() { ...updateData, }); - console.log("Updated issue #" + issue.number + ": " + issue.html_url); + core.info("Updated issue #" + issue.number + ": " + issue.html_url); updatedIssues.push(issue); // Set output for the last updated issue (for backward compatibility) @@ -237,7 +234,7 @@ async function main() { await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully updated ${updatedIssues.length} issue(s)`); + core.info(`Successfully updated ${updatedIssues.length} issue(s)`); return updatedIssues; } await main(); From e937f1efa1bb8350785bcfc931f0a54c02ea8960 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:49:27 +0000 Subject: [PATCH 10/13] Replace core.error with core.setFailed for improved error handling in JSON parsing across workflow scripts --- pkg/workflow/js/add_labels.cjs | 2 +- pkg/workflow/js/create_code_scanning_alert.cjs | 2 +- pkg/workflow/js/create_comment.cjs | 2 +- pkg/workflow/js/create_discussion.cjs | 10 ++++++---- pkg/workflow/js/create_issue.cjs | 2 +- pkg/workflow/js/create_pr_review_comment.cjs | 2 +- pkg/workflow/js/create_pull_request.cjs | 2 +- pkg/workflow/js/missing_tool.cjs | 2 +- pkg/workflow/js/push_to_pr_branch.cjs | 2 +- pkg/workflow/js/update_issue.cjs | 2 +- 10 files changed, 15 insertions(+), 13 deletions(-) diff --git a/pkg/workflow/js/add_labels.cjs b/pkg/workflow/js/add_labels.cjs index d7f8c8a567d..cfc5fd6bc88 100644 --- a/pkg/workflow/js/add_labels.cjs +++ b/pkg/workflow/js/add_labels.cjs @@ -18,7 +18,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.error( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/create_code_scanning_alert.cjs b/pkg/workflow/js/create_code_scanning_alert.cjs index b1c906c9847..7c5527c2a75 100644 --- a/pkg/workflow/js/create_code_scanning_alert.cjs +++ b/pkg/workflow/js/create_code_scanning_alert.cjs @@ -18,7 +18,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.info( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/create_comment.cjs b/pkg/workflow/js/create_comment.cjs index f27c526e886..3d2d22de22d 100644 --- a/pkg/workflow/js/create_comment.cjs +++ b/pkg/workflow/js/create_comment.cjs @@ -21,7 +21,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.info( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/create_discussion.cjs b/pkg/workflow/js/create_discussion.cjs index 6c0fc0fcdfe..ed5ce75294b 100644 --- a/pkg/workflow/js/create_discussion.cjs +++ b/pkg/workflow/js/create_discussion.cjs @@ -17,7 +17,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.error( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; @@ -93,9 +93,11 @@ async function main() { discussionCategories = queryResult.repository.discussionCategories.nodes || []; core.info( - `Available categories: ${JSON.stringify(discussionCategories.map( - /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) - ))}` + `Available categories: ${JSON.stringify( + discussionCategories.map( + /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) + ) + )}` ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); diff --git a/pkg/workflow/js/create_issue.cjs b/pkg/workflow/js/create_issue.cjs index a960dbe0a4b..b298589fe1f 100644 --- a/pkg/workflow/js/create_issue.cjs +++ b/pkg/workflow/js/create_issue.cjs @@ -20,7 +20,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.info( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/create_pr_review_comment.cjs b/pkg/workflow/js/create_pr_review_comment.cjs index d97c0f4287a..007e497246f 100644 --- a/pkg/workflow/js/create_pr_review_comment.cjs +++ b/pkg/workflow/js/create_pr_review_comment.cjs @@ -18,7 +18,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.info( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/create_pull_request.cjs b/pkg/workflow/js/create_pull_request.cjs index b0ea9bd04af..2e97b2deede 100644 --- a/pkg/workflow/js/create_pull_request.cjs +++ b/pkg/workflow/js/create_pull_request.cjs @@ -129,7 +129,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.error( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/missing_tool.cjs b/pkg/workflow/js/missing_tool.cjs index 2d4ba42bd85..4cb48a1ba51 100644 --- a/pkg/workflow/js/missing_tool.cjs +++ b/pkg/workflow/js/missing_tool.cjs @@ -29,7 +29,7 @@ async function main() { try { validatedOutput = JSON.parse(agentOutput); } catch (error) { - core.error( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/push_to_pr_branch.cjs b/pkg/workflow/js/push_to_pr_branch.cjs index d3cf6b112aa..8363da4f025 100644 --- a/pkg/workflow/js/push_to_pr_branch.cjs +++ b/pkg/workflow/js/push_to_pr_branch.cjs @@ -85,7 +85,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.info( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/pkg/workflow/js/update_issue.cjs b/pkg/workflow/js/update_issue.cjs index efbb01e87bf..ffdd1a7d501 100644 --- a/pkg/workflow/js/update_issue.cjs +++ b/pkg/workflow/js/update_issue.cjs @@ -21,7 +21,7 @@ async function main() { try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.info( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; From 382086cda004be7d82ea19f2b51a5924bdae5ff6 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:50:15 +0000 Subject: [PATCH 11/13] Refactor logging messages to use a single colon for consistency across workflow scripts --- pkg/workflow/js/add_reaction.cjs | 4 ++-- .../js/add_reaction_and_edit_comment.cjs | 14 +++++++------- pkg/workflow/js/collect_ndjson_output.cjs | 4 ++-- pkg/workflow/js/create_code_scanning_alert.cjs | 2 +- pkg/workflow/js/create_comment.cjs | 4 ++-- pkg/workflow/js/create_discussion.cjs | 6 +++--- pkg/workflow/js/create_issue.cjs | 8 ++++---- pkg/workflow/js/create_pr_review_comment.cjs | 4 ++-- pkg/workflow/js/push_to_pr_branch.cjs | 18 +++++++++--------- pkg/workflow/js/update_issue.cjs | 2 +- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/pkg/workflow/js/add_reaction.cjs b/pkg/workflow/js/add_reaction.cjs index e39ac5db8ad..ca824af5f80 100644 --- a/pkg/workflow/js/add_reaction.cjs +++ b/pkg/workflow/js/add_reaction.cjs @@ -2,7 +2,7 @@ async function main() { // Read inputs from environment variables const reaction = process.env.GITHUB_AW_REACTION || "eyes"; - core.info(`Reaction type:: ${reaction}`); + core.info(`Reaction type: ${reaction}`); // Validate reaction type const validReactions = [ @@ -73,7 +73,7 @@ async function main() { return; } - core.info(`API endpoint:: ${endpoint}`); + core.info(`API endpoint: ${endpoint}`); await addReaction(endpoint, reaction); } catch (error) { diff --git a/pkg/workflow/js/add_reaction_and_edit_comment.cjs b/pkg/workflow/js/add_reaction_and_edit_comment.cjs index 365d9aee0dd..d4a48fb10ae 100644 --- a/pkg/workflow/js/add_reaction_and_edit_comment.cjs +++ b/pkg/workflow/js/add_reaction_and_edit_comment.cjs @@ -7,10 +7,10 @@ async function main() { ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; - core.info(`Reaction type:: ${reaction}`); - core.info(`Command name:: ${command || "none"}`); - core.info(`Run ID:: ${runId}`); - core.info(`Run URL:: ${runUrl}`); + core.info(`Reaction type: ${reaction}`); + core.info(`Command name: ${command || "none"}`); + core.info(`Run ID: ${runId}`); + core.info(`Run URL: ${runUrl}`); // Validate reaction type const validReactions = [ @@ -92,14 +92,14 @@ async function main() { return; } - core.info(`Reaction API endpoint:: ${reactionEndpoint}`); + core.info(`Reaction API endpoint: ${reactionEndpoint}`); // Add reaction first await addReaction(reactionEndpoint, reaction); // Then edit comment if applicable and if it's a comment event if (shouldEditComment && commentUpdateEndpoint) { - core.info(`Comment update endpoint:: ${commentUpdateEndpoint}`); + core.info(`Comment update endpoint: ${commentUpdateEndpoint}`); await editCommentWithWorkflowLink(commentUpdateEndpoint, runUrl); } else { if (!command && commentUpdateEndpoint) { @@ -107,7 +107,7 @@ async function main() { "Skipping comment edit - only available for command workflows" ); } else { - core.info(`Skipping comment edit for event type:: ${eventName}`); + core.info(`Skipping comment edit for event type: ${eventName}`); } } } catch (error) { diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index fc43fdac295..0f0a1da0ecc 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -315,7 +315,7 @@ async function main() { } if (!fs.existsSync(outputFile)) { - core.info(`Output file does not exist:: ${outputFile}`); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } @@ -327,7 +327,7 @@ async function main() { return; } - core.info(`Raw output content length:: ${outputContent.length}`); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ diff --git a/pkg/workflow/js/create_code_scanning_alert.cjs b/pkg/workflow/js/create_code_scanning_alert.cjs index 7c5527c2a75..86460b25ac9 100644 --- a/pkg/workflow/js/create_code_scanning_alert.cjs +++ b/pkg/workflow/js/create_code_scanning_alert.cjs @@ -11,7 +11,7 @@ async function main() { return; } - core.info(`Agent output content length:: ${outputContent.length}`); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; diff --git a/pkg/workflow/js/create_comment.cjs b/pkg/workflow/js/create_comment.cjs index 3d2d22de22d..67693c46a9a 100644 --- a/pkg/workflow/js/create_comment.cjs +++ b/pkg/workflow/js/create_comment.cjs @@ -14,7 +14,7 @@ async function main() { return; } - core.info(`Agent output content length:: ${outputContent.length}`); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; @@ -165,7 +165,7 @@ async function main() { body += `\n\n> Generated by Agentic Workflow [Run](${runUrl})\n`; core.info(`Creating comment on ${commentEndpoint} #${issueNumber}`); - core.info(`Comment content length:: ${body.length}`); + core.info(`Comment content length: ${body.length}`); try { // Create the comment using GitHub API diff --git a/pkg/workflow/js/create_discussion.cjs b/pkg/workflow/js/create_discussion.cjs index ed5ce75294b..a4feaf4a386 100644 --- a/pkg/workflow/js/create_discussion.cjs +++ b/pkg/workflow/js/create_discussion.cjs @@ -183,9 +183,9 @@ async function main() { // Prepare the body content const body = bodyLines.join("\n").trim(); - core.info(`Creating discussion with title:: ${title}`); - core.info(`Category ID:: ${categoryId}`); - core.info(`Body length:: ${body.length}`); + core.info(`Creating discussion with title: ${title}`); + core.info(`Category ID: ${categoryId}`); + core.info(`Body length: ${body.length}`); try { // Create the discussion using GraphQL API with parameterized mutation diff --git a/pkg/workflow/js/create_issue.cjs b/pkg/workflow/js/create_issue.cjs index b298589fe1f..7399b26aef3 100644 --- a/pkg/workflow/js/create_issue.cjs +++ b/pkg/workflow/js/create_issue.cjs @@ -13,7 +13,7 @@ async function main() { return; } - core.info(`Agent output content length:: ${outputContent.length}`); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; @@ -132,9 +132,9 @@ async function main() { // Prepare the body content const body = bodyLines.join("\n").trim(); - core.info(`Creating issue with title:: ${title}`); - core.info(`Labels:: ${labels}`); - core.info(`Body length:: ${body.length}`); + core.info(`Creating issue with title: ${title}`); + core.info(`Labels: ${labels}`); + core.info(`Body length: ${body.length}`); try { // Create the issue using GitHub API diff --git a/pkg/workflow/js/create_pr_review_comment.cjs b/pkg/workflow/js/create_pr_review_comment.cjs index 007e497246f..e743a50baaf 100644 --- a/pkg/workflow/js/create_pr_review_comment.cjs +++ b/pkg/workflow/js/create_pr_review_comment.cjs @@ -11,7 +11,7 @@ async function main() { return; } - core.info(`Agent output content length:: ${outputContent.length}`); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; @@ -203,7 +203,7 @@ async function main() { core.info( `Creating review comment on PR #${pullRequestNumber} at ${commentItem.path}:${line}${startLine ? ` (lines ${startLine}-${line})` : ""} [${side}]` ); - core.info(`Comment content length:: ${body.length}`); + core.info(`Comment content length: ${body.length}`); try { // Prepare the request parameters diff --git a/pkg/workflow/js/push_to_pr_branch.cjs b/pkg/workflow/js/push_to_pr_branch.cjs index 8363da4f025..13357efe0d4 100644 --- a/pkg/workflow/js/push_to_pr_branch.cjs +++ b/pkg/workflow/js/push_to_pr_branch.cjs @@ -74,11 +74,11 @@ async function main() { } } - core.info(`Agent output content length:: ${outputContent.length}`); + core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { core.info("Patch content validation passed"); } - core.info(`Target configuration:: ${target}`); + core.info(`Target configuration: ${target}`); // Parse the validated output JSON let validatedOutput; @@ -191,13 +191,13 @@ async function main() { return; } - core.info(`Target branch:: ${branchName}`); + core.info(`Target branch: ${branchName}`); // Check if patch has actual changes (not just empty) const hasChanges = !isEmpty; // Switch to or create the target branch - core.info(`Switching to branch:: ${branchName}`); + core.info(`Switching to branch: ${branchName}`); try { // Try to checkout existing branch first execSync("git fetch origin", { stdio: "inherit" }); @@ -211,14 +211,14 @@ async function main() { execSync(`git checkout -B ${branchName} origin/${branchName}`, { stdio: "inherit", }); - core.info(`Checked out existing branch from origin:: ${branchName}`); + core.info(`Checked out existing branch from origin: ${branchName}`); } catch (originError) { // Branch doesn't exist on origin, check if it exists locally try { execSync(`git rev-parse --verify ${branchName}`, { stdio: "pipe" }); // Branch exists locally, check it out execSync(`git checkout ${branchName}`, { stdio: "inherit" }); - core.info(`Checked out existing local branch:: ${branchName}`); + core.info(`Checked out existing local branch: ${branchName}`); } catch (localError) { // Branch doesn't exist locally or on origin, create it from default branch core.info( @@ -230,7 +230,7 @@ async function main() { "git remote show origin | grep 'HEAD branch' | cut -d' ' -f5", { encoding: "utf8" } ).trim(); - core.info(`Default branch:: ${defaultBranch}`); + core.info(`Default branch: ${defaultBranch}`); // Ensure we have the latest default branch execSync(`git checkout ${defaultBranch}`, { stdio: "inherit" }); @@ -238,7 +238,7 @@ async function main() { // Create new branch from default branch execSync(`git checkout -b ${branchName}`, { stdio: "inherit" }); - core.info(`Created new branch from default branch:: ${branchName}`); + core.info(`Created new branch from default branch: ${branchName}`); } } } catch (error) { @@ -258,7 +258,7 @@ async function main() { // Push the applied commits to the branch execSync(`git push origin ${branchName}`, { stdio: "inherit" }); - core.info(`Changes committed and pushed to branch:: ${branchName}`); + core.info(`Changes committed and pushed to branch: ${branchName}`); } catch (error) { core.error( `Failed to apply patch: ${error instanceof Error ? error.message : String(error)}` diff --git a/pkg/workflow/js/update_issue.cjs b/pkg/workflow/js/update_issue.cjs index ffdd1a7d501..14cff6e31ae 100644 --- a/pkg/workflow/js/update_issue.cjs +++ b/pkg/workflow/js/update_issue.cjs @@ -14,7 +14,7 @@ async function main() { return; } - core.info(`Agent output content length:: ${outputContent.length}`); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; From ecc46e19c7f329f87c682264adfefefb72dca2f4 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 15:51:28 +0000 Subject: [PATCH 12/13] Refactor logging in GitHub Actions workflows to use core methods - Replaced console.log statements with core.info, core.debug, core.warning, and core.setFailed in multiple workflow files for improved logging consistency and clarity. - Updated workflows related to safe outputs, pull requests, issue updates, and agent logs to enhance error handling and output messaging. - Ensured that all log messages are appropriately categorized to facilitate better debugging and monitoring of workflow executions. --- .github/workflows/ci-doctor.lock.yml | 121 +++++++++--------- ...est-safe-output-add-issue-comment.lock.yml | 82 ++++++------ .../test-safe-output-add-issue-label.lock.yml | 76 +++++------ ...output-create-code-scanning-alert.lock.yml | 108 +++++++--------- ...est-safe-output-create-discussion.lock.yml | 92 +++++++------ .../test-safe-output-create-issue.lock.yml | 93 +++++++------- ...reate-pull-request-review-comment.lock.yml | 104 +++++++-------- ...t-safe-output-create-pull-request.lock.yml | 42 +++--- .../test-safe-output-missing-tool.lock.yml | 24 ++-- ...est-safe-output-push-to-pr-branch.lock.yml | 90 ++++++------- .../test-safe-output-update-issue.lock.yml | 95 +++++++------- .../test-ai-inference-github-models.lock.yml | 4 +- .../test-claude-add-issue-comment.lock.yml | 4 +- .../test-claude-add-issue-labels.lock.yml | 4 +- .../workflows/test-claude-command.lock.yml | 4 +- .../test-claude-create-issue.lock.yml | 4 +- ...reate-pull-request-review-comment.lock.yml | 4 +- .../test-claude-create-pull-request.lock.yml | 4 +- ...eate-repository-security-advisory.lock.yml | 4 +- pkg/cli/workflows/test-claude-mcp.lock.yml | 4 +- .../test-claude-push-to-pr-branch.lock.yml | 4 +- .../test-claude-update-issue.lock.yml | 4 +- 22 files changed, 473 insertions(+), 498 deletions(-) diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index a5a5be1a0e7..23cc041ce76 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -742,7 +742,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -760,32 +760,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1219,7 +1221,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1237,7 +1239,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1250,7 +1252,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1299,11 +1301,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); @@ -1669,27 +1671,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all create-issue items @@ -1697,10 +1698,10 @@ jobs: /** @param {any} item */ item => item.type === "create-issue" ); if (createIssueItems.length === 0) { - console.log("No create-issue items found in agent output"); + core.info("No create-issue items found in agent output"); return; } - console.log(`Found ${createIssueItems.length} create-issue item(s)`); + core.info(`Found ${createIssueItems.length} create-issue item(s)`); // If in staged mode, emit step summary instead of creating issues if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Create Issues Preview\n\n"; @@ -1720,7 +1721,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Issue creation preview written to step summary"); + core.info("📝 Issue creation preview written to step summary"); return; } // Check if we're in an issue context (triggered by an issue event) @@ -1737,9 +1738,8 @@ jobs: // Process each create-issue item for (let i = 0; i < createIssueItems.length; i++) { const createIssueItem = createIssueItems[i]; - console.log( - `Processing create-issue item ${i + 1}/${createIssueItems.length}:`, - { title: createIssueItem.title, bodyLength: createIssueItem.body.length } + core.info( + `Processing create-issue item ${i + 1}/${createIssueItems.length}: title=${createIssueItem.title}, bodyLength=${createIssueItem.body.length}` ); // Merge environment labels with item-specific labels let labels = [...envLabels]; @@ -1759,7 +1759,7 @@ jobs: title = titlePrefix + title; } if (parentIssueNumber) { - console.log("Detected issue context, parent issue #" + parentIssueNumber); + core.info("Detected issue context, parent issue #" + parentIssueNumber); // Add reference to parent issue in the child issue body bodyLines.push(`Related to #${parentIssueNumber}`); } @@ -1777,9 +1777,9 @@ jobs: ); // Prepare the body content const body = bodyLines.join("\n").trim(); - console.log("Creating issue with title:", title); - console.log("Labels:", labels); - console.log("Body length:", body.length); + core.info(`Creating issue with title: ${title}`); + core.info(`Labels: ${labels}`); + core.info(`Body length: ${body.length}`); try { // Create the issue using GitHub API const { data: issue } = await github.rest.issues.create({ @@ -1789,7 +1789,7 @@ jobs: body: body, labels: labels, }); - console.log("Created issue #" + issue.number + ": " + issue.html_url); + core.info("Created issue #" + issue.number + ": " + issue.html_url); createdIssues.push(issue); // If we have a parent issue, add a comment to it referencing the new child issue if (parentIssueNumber) { @@ -1800,11 +1800,10 @@ jobs: issue_number: parentIssueNumber, body: `Created related issue: #${issue.number}`, }); - console.log("Added comment to parent issue #" + parentIssueNumber); + core.info("Added comment to parent issue #" + parentIssueNumber); } catch (error) { - console.log( - "Warning: Could not add comment to parent issue:", - error instanceof Error ? error.message : String(error) + core.info( + `Warning: Could not add comment to parent issue: ${error instanceof Error ? error.message : String(error)}` ); } } @@ -1820,10 +1819,10 @@ jobs: if ( errorMessage.includes("Issues has been disabled in this repository") ) { - console.log( + core.info( `⚠ Cannot create issue "${title}": Issues are disabled for this repository` ); - console.log( + core.info( "Consider enabling issues in repository settings if you want to create issues automatically" ); continue; // Skip this issue but continue processing others @@ -1840,7 +1839,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully created ${createdIssues.length} issue(s)`); + core.info(`Successfully created ${createdIssues.length} issue(s)`); } await main(); @@ -1870,27 +1869,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all add-issue-comment items @@ -1898,10 +1896,10 @@ jobs: /** @param {any} item */ item => item.type === "add-issue-comment" ); if (commentItems.length === 0) { - console.log("No add-issue-comment items found in agent output"); + core.info("No add-issue-comment items found in agent output"); return; } - console.log(`Found ${commentItems.length} add-issue-comment item(s)`); + core.info(`Found ${commentItems.length} add-issue-comment item(s)`); // If in staged mode, emit step summary instead of creating comments if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Add Comments Preview\n\n"; @@ -1920,12 +1918,12 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Comment creation preview written to step summary"); + core.info("📝 Comment creation preview written to step summary"); return; } // Get the target configuration from environment variable const commentTarget = process.env.GITHUB_AW_COMMENT_TARGET || "triggering"; - console.log(`Comment target configuration: ${commentTarget}`); + core.info(`Comment target configuration: ${commentTarget}`); // Check if we're in an issue or pull request context const isIssueContext = context.eventName === "issues" || context.eventName === "issue_comment"; @@ -1935,7 +1933,7 @@ jobs: context.eventName === "pull_request_review_comment"; // Validate context based on target configuration if (commentTarget === "triggering" && !isIssueContext && !isPRContext) { - console.log( + core.info( 'Target is "triggering" but not running in issue or pull request context, skipping comment creation' ); return; @@ -1944,9 +1942,8 @@ jobs: // Process each comment item for (let i = 0; i < commentItems.length; i++) { const commentItem = commentItems[i]; - console.log( - `Processing add-issue-comment item ${i + 1}/${commentItems.length}:`, - { bodyLength: commentItem.body.length } + core.info( + `Processing add-issue-comment item ${i + 1}/${commentItems.length}: bodyLength=${commentItem.body.length}` ); // Determine the issue/PR number and comment endpoint for this comment let issueNumber; @@ -1956,14 +1953,14 @@ jobs: if (commentItem.issue_number) { issueNumber = parseInt(commentItem.issue_number, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number specified: ${commentItem.issue_number}` ); continue; } commentEndpoint = "issues"; } else { - console.log( + core.info( 'Target is "*" but no issue_number specified in comment item' ); continue; @@ -1972,7 +1969,7 @@ jobs: // Explicit issue number specified in target issueNumber = parseInt(commentTarget, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number in target configuration: ${commentTarget}` ); continue; @@ -1985,7 +1982,7 @@ jobs: issueNumber = context.payload.issue.number; commentEndpoint = "issues"; } else { - console.log("Issue context detected but no issue found in payload"); + core.info("Issue context detected but no issue found in payload"); continue; } } else if (isPRContext) { @@ -1993,7 +1990,7 @@ jobs: issueNumber = context.payload.pull_request.number; commentEndpoint = "issues"; // PR comments use the issues API endpoint } else { - console.log( + core.info( "Pull request context detected but no pull request found in payload" ); continue; @@ -2001,7 +1998,7 @@ jobs: } } if (!issueNumber) { - console.log("Could not determine issue or pull request number"); + core.info("Could not determine issue or pull request number"); continue; } // Extract body from the JSON item @@ -2012,8 +2009,8 @@ jobs: ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `https://github.com/actions/runs/${runId}`; body += `\n\n> Generated by Agentic Workflow [Run](${runUrl})\n`; - console.log(`Creating comment on ${commentEndpoint} #${issueNumber}`); - console.log("Comment content length:", body.length); + core.info(`Creating comment on ${commentEndpoint} #${issueNumber}`); + core.info(`Comment content length: ${body.length}`); try { // Create the comment using GitHub API const { data: comment } = await github.rest.issues.createComment({ @@ -2022,7 +2019,7 @@ jobs: issue_number: issueNumber, body: body, }); - console.log("Created comment #" + comment.id + ": " + comment.html_url); + core.info("Created comment #" + comment.id + ": " + comment.html_url); createdComments.push(comment); // Set output for the last created comment (for backward compatibility) if (i === commentItems.length - 1) { @@ -2044,7 +2041,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully created ${createdComments.length} comment(s)`); + core.info(`Successfully created ${createdComments.length} comment(s)`); return createdComments; } await main(); diff --git a/.github/workflows/test-safe-output-add-issue-comment.lock.yml b/.github/workflows/test-safe-output-add-issue-comment.lock.yml index e7e4ed23232..c3f57a6ffea 100644 --- a/.github/workflows/test-safe-output-add-issue-comment.lock.yml +++ b/.github/workflows/test-safe-output-add-issue-comment.lock.yml @@ -39,7 +39,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -57,10 +57,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -68,18 +68,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -573,7 +573,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -591,32 +591,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1050,7 +1052,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1068,7 +1070,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1081,7 +1083,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1142,27 +1144,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all add-issue-comment items @@ -1170,10 +1171,10 @@ jobs: /** @param {any} item */ item => item.type === "add-issue-comment" ); if (commentItems.length === 0) { - console.log("No add-issue-comment items found in agent output"); + core.info("No add-issue-comment items found in agent output"); return; } - console.log(`Found ${commentItems.length} add-issue-comment item(s)`); + core.info(`Found ${commentItems.length} add-issue-comment item(s)`); // If in staged mode, emit step summary instead of creating comments if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Add Comments Preview\n\n"; @@ -1192,12 +1193,12 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Comment creation preview written to step summary"); + core.info("📝 Comment creation preview written to step summary"); return; } // Get the target configuration from environment variable const commentTarget = process.env.GITHUB_AW_COMMENT_TARGET || "triggering"; - console.log(`Comment target configuration: ${commentTarget}`); + core.info(`Comment target configuration: ${commentTarget}`); // Check if we're in an issue or pull request context const isIssueContext = context.eventName === "issues" || context.eventName === "issue_comment"; @@ -1207,7 +1208,7 @@ jobs: context.eventName === "pull_request_review_comment"; // Validate context based on target configuration if (commentTarget === "triggering" && !isIssueContext && !isPRContext) { - console.log( + core.info( 'Target is "triggering" but not running in issue or pull request context, skipping comment creation' ); return; @@ -1216,9 +1217,8 @@ jobs: // Process each comment item for (let i = 0; i < commentItems.length; i++) { const commentItem = commentItems[i]; - console.log( - `Processing add-issue-comment item ${i + 1}/${commentItems.length}:`, - { bodyLength: commentItem.body.length } + core.info( + `Processing add-issue-comment item ${i + 1}/${commentItems.length}: bodyLength=${commentItem.body.length}` ); // Determine the issue/PR number and comment endpoint for this comment let issueNumber; @@ -1228,14 +1228,14 @@ jobs: if (commentItem.issue_number) { issueNumber = parseInt(commentItem.issue_number, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number specified: ${commentItem.issue_number}` ); continue; } commentEndpoint = "issues"; } else { - console.log( + core.info( 'Target is "*" but no issue_number specified in comment item' ); continue; @@ -1244,7 +1244,7 @@ jobs: // Explicit issue number specified in target issueNumber = parseInt(commentTarget, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number in target configuration: ${commentTarget}` ); continue; @@ -1257,7 +1257,7 @@ jobs: issueNumber = context.payload.issue.number; commentEndpoint = "issues"; } else { - console.log("Issue context detected but no issue found in payload"); + core.info("Issue context detected but no issue found in payload"); continue; } } else if (isPRContext) { @@ -1265,7 +1265,7 @@ jobs: issueNumber = context.payload.pull_request.number; commentEndpoint = "issues"; // PR comments use the issues API endpoint } else { - console.log( + core.info( "Pull request context detected but no pull request found in payload" ); continue; @@ -1273,7 +1273,7 @@ jobs: } } if (!issueNumber) { - console.log("Could not determine issue or pull request number"); + core.info("Could not determine issue or pull request number"); continue; } // Extract body from the JSON item @@ -1284,8 +1284,8 @@ jobs: ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `https://github.com/actions/runs/${runId}`; body += `\n\n> Generated by Agentic Workflow [Run](${runUrl})\n`; - console.log(`Creating comment on ${commentEndpoint} #${issueNumber}`); - console.log("Comment content length:", body.length); + core.info(`Creating comment on ${commentEndpoint} #${issueNumber}`); + core.info(`Comment content length: ${body.length}`); try { // Create the comment using GitHub API const { data: comment } = await github.rest.issues.createComment({ @@ -1294,7 +1294,7 @@ jobs: issue_number: issueNumber, body: body, }); - console.log("Created comment #" + comment.id + ": " + comment.html_url); + core.info("Created comment #" + comment.id + ": " + comment.html_url); createdComments.push(comment); // Set output for the last created comment (for backward compatibility) if (i === commentItems.length - 1) { @@ -1316,7 +1316,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully created ${createdComments.length} comment(s)`); + core.info(`Successfully created ${createdComments.length} comment(s)`); return createdComments; } await main(); diff --git a/.github/workflows/test-safe-output-add-issue-label.lock.yml b/.github/workflows/test-safe-output-add-issue-label.lock.yml index d57af8ebe40..9b5f44ff451 100644 --- a/.github/workflows/test-safe-output-add-issue-label.lock.yml +++ b/.github/workflows/test-safe-output-add-issue-label.lock.yml @@ -41,7 +41,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -59,10 +59,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -70,18 +70,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -577,7 +577,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -595,32 +595,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1054,7 +1056,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1072,7 +1074,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1085,7 +1087,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1144,27 +1146,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.debug(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.warning("No valid items found in agent output"); return; } // Find the add-issue-label item @@ -1172,12 +1173,12 @@ jobs: /** @param {any} item */ item => item.type === "add-issue-label" ); if (!labelsItem) { - console.log("No add-issue-label item found in agent output"); + core.warning("No add-issue-label item found in agent output"); return; } - console.log("Found add-issue-label item:", { - labelsCount: labelsItem.labels.length, - }); + core.debug( + `Found add-issue-label item with ${labelsItem.labels.length} labels` + ); // If in staged mode, emit step summary instead of adding labels if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { let summaryContent = "## 🎭 Staged Mode: Add Labels Preview\n\n"; @@ -1193,7 +1194,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Label addition preview written to step summary"); + core.info("📝 Label addition preview written to step summary"); return; } // Read the allowed labels from environment variable (optional) @@ -1209,9 +1210,9 @@ jobs: } } if (allowedLabels) { - console.log("Allowed labels:", allowedLabels); + core.debug(`Allowed labels: ${JSON.stringify(allowedLabels)}`); } else { - console.log("No label restrictions - any labels are allowed"); + core.debug("No label restrictions - any labels are allowed"); } // Read the max limit from environment variable (default: 3) const maxCountEnv = process.env.GITHUB_AW_LABELS_MAX_COUNT; @@ -1222,7 +1223,7 @@ jobs: ); return; } - console.log("Max count:", maxCount); + core.debug(`Max count: ${maxCount}`); // Check if we're in an issue or pull request context const isIssueContext = context.eventName === "issues" || context.eventName === "issue_comment"; @@ -1264,7 +1265,7 @@ jobs: } // Extract labels from the JSON item const requestedLabels = labelsItem.labels || []; - console.log("Requested labels:", requestedLabels); + core.debug(`Requested labels: ${JSON.stringify(requestedLabels)}`); // Check for label removal attempts (labels starting with '-') for (const label of requestedLabels) { if (label.startsWith("-")) { @@ -1288,11 +1289,11 @@ jobs: let uniqueLabels = [...new Set(validLabels)]; // Enforce max limit if (uniqueLabels.length > maxCount) { - console.log(`too many labels, keep ${maxCount}`); + core.debug(`too many labels, keep ${maxCount}`); uniqueLabels = uniqueLabels.slice(0, maxCount); } if (uniqueLabels.length === 0) { - console.log("No labels to add"); + core.info("No labels to add"); core.setOutput("labels_added", ""); await core.summary .addRaw( @@ -1304,9 +1305,8 @@ jobs: .write(); return; } - console.log( - `Adding ${uniqueLabels.length} labels to ${contextType} #${issueNumber}:`, - uniqueLabels + core.info( + `Adding ${uniqueLabels.length} labels to ${contextType} #${issueNumber}: ${JSON.stringify(uniqueLabels)}` ); try { // Add labels using GitHub API @@ -1316,7 +1316,7 @@ jobs: issue_number: issueNumber, labels: uniqueLabels, }); - console.log( + core.info( `Successfully added ${uniqueLabels.length} labels to ${contextType} #${issueNumber}` ); // Set output for other jobs to use diff --git a/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml b/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml index b0c4eaae2a8..c2ed36a411a 100644 --- a/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml +++ b/.github/workflows/test-safe-output-create-code-scanning-alert.lock.yml @@ -43,7 +43,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -61,10 +61,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -72,18 +72,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -599,7 +599,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -617,32 +617,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1076,7 +1078,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1094,7 +1096,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1107,7 +1109,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1169,27 +1171,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all create-code-scanning-alert items @@ -1197,12 +1198,10 @@ jobs: /** @param {any} item */ item => item.type === "create-code-scanning-alert" ); if (securityItems.length === 0) { - console.log("No create-code-scanning-alert items found in agent output"); + core.info("No create-code-scanning-alert items found in agent output"); return; } - console.log( - `Found ${securityItems.length} create-code-scanning-alert item(s)` - ); + core.info(`Found ${securityItems.length} create-code-scanning-alert item(s)`); // If in staged mode, emit step summary instead of creating code scanning alerts if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { let summaryContent = @@ -1220,7 +1219,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( + core.info( "📝 Code scanning alert creation preview written to step summary" ); return; @@ -1229,37 +1228,28 @@ jobs: const maxFindings = process.env.GITHUB_AW_SECURITY_REPORT_MAX ? parseInt(process.env.GITHUB_AW_SECURITY_REPORT_MAX) : 0; // 0 means unlimited - console.log( + core.info( `Max findings configuration: ${maxFindings === 0 ? "unlimited" : maxFindings}` ); // Get the driver configuration from environment variable const driverName = process.env.GITHUB_AW_SECURITY_REPORT_DRIVER || "GitHub Agentic Workflows Security Scanner"; - console.log(`Driver name: ${driverName}`); + core.info(`Driver name: ${driverName}`); // Get the workflow filename for rule ID prefix const workflowFilename = process.env.GITHUB_AW_WORKFLOW_FILENAME || "workflow"; - console.log(`Workflow filename for rule ID prefix: ${workflowFilename}`); + core.info(`Workflow filename for rule ID prefix: ${workflowFilename}`); const validFindings = []; // Process each security item and validate the findings for (let i = 0; i < securityItems.length; i++) { const securityItem = securityItems[i]; - console.log( - `Processing create-code-scanning-alert item ${i + 1}/${securityItems.length}:`, - { - file: securityItem.file, - line: securityItem.line, - severity: securityItem.severity, - messageLength: securityItem.message - ? securityItem.message.length - : "undefined", - ruleIdSuffix: securityItem.ruleIdSuffix || "not specified", - } + core.info( + `Processing create-code-scanning-alert item ${i + 1}/${securityItems.length}: file=${securityItem.file}, line=${securityItem.line}, severity=${securityItem.severity}, messageLength=${securityItem.message ? securityItem.message.length : "undefined"}, ruleIdSuffix=${securityItem.ruleIdSuffix || "not specified"}` ); // Validate required fields if (!securityItem.file) { - console.log('Missing required field "file" in code scanning alert item'); + core.info('Missing required field "file" in code scanning alert item'); continue; } if ( @@ -1267,19 +1257,19 @@ jobs: (typeof securityItem.line !== "number" && typeof securityItem.line !== "string") ) { - console.log( + core.info( 'Missing or invalid required field "line" in code scanning alert item' ); continue; } if (!securityItem.severity || typeof securityItem.severity !== "string") { - console.log( + core.info( 'Missing or invalid required field "severity" in code scanning alert item' ); continue; } if (!securityItem.message || typeof securityItem.message !== "string") { - console.log( + core.info( 'Missing or invalid required field "message" in code scanning alert item' ); continue; @@ -1287,7 +1277,7 @@ jobs: // Parse line number const line = parseInt(securityItem.line, 10); if (isNaN(line) || line <= 0) { - console.log(`Invalid line number: ${securityItem.line}`); + core.info(`Invalid line number: ${securityItem.line}`); continue; } // Parse optional column number @@ -1297,14 +1287,14 @@ jobs: typeof securityItem.column !== "number" && typeof securityItem.column !== "string" ) { - console.log( + core.info( 'Invalid field "column" in code scanning alert item (must be number or string)' ); continue; } const parsedColumn = parseInt(securityItem.column, 10); if (isNaN(parsedColumn) || parsedColumn <= 0) { - console.log(`Invalid column number: ${securityItem.column}`); + core.info(`Invalid column number: ${securityItem.column}`); continue; } column = parsedColumn; @@ -1313,7 +1303,7 @@ jobs: let ruleIdSuffix = null; if (securityItem.ruleIdSuffix !== undefined) { if (typeof securityItem.ruleIdSuffix !== "string") { - console.log( + core.info( 'Invalid field "ruleIdSuffix" in code scanning alert item (must be string)' ); continue; @@ -1321,14 +1311,14 @@ jobs: // Validate that the suffix doesn't contain invalid characters const trimmedSuffix = securityItem.ruleIdSuffix.trim(); if (trimmedSuffix.length === 0) { - console.log( + core.info( 'Invalid field "ruleIdSuffix" in code scanning alert item (cannot be empty)' ); continue; } // Check for characters that would be problematic in rule IDs if (!/^[a-zA-Z0-9_-]+$/.test(trimmedSuffix)) { - console.log( + core.info( `Invalid ruleIdSuffix "${trimmedSuffix}" (must contain only alphanumeric characters, hyphens, and underscores)` ); continue; @@ -1345,7 +1335,7 @@ jobs: }; const normalizedSeverity = securityItem.severity.toLowerCase(); if (!severityMap[normalizedSeverity]) { - console.log( + core.info( `Invalid severity level: ${securityItem.severity} (must be error, warning, info, or note)` ); continue; @@ -1363,15 +1353,15 @@ jobs: }); // Check if we've reached the max limit if (maxFindings > 0 && validFindings.length >= maxFindings) { - console.log(`Reached maximum findings limit: ${maxFindings}`); + core.info(`Reached maximum findings limit: ${maxFindings}`); break; } } if (validFindings.length === 0) { - console.log("No valid security findings to report"); + core.info("No valid security findings to report"); return; } - console.log(`Processing ${validFindings.length} valid security finding(s)`); + core.info(`Processing ${validFindings.length} valid security finding(s)`); // Generate SARIF file const sarifContent = { $schema: @@ -1414,8 +1404,8 @@ jobs: const sarifFilePath = path.join(process.cwd(), sarifFileName); try { fs.writeFileSync(sarifFilePath, JSON.stringify(sarifContent, null, 2)); - console.log(`✓ Created SARIF file: ${sarifFilePath}`); - console.log(`SARIF file size: ${fs.statSync(sarifFilePath).size} bytes`); + core.info(`✓ Created SARIF file: ${sarifFilePath}`); + core.info(`SARIF file size: ${fs.statSync(sarifFilePath).size} bytes`); // Set outputs for the GitHub Action core.setOutput("sarif_file", sarifFilePath); core.setOutput("findings_count", validFindings.length); @@ -1442,7 +1432,7 @@ jobs: ); throw error; } - console.log( + core.info( `Successfully created code scanning alert with ${validFindings.length} finding(s)` ); return { diff --git a/.github/workflows/test-safe-output-create-discussion.lock.yml b/.github/workflows/test-safe-output-create-discussion.lock.yml index d5721a91a41..2a2b39fc853 100644 --- a/.github/workflows/test-safe-output-create-discussion.lock.yml +++ b/.github/workflows/test-safe-output-create-discussion.lock.yml @@ -38,7 +38,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -56,10 +56,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -67,18 +67,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -564,7 +564,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -582,32 +582,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1041,7 +1043,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1059,7 +1061,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1072,7 +1074,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1129,27 +1131,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.debug(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.warning("No valid items found in agent output"); return; } // Find all create-discussion items @@ -1157,12 +1158,10 @@ jobs: /** @param {any} item */ item => item.type === "create-discussion" ); if (createDiscussionItems.length === 0) { - console.log("No create-discussion items found in agent output"); + core.warning("No create-discussion items found in agent output"); return; } - console.log( - `Found ${createDiscussionItems.length} create-discussion item(s)` - ); + core.debug(`Found ${createDiscussionItems.length} create-discussion item(s)`); // If in staged mode, emit step summary instead of creating discussions if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { let summaryContent = "## 🎭 Staged Mode: Create Discussions Preview\n\n"; @@ -1182,7 +1181,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Discussion creation preview written to step summary"); + core.info("📝 Discussion creation preview written to step summary"); return; } // Get repository ID and discussion categories using GraphQL API @@ -1211,11 +1210,12 @@ jobs: repositoryId = queryResult.repository.id; discussionCategories = queryResult.repository.discussionCategories.nodes || []; - console.log( - "Available categories:", - discussionCategories.map( - /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) - ) + core.info( + `Available categories: ${JSON.stringify( + discussionCategories.map( + /** @param {any} cat */ cat => ({ name: cat.name, id: cat.id }) + ) + )}` ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); @@ -1225,10 +1225,10 @@ jobs: errorMessage.includes("not found") || errorMessage.includes("Could not resolve to a Repository") ) { - console.log( + core.info( "⚠ Cannot create discussions: Discussions are not enabled for this repository" ); - console.log( + core.info( "Consider enabling discussions in repository settings if you want to create discussions automatically" ); return; // Exit gracefully without creating discussions @@ -1241,7 +1241,7 @@ jobs: if (!categoryId && discussionCategories.length > 0) { // Default to the first category if none specified categoryId = discussionCategories[0].id; - console.log( + core.info( `No category-id specified, using default category: ${discussionCategories[0].name} (${categoryId})` ); } @@ -1259,12 +1259,8 @@ jobs: // Process each create-discussion item for (let i = 0; i < createDiscussionItems.length; i++) { const createDiscussionItem = createDiscussionItems[i]; - console.log( - `Processing create-discussion item ${i + 1}/${createDiscussionItems.length}:`, - { - title: createDiscussionItem.title, - bodyLength: createDiscussionItem.body.length, - } + core.info( + `Processing create-discussion item ${i + 1}/${createDiscussionItems.length}: title=${createDiscussionItem.title}, bodyLength=${createDiscussionItem.body.length}` ); // Extract title and body from the JSON item let title = createDiscussionItem.title @@ -1293,9 +1289,9 @@ jobs: ); // Prepare the body content const body = bodyLines.join("\n").trim(); - console.log("Creating discussion with title:", title); - console.log("Category ID:", categoryId); - console.log("Body length:", body.length); + core.info(`Creating discussion with title: ${title}`); + core.info(`Category ID: ${categoryId}`); + core.info(`Body length: ${body.length}`); try { // Create the discussion using GraphQL API with parameterized mutation const createDiscussionMutation = ` @@ -1322,7 +1318,7 @@ jobs: body: body, }); const discussion = mutationResult.createDiscussion.discussion; - console.log( + core.info( "Created discussion #" + discussion.number + ": " + discussion.url ); createdDiscussions.push(discussion); @@ -1346,9 +1342,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log( - `Successfully created ${createdDiscussions.length} discussion(s)` - ); + core.info(`Successfully created ${createdDiscussions.length} discussion(s)`); } await main(); diff --git a/.github/workflows/test-safe-output-create-issue.lock.yml b/.github/workflows/test-safe-output-create-issue.lock.yml index f2b0efe530d..64b5e310426 100644 --- a/.github/workflows/test-safe-output-create-issue.lock.yml +++ b/.github/workflows/test-safe-output-create-issue.lock.yml @@ -35,7 +35,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -53,10 +53,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -64,18 +64,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -568,7 +568,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -586,32 +586,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1045,7 +1047,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1063,7 +1065,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1076,7 +1078,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1133,7 +1135,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -1151,10 +1153,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -1162,18 +1164,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -1207,27 +1209,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all create-issue items @@ -1235,10 +1236,10 @@ jobs: /** @param {any} item */ item => item.type === "create-issue" ); if (createIssueItems.length === 0) { - console.log("No create-issue items found in agent output"); + core.info("No create-issue items found in agent output"); return; } - console.log(`Found ${createIssueItems.length} create-issue item(s)`); + core.info(`Found ${createIssueItems.length} create-issue item(s)`); // If in staged mode, emit step summary instead of creating issues if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Create Issues Preview\n\n"; @@ -1258,7 +1259,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Issue creation preview written to step summary"); + core.info("📝 Issue creation preview written to step summary"); return; } // Check if we're in an issue context (triggered by an issue event) @@ -1275,9 +1276,8 @@ jobs: // Process each create-issue item for (let i = 0; i < createIssueItems.length; i++) { const createIssueItem = createIssueItems[i]; - console.log( - `Processing create-issue item ${i + 1}/${createIssueItems.length}:`, - { title: createIssueItem.title, bodyLength: createIssueItem.body.length } + core.info( + `Processing create-issue item ${i + 1}/${createIssueItems.length}: title=${createIssueItem.title}, bodyLength=${createIssueItem.body.length}` ); // Merge environment labels with item-specific labels let labels = [...envLabels]; @@ -1297,7 +1297,7 @@ jobs: title = titlePrefix + title; } if (parentIssueNumber) { - console.log("Detected issue context, parent issue #" + parentIssueNumber); + core.info("Detected issue context, parent issue #" + parentIssueNumber); // Add reference to parent issue in the child issue body bodyLines.push(`Related to #${parentIssueNumber}`); } @@ -1315,9 +1315,9 @@ jobs: ); // Prepare the body content const body = bodyLines.join("\n").trim(); - console.log("Creating issue with title:", title); - console.log("Labels:", labels); - console.log("Body length:", body.length); + core.info(`Creating issue with title: ${title}`); + core.info(`Labels: ${labels}`); + core.info(`Body length: ${body.length}`); try { // Create the issue using GitHub API const { data: issue } = await github.rest.issues.create({ @@ -1327,7 +1327,7 @@ jobs: body: body, labels: labels, }); - console.log("Created issue #" + issue.number + ": " + issue.html_url); + core.info("Created issue #" + issue.number + ": " + issue.html_url); createdIssues.push(issue); // If we have a parent issue, add a comment to it referencing the new child issue if (parentIssueNumber) { @@ -1338,11 +1338,10 @@ jobs: issue_number: parentIssueNumber, body: `Created related issue: #${issue.number}`, }); - console.log("Added comment to parent issue #" + parentIssueNumber); + core.info("Added comment to parent issue #" + parentIssueNumber); } catch (error) { - console.log( - "Warning: Could not add comment to parent issue:", - error instanceof Error ? error.message : String(error) + core.info( + `Warning: Could not add comment to parent issue: ${error instanceof Error ? error.message : String(error)}` ); } } @@ -1358,10 +1357,10 @@ jobs: if ( errorMessage.includes("Issues has been disabled in this repository") ) { - console.log( + core.info( `⚠ Cannot create issue "${title}": Issues are disabled for this repository` ); - console.log( + core.info( "Consider enabling issues in repository settings if you want to create issues automatically" ); continue; // Skip this issue but continue processing others @@ -1378,7 +1377,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully created ${createdIssues.length} issue(s)`); + core.info(`Successfully created ${createdIssues.length} issue(s)`); } await main(); diff --git a/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml b/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml index b7299793fbc..176cbf2159d 100644 --- a/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml +++ b/.github/workflows/test-safe-output-create-pull-request-review-comment.lock.yml @@ -37,7 +37,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -55,10 +55,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -66,18 +66,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -581,7 +581,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -599,32 +599,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1058,7 +1060,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1076,7 +1078,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1089,7 +1091,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1147,27 +1149,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all create-pull-request-review-comment items @@ -1176,12 +1177,12 @@ jobs: item.type === "create-pull-request-review-comment" ); if (reviewCommentItems.length === 0) { - console.log( + core.info( "No create-pull-request-review-comment items found in agent output" ); return; } - console.log( + core.info( `Found ${reviewCommentItems.length} create-pull-request-review-comment item(s)` ); // If in staged mode, emit step summary instead of creating review comments @@ -1204,14 +1205,12 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log( - "📝 PR review comment creation preview written to step summary" - ); + core.info("📝 PR review comment creation preview written to step summary"); return; } // Get the side configuration from environment variable const defaultSide = process.env.GITHUB_AW_PR_REVIEW_COMMENT_SIDE || "RIGHT"; - console.log(`Default comment side configuration: ${defaultSide}`); + core.info(`Default comment side configuration: ${defaultSide}`); // Check if we're in a pull request context, or an issue comment context on a PR const isPRContext = context.eventName === "pull_request" || @@ -1221,7 +1220,7 @@ jobs: context.payload.issue && context.payload.issue.pull_request); if (!isPRContext) { - console.log( + core.info( "Not running in pull request context, skipping review comment creation" ); return; @@ -1240,16 +1239,15 @@ jobs: }, }); pullRequest = fullPR; - console.log("Fetched full pull request details from API"); + core.info("Fetched full pull request details from API"); } catch (error) { - console.log( - "Failed to fetch full pull request details:", - error instanceof Error ? error.message : String(error) + core.info( + `Failed to fetch full pull request details: ${error instanceof Error ? error.message : String(error)}` ); return; } } else { - console.log( + core.info( "Pull request data not found in payload - cannot create review comments" ); return; @@ -1257,29 +1255,23 @@ jobs: } // Check if we have the commit SHA needed for creating review comments if (!pullRequest || !pullRequest.head || !pullRequest.head.sha) { - console.log( + core.info( "Pull request head commit SHA not found in payload - cannot create review comments" ); return; } const pullRequestNumber = pullRequest.number; - console.log(`Creating review comments on PR #${pullRequestNumber}`); + core.info(`Creating review comments on PR #${pullRequestNumber}`); const createdComments = []; // Process each review comment item for (let i = 0; i < reviewCommentItems.length; i++) { const commentItem = reviewCommentItems[i]; - console.log( - `Processing create-pull-request-review-comment item ${i + 1}/${reviewCommentItems.length}:`, - { - bodyLength: commentItem.body ? commentItem.body.length : "undefined", - path: commentItem.path, - line: commentItem.line, - startLine: commentItem.start_line, - } + core.info( + `Processing create-pull-request-review-comment item ${i + 1}/${reviewCommentItems.length}: bodyLength=${commentItem.body ? commentItem.body.length : "undefined"}, path=${commentItem.path}, line=${commentItem.line}, startLine=${commentItem.start_line}` ); // Validate required fields if (!commentItem.path) { - console.log('Missing required field "path" in review comment item'); + core.info('Missing required field "path" in review comment item'); continue; } if ( @@ -1287,13 +1279,13 @@ jobs: (typeof commentItem.line !== "number" && typeof commentItem.line !== "string") ) { - console.log( + core.info( 'Missing or invalid required field "line" in review comment item' ); continue; } if (!commentItem.body || typeof commentItem.body !== "string") { - console.log( + core.info( 'Missing or invalid required field "body" in review comment item' ); continue; @@ -1301,14 +1293,14 @@ jobs: // Parse line numbers const line = parseInt(commentItem.line, 10); if (isNaN(line) || line <= 0) { - console.log(`Invalid line number: ${commentItem.line}`); + core.info(`Invalid line number: ${commentItem.line}`); continue; } let startLine = undefined; if (commentItem.start_line) { startLine = parseInt(commentItem.start_line, 10); if (isNaN(startLine) || startLine <= 0 || startLine > line) { - console.log( + core.info( `Invalid start_line number: ${commentItem.start_line} (must be <= line: ${line})` ); continue; @@ -1317,7 +1309,7 @@ jobs: // Determine side (LEFT or RIGHT) const side = commentItem.side || defaultSide; if (side !== "LEFT" && side !== "RIGHT") { - console.log(`Invalid side value: ${side} (must be LEFT or RIGHT)`); + core.info(`Invalid side value: ${side} (must be LEFT or RIGHT)`); continue; } // Extract body from the JSON item @@ -1328,10 +1320,10 @@ jobs: ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `https://github.com/actions/runs/${runId}`; body += `\n\n> Generated by Agentic Workflow [Run](${runUrl})\n`; - console.log( + core.info( `Creating review comment on PR #${pullRequestNumber} at ${commentItem.path}:${line}${startLine ? ` (lines ${startLine}-${line})` : ""} [${side}]` ); - console.log("Comment content length:", body.length); + core.info(`Comment content length: ${body.length}`); try { // Prepare the request parameters /** @type {any} */ @@ -1353,7 +1345,7 @@ jobs: // Create the review comment using GitHub API const { data: comment } = await github.rest.pulls.createReviewComment(requestParams); - console.log( + core.info( "Created review comment #" + comment.id + ": " + comment.html_url ); createdComments.push(comment); @@ -1377,9 +1369,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log( - `Successfully created ${createdComments.length} review comment(s)` - ); + core.info(`Successfully created ${createdComments.length} review comment(s)`); return createdComments; } await main(); diff --git a/.github/workflows/test-safe-output-create-pull-request.lock.yml b/.github/workflows/test-safe-output-create-pull-request.lock.yml index d928c8668a0..c1f83311956 100644 --- a/.github/workflows/test-safe-output-create-pull-request.lock.yml +++ b/.github/workflows/test-safe-output-create-pull-request.lock.yml @@ -36,7 +36,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -54,10 +54,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -65,18 +65,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -597,7 +597,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -615,32 +615,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1074,7 +1076,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1092,7 +1094,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1105,7 +1107,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1408,7 +1410,7 @@ jobs: try { validatedOutput = JSON.parse(outputContent); } catch (error) { - core.error( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; @@ -1425,7 +1427,9 @@ jobs: core.warning("No create-pull-request item found in agent output"); return; } - core.debug(`Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}`); + core.debug( + `Found create-pull-request item: title="${pullRequestItem.title}", bodyLength=${pullRequestItem.body.length}` + ); // If in staged mode, emit step summary instead of creating PR if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Create Pull Request Preview\n\n"; @@ -1570,7 +1574,7 @@ jobs: issue_number: pullRequest.number, labels: labels, }); - console.log("Added labels to pull request:", labels); + core.info(`Added labels to pull request: ${JSON.stringify(labels)}`); } // Set output for other jobs to use core.setOutput("pull_request_number", pullRequest.number); diff --git a/.github/workflows/test-safe-output-missing-tool.lock.yml b/.github/workflows/test-safe-output-missing-tool.lock.yml index 59a978af4af..4d5ff39ac94 100644 --- a/.github/workflows/test-safe-output-missing-tool.lock.yml +++ b/.github/workflows/test-safe-output-missing-tool.lock.yml @@ -506,7 +506,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -524,32 +524,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -983,7 +985,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1001,7 +1003,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1014,7 +1016,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1093,7 +1095,7 @@ jobs: try { validatedOutput = JSON.parse(agentOutput); } catch (error) { - core.error( + core.setFailed( `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; diff --git a/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml b/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml index f1e7a1666a2..5885d4e3334 100644 --- a/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml +++ b/.github/workflows/test-safe-output-push-to-pr-branch.lock.yml @@ -37,7 +37,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -55,10 +55,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -66,18 +66,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -601,7 +601,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -619,32 +619,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1078,7 +1080,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1096,7 +1098,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1109,7 +1111,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1304,7 +1306,7 @@ jobs: // Environment validation - fail early if required variables are missing const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT || ""; if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } const target = process.env.GITHUB_AW_PUSH_TARGET || "triggering"; @@ -1321,7 +1323,7 @@ jobs: return; case "warn": default: - console.log(message); + core.info(message); return; } } @@ -1339,7 +1341,7 @@ jobs: return; case "warn": default: - console.log(message); + core.info(message); return; } } @@ -1359,28 +1361,27 @@ jobs: break; case "warn": default: - console.log(message); + core.info(message); break; } } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); if (!isEmpty) { - console.log("Patch content validation passed"); + core.info("Patch content validation passed"); } - console.log("Target configuration:", target); + core.info(`Target configuration: ${target}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find the push-to-pr-branch item @@ -1388,10 +1389,10 @@ jobs: /** @param {any} item */ item => item.type === "push-to-pr-branch" ); if (!pushItem) { - console.log("No push-to-pr-branch item found in agent output"); + core.info("No push-to-pr-branch item found in agent output"); return; } - console.log("Found push-to-pr-branch item"); + core.info("Found push-to-pr-branch item"); // If in staged mode, emit step summary instead of pushing changes if (process.env.GITHUB_AW_SAFE_OUTPUTS_STAGED === "true") { let summaryContent = "## 🎭 Staged Mode: Push to PR Branch Preview\n\n"; @@ -1412,7 +1413,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Push to PR branch preview written to step summary"); + core.info("📝 Push to PR branch preview written to step summary"); return; } // Validate target configuration for pull request context @@ -1460,18 +1461,18 @@ jobs: throw new Error("No head branch found for PR"); } } catch (error) { - console.log( + core.info( `Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}` ); // Exit with failure if we cannot determine the branch name core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); return; } - console.log("Target branch:", branchName); + core.info(`Target branch: ${branchName}`); // Check if patch has actual changes (not just empty) const hasChanges = !isEmpty; // Switch to or create the target branch - console.log("Switching to branch:", branchName); + core.info(`Switching to branch: ${branchName}`); try { // Try to checkout existing branch first execSync("git fetch origin", { stdio: "inherit" }); @@ -1484,32 +1485,31 @@ jobs: execSync(`git checkout -B ${branchName} origin/${branchName}`, { stdio: "inherit", }); - console.log("Checked out existing branch from origin:", branchName); + core.info(`Checked out existing branch from origin: ${branchName}`); } catch (originError) { // Branch doesn't exist on origin, check if it exists locally try { execSync(`git rev-parse --verify ${branchName}`, { stdio: "pipe" }); // Branch exists locally, check it out execSync(`git checkout ${branchName}`, { stdio: "inherit" }); - console.log("Checked out existing local branch:", branchName); + core.info(`Checked out existing local branch: ${branchName}`); } catch (localError) { // Branch doesn't exist locally or on origin, create it from default branch - console.log( - "Branch does not exist, creating new branch from default branch:", - branchName + core.info( + `Branch does not exist, creating new branch from default branch: ${branchName}` ); // Get the default branch name const defaultBranch = execSync( "git remote show origin | grep 'HEAD branch' | cut -d' ' -f5", { encoding: "utf8" } ).trim(); - console.log("Default branch:", defaultBranch); + core.info(`Default branch: ${defaultBranch}`); // Ensure we have the latest default branch execSync(`git checkout ${defaultBranch}`, { stdio: "inherit" }); execSync(`git pull origin ${defaultBranch}`, { stdio: "inherit" }); // Create new branch from default branch execSync(`git checkout -b ${branchName}`, { stdio: "inherit" }); - console.log("Created new branch from default branch:", branchName); + core.info(`Created new branch from default branch: ${branchName}`); } } } catch (error) { @@ -1520,14 +1520,14 @@ jobs: } // Apply the patch using git CLI (skip if empty) if (!isEmpty) { - console.log("Applying patch..."); + core.info("Applying patch..."); try { // Patches are created with git format-patch, so use git am to apply them execSync("git am /tmp/aw.patch", { stdio: "inherit" }); - console.log("Patch applied successfully"); + core.info("Patch applied successfully"); // Push the applied commits to the branch execSync(`git push origin ${branchName}`, { stdio: "inherit" }); - console.log("Changes committed and pushed to branch:", branchName); + core.info(`Changes committed and pushed to branch: ${branchName}`); } catch (error) { core.error( `Failed to apply patch: ${error instanceof Error ? error.message : String(error)}` @@ -1536,7 +1536,7 @@ jobs: return; } } else { - console.log("Skipping patch application (empty patch)"); + core.info("Skipping patch application (empty patch)"); // Handle if-no-changes configuration for empty patches const message = "No changes to apply - noop operation completed successfully"; @@ -1551,7 +1551,7 @@ jobs: break; case "warn": default: - console.log(message); + core.info(message); break; } } diff --git a/.github/workflows/test-safe-output-update-issue.lock.yml b/.github/workflows/test-safe-output-update-issue.lock.yml index 0df2bba33f4..3a438007098 100644 --- a/.github/workflows/test-safe-output-update-issue.lock.yml +++ b/.github/workflows/test-safe-output-update-issue.lock.yml @@ -36,7 +36,7 @@ jobs: // skip check for safe events const safeEvents = ["workflow_dispatch", "workflow_run", "schedule"]; if (safeEvents.includes(eventName)) { - console.log(`✅ Event ${eventName} does not require validation`); + core.info(`✅ Event ${eventName} does not require validation`); return; } const actor = context.actor; @@ -54,10 +54,10 @@ jobs: } // Check if the actor has the required repository permissions try { - console.log( + core.debug( `Checking if user '${actor}' has required permissions for ${owner}/${repo}` ); - console.log(`Required permissions: ${requiredPermissions.join(", ")}`); + core.debug(`Required permissions: ${requiredPermissions.join(", ")}`); const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ owner: owner, @@ -65,18 +65,18 @@ jobs: username: actor, }); const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); + core.debug(`Repository permission level: ${permission}`); // Check if user has one of the required permission levels for (const requiredPerm of requiredPermissions) { if ( permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain") ) { - console.log(`✅ User has ${permission} access to repository`); + core.info(`✅ User has ${permission} access to repository`); return; } } - console.log( + core.warning( `User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}` ); } catch (repoError) { @@ -573,7 +573,7 @@ jobs: return JSON.parse(repairedJson); } catch (repairError) { // If repair also fails, throw the error - console.log(`invalid input json: ${jsonStr}`); + core.info(`invalid input json: ${jsonStr}`); const originalMsg = originalError instanceof Error ? originalError.message @@ -591,32 +591,34 @@ jobs: const outputFile = process.env.GITHUB_AW_SAFE_OUTPUTS; const safeOutputsConfig = process.env.GITHUB_AW_SAFE_OUTPUTS_CONFIG; if (!outputFile) { - console.log("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); + core.info("GITHUB_AW_SAFE_OUTPUTS not set, no output to collect"); core.setOutput("output", ""); return; } if (!fs.existsSync(outputFile)) { - console.log("Output file does not exist:", outputFile); + core.info(`Output file does not exist: ${outputFile}`); core.setOutput("output", ""); return; } const outputContent = fs.readFileSync(outputFile, "utf8"); if (outputContent.trim() === "") { - console.log("Output file is empty"); + core.info("Output file is empty"); core.setOutput("output", ""); return; } - console.log("Raw output content length:", outputContent.length); + core.info(`Raw output content length: ${outputContent.length}`); // Parse the safe-outputs configuration /** @type {any} */ let expectedOutputTypes = {}; if (safeOutputsConfig) { try { expectedOutputTypes = JSON.parse(safeOutputsConfig); - console.log("Expected output types:", Object.keys(expectedOutputTypes)); + core.info( + `Expected output types: ${JSON.stringify(Object.keys(expectedOutputTypes))}` + ); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - console.log("Warning: Could not parse safe-outputs config:", errorMsg); + core.info(`Warning: Could not parse safe-outputs config: ${errorMsg}`); } } // Parse JSONL content @@ -1050,7 +1052,7 @@ jobs: errors.push(`Line ${i + 1}: Unknown output type '${itemType}'`); continue; } - console.log(`Line ${i + 1}: Valid ${itemType} item`); + core.info(`Line ${i + 1}: Valid ${itemType} item`); parsedItems.push(item); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); @@ -1068,7 +1070,7 @@ jobs: // For now, we'll continue with valid items but log the errors // In the future, we might want to fail the workflow for invalid items } - console.log(`Successfully parsed ${parsedItems.length} valid output items`); + core.info(`Successfully parsed ${parsedItems.length} valid output items`); // Set the parsed and validated items as output const validatedOutput = { items: parsedItems, @@ -1081,7 +1083,7 @@ jobs: // Ensure the /tmp directory exists fs.mkdirSync("/tmp", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); - console.log(`Stored validated output to: ${agentOutputFile}`); + core.info(`Stored validated output to: ${agentOutputFile}`); // Set the environment variable GITHUB_AW_AGENT_OUTPUT to the file path core.exportVariable("GITHUB_AW_AGENT_OUTPUT", agentOutputFile); } catch (error) { @@ -1144,27 +1146,26 @@ jobs: // Read the validated output content from environment variable const outputContent = process.env.GITHUB_AW_AGENT_OUTPUT; if (!outputContent) { - console.log("No GITHUB_AW_AGENT_OUTPUT environment variable found"); + core.info("No GITHUB_AW_AGENT_OUTPUT environment variable found"); return; } if (outputContent.trim() === "") { - console.log("Agent output content is empty"); + core.info("Agent output content is empty"); return; } - console.log("Agent output content length:", outputContent.length); + core.info(`Agent output content length: ${outputContent.length}`); // Parse the validated output JSON let validatedOutput; try { validatedOutput = JSON.parse(outputContent); } catch (error) { - console.log( - "Error parsing agent output JSON:", - error instanceof Error ? error.message : String(error) + core.setFailed( + `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}` ); return; } if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { - console.log("No valid items found in agent output"); + core.info("No valid items found in agent output"); return; } // Find all update-issue items @@ -1172,10 +1173,10 @@ jobs: /** @param {any} item */ item => item.type === "update-issue" ); if (updateItems.length === 0) { - console.log("No update-issue items found in agent output"); + core.info("No update-issue items found in agent output"); return; } - console.log(`Found ${updateItems.length} update-issue item(s)`); + core.info(`Found ${updateItems.length} update-issue item(s)`); // If in staged mode, emit step summary instead of updating issues if (isStaged) { let summaryContent = "## 🎭 Staged Mode: Update Issues Preview\n\n"; @@ -1202,7 +1203,7 @@ jobs: } // Write to step summary await core.summary.addRaw(summaryContent).write(); - console.log("📝 Issue update preview written to step summary"); + core.info("📝 Issue update preview written to step summary"); return; } // Get the configuration from environment variables @@ -1210,8 +1211,8 @@ jobs: const canUpdateStatus = process.env.GITHUB_AW_UPDATE_STATUS === "true"; const canUpdateTitle = process.env.GITHUB_AW_UPDATE_TITLE === "true"; const canUpdateBody = process.env.GITHUB_AW_UPDATE_BODY === "true"; - console.log(`Update target configuration: ${updateTarget}`); - console.log( + core.info(`Update target configuration: ${updateTarget}`); + core.info( `Can update status: ${canUpdateStatus}, title: ${canUpdateTitle}, body: ${canUpdateBody}` ); // Check if we're in an issue context @@ -1219,7 +1220,7 @@ jobs: context.eventName === "issues" || context.eventName === "issue_comment"; // Validate context based on target configuration if (updateTarget === "triggering" && !isIssueContext) { - console.log( + core.info( 'Target is "triggering" but not running in issue context, skipping issue update' ); return; @@ -1228,7 +1229,7 @@ jobs: // Process each update item for (let i = 0; i < updateItems.length; i++) { const updateItem = updateItems[i]; - console.log(`Processing update-issue item ${i + 1}/${updateItems.length}`); + core.info(`Processing update-issue item ${i + 1}/${updateItems.length}`); // Determine the issue number for this update let issueNumber; if (updateTarget === "*") { @@ -1236,22 +1237,20 @@ jobs: if (updateItem.issue_number) { issueNumber = parseInt(updateItem.issue_number, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number specified: ${updateItem.issue_number}` ); continue; } } else { - console.log( - 'Target is "*" but no issue_number specified in update item' - ); + core.info('Target is "*" but no issue_number specified in update item'); continue; } } else if (updateTarget && updateTarget !== "triggering") { // Explicit issue number specified in target issueNumber = parseInt(updateTarget, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - console.log( + core.info( `Invalid issue number in target configuration: ${updateTarget}` ); continue; @@ -1262,19 +1261,19 @@ jobs: if (context.payload.issue) { issueNumber = context.payload.issue.number; } else { - console.log("Issue context detected but no issue found in payload"); + core.info("Issue context detected but no issue found in payload"); continue; } } else { - console.log("Could not determine issue number"); + core.info("Could not determine issue number"); continue; } } if (!issueNumber) { - console.log("Could not determine issue number"); + core.info("Could not determine issue number"); continue; } - console.log(`Updating issue #${issueNumber}`); + core.info(`Updating issue #${issueNumber}`); // Build the update object based on allowed fields and provided values /** @type {any} */ const updateData = {}; @@ -1284,9 +1283,9 @@ jobs: if (updateItem.status === "open" || updateItem.status === "closed") { updateData.state = updateItem.status; hasUpdates = true; - console.log(`Will update status to: ${updateItem.status}`); + core.info(`Will update status to: ${updateItem.status}`); } else { - console.log( + core.info( `Invalid status value: ${updateItem.status}. Must be 'open' or 'closed'` ); } @@ -1298,22 +1297,22 @@ jobs: ) { updateData.title = updateItem.title.trim(); hasUpdates = true; - console.log(`Will update title to: ${updateItem.title.trim()}`); + core.info(`Will update title to: ${updateItem.title.trim()}`); } else { - console.log("Invalid title value: must be a non-empty string"); + core.info("Invalid title value: must be a non-empty string"); } } if (canUpdateBody && updateItem.body !== undefined) { if (typeof updateItem.body === "string") { updateData.body = updateItem.body; hasUpdates = true; - console.log(`Will update body (length: ${updateItem.body.length})`); + core.info(`Will update body (length: ${updateItem.body.length})`); } else { - console.log("Invalid body value: must be a string"); + core.info("Invalid body value: must be a string"); } } if (!hasUpdates) { - console.log("No valid updates to apply for this item"); + core.info("No valid updates to apply for this item"); continue; } try { @@ -1324,7 +1323,7 @@ jobs: issue_number: issueNumber, ...updateData, }); - console.log("Updated issue #" + issue.number + ": " + issue.html_url); + core.info("Updated issue #" + issue.number + ": " + issue.html_url); updatedIssues.push(issue); // Set output for the last updated issue (for backward compatibility) if (i === updateItems.length - 1) { @@ -1346,7 +1345,7 @@ jobs: } await core.summary.addRaw(summaryContent).write(); } - console.log(`Successfully updated ${updatedIssues.length} issue(s)`); + core.info(`Successfully updated ${updatedIssues.length} issue(s)`); return updatedIssues; } await main(); diff --git a/pkg/cli/workflows/test-ai-inference-github-models.lock.yml b/pkg/cli/workflows/test-ai-inference-github-models.lock.yml index 23880c0f022..0399e8e6e57 100644 --- a/pkg/cli/workflows/test-ai-inference-github-models.lock.yml +++ b/pkg/cli/workflows/test-ai-inference-github-models.lock.yml @@ -316,11 +316,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml b/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml index ea042419e21..b16bf6d9dce 100644 --- a/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml +++ b/pkg/cli/workflows/test-claude-add-issue-comment.lock.yml @@ -313,11 +313,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml b/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml index c19dc109455..e0a221349d6 100644 --- a/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml +++ b/pkg/cli/workflows/test-claude-add-issue-labels.lock.yml @@ -313,11 +313,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-command.lock.yml b/pkg/cli/workflows/test-claude-command.lock.yml index 71857cc5e8d..d9ff0cd94e5 100644 --- a/pkg/cli/workflows/test-claude-command.lock.yml +++ b/pkg/cli/workflows/test-claude-command.lock.yml @@ -313,11 +313,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-create-issue.lock.yml b/pkg/cli/workflows/test-claude-create-issue.lock.yml index 16045d212e9..2736c23fd6e 100644 --- a/pkg/cli/workflows/test-claude-create-issue.lock.yml +++ b/pkg/cli/workflows/test-claude-create-issue.lock.yml @@ -313,11 +313,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml b/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml index c59d326b3cf..21b26a8fb40 100644 --- a/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml +++ b/pkg/cli/workflows/test-claude-create-pull-request-review-comment.lock.yml @@ -313,11 +313,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-create-pull-request.lock.yml b/pkg/cli/workflows/test-claude-create-pull-request.lock.yml index 83c606b68ab..16b613bba25 100644 --- a/pkg/cli/workflows/test-claude-create-pull-request.lock.yml +++ b/pkg/cli/workflows/test-claude-create-pull-request.lock.yml @@ -318,11 +318,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml b/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml index 6a5875a3567..1d23175a97f 100644 --- a/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml +++ b/pkg/cli/workflows/test-claude-create-repository-security-advisory.lock.yml @@ -316,11 +316,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-mcp.lock.yml b/pkg/cli/workflows/test-claude-mcp.lock.yml index 75f96ecbd35..463be71180d 100644 --- a/pkg/cli/workflows/test-claude-mcp.lock.yml +++ b/pkg/cli/workflows/test-claude-mcp.lock.yml @@ -316,11 +316,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml b/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml index 7cab44dec9d..4d79c5cc5de 100644 --- a/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml +++ b/pkg/cli/workflows/test-claude-push-to-pr-branch.lock.yml @@ -318,11 +318,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); diff --git a/pkg/cli/workflows/test-claude-update-issue.lock.yml b/pkg/cli/workflows/test-claude-update-issue.lock.yml index c5a019379b9..e683f16bc20 100644 --- a/pkg/cli/workflows/test-claude-update-issue.lock.yml +++ b/pkg/cli/workflows/test-claude-update-issue.lock.yml @@ -316,11 +316,11 @@ jobs: // Get the log file path from environment const logFile = process.env.GITHUB_AW_AGENT_OUTPUT; if (!logFile) { - console.log("No agent log file specified"); + core.info("No agent log file specified"); return; } if (!fs.existsSync(logFile)) { - console.log(`Log file not found: ${logFile}`); + core.info(`Log file not found: ${logFile}`); return; } const logContent = fs.readFileSync(logFile, "utf8"); From f508a19fa133e68304d9b7728ff0e2265a5f4b56 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 12 Sep 2025 16:05:52 +0000 Subject: [PATCH 13/13] Remove Codex log parsing tests from log_parser_test.go --- pkg/workflow/log_parser_snapshot_test.go | 6 -- pkg/workflow/log_parser_test.go | 80 ------------------------ 2 files changed, 86 deletions(-) diff --git a/pkg/workflow/log_parser_snapshot_test.go b/pkg/workflow/log_parser_snapshot_test.go index fb72b5520b4..aed26a18810 100644 --- a/pkg/workflow/log_parser_snapshot_test.go +++ b/pkg/workflow/log_parser_snapshot_test.go @@ -24,12 +24,6 @@ func TestLogParserSnapshots(t *testing.T) { logFile: "sample_claude_log.txt", expectedFile: "expected_claude_baseline.md", }, - { - name: "Codex log parsing", - engine: "codex", - logFile: "sample_codex_log.txt", - expectedFile: "expected_codex_baseline.md", - }, } for _, tt := range tests { diff --git a/pkg/workflow/log_parser_test.go b/pkg/workflow/log_parser_test.go index 5baaf56ac5f..62fe43d3826 100644 --- a/pkg/workflow/log_parser_test.go +++ b/pkg/workflow/log_parser_test.go @@ -149,83 +149,3 @@ func TestParseClaudeLogSmoke(t *testing.T) { t.Error("Expected error message for empty Claude log") } } - -func TestParseCodexLogSmoke(t *testing.T) { - script := GetLogParserScript("parse_codex_log") - if script == "" { - t.Skip("parse_codex_log script not available") - } - - // Test with minimal valid Codex log - minimalCodexLog := `[2025-08-31T12:37:08] OpenAI Codex v0.27.0 (research preview) --------- -workdir: /home/runner/work/test/test -model: o4-mini -provider: openai -approval: never -sandbox: workspace-write [workdir, /tmp] -reasoning effort: medium -reasoning summaries: auto --------- -[2025-08-31T12:37:08] User instructions: -Test task for the agent. - -[2025-08-31T12:37:09] thinking -Let me help with this test task. - -[2025-08-31T12:37:10] tool get_current_time() -[2025-08-31T12:37:10] success in 0.2s - -[2025-08-31T12:37:11] exec echo "Hello from Codex" in working directory -[2025-08-31T12:37:11] success in 0.1s - -tokens used: 250 - -[2025-08-31T12:37:12] Final response: Task completed successfully.` - - result, err := runJSLogParser(script, minimalCodexLog) - if err != nil { - t.Fatalf("Failed to parse minimal Codex log: %v", err) - } - - // Verify essential sections are present - if !strings.Contains(result, "🤖 Commands and Tools") { - t.Error("Expected Codex log output to contain Commands and Tools section") - } - if !strings.Contains(result, "🤖 Reasoning") { - t.Error("Expected Codex log output to contain Reasoning section") - } - if !strings.Contains(result, "get_current_time") { - t.Error("Expected Codex log output to contain tool usage") - } - if !strings.Contains(result, "echo") { - t.Error("Expected Codex log output to contain exec command") - } - if !strings.Contains(result, "Total Tokens Used") { - t.Error("Expected Codex log output to contain token usage") - } - - // Test with empty input - result, err = runJSLogParser(script, "") - if err != nil { - t.Fatalf("Failed to parse empty Codex log: %v", err) - } - // Codex parser should handle empty input gracefully - if !strings.Contains(result, "🤖 Commands and Tools") { - t.Error("Expected Codex log output to contain Commands and Tools section even for empty input") - } - - // Test with malformed log entries - malformedLog := `[2025-08-31T12:37:08] Invalid log format -Some random text that doesn't follow expected patterns -More unstructured content` - - result, err = runJSLogParser(script, malformedLog) - if err != nil { - t.Fatalf("Failed to parse malformed Codex log: %v", err) - } - // Should still produce basic structure - if !strings.Contains(result, "🤖 Commands and Tools") { - t.Error("Expected Codex log output to contain Commands and Tools section even for malformed input") - } -}