* Update body content with the specified operation * Generic helper for updating markdown bodies (PRs, releases, discussions, etc.) * @param {Object} params - Update parameters * @param {string} params.currentBody - Current body content * @param {string} params.newContent - New content to add/re
(params)
| 93 | * @returns {string} Updated body content |
| 94 | */ |
| 95 | function updateBody(params) { |
| 96 | const { currentBody, newContent, operation, workflowName, runUrl, workflowId, includeFooter = true, historyUrl } = params; |
| 97 | // When footer is enabled use the full footer (includes install instructions, XML marker, etc.) |
| 98 | // When footer is disabled still add standalone workflow-id marker for searchability |
| 99 | const aiFooter = includeFooter ? buildAIFooter(workflowName, runUrl, historyUrl) : ""; |
| 100 | const workflowIdMarker = !includeFooter && workflowId ? `\n\n${generateWorkflowIdMarker(workflowId)}` : ""; |
| 101 | |
| 102 | // Sanitize new content to prevent injection attacks |
| 103 | const sanitizedNewContent = sanitizeContent(newContent); |
| 104 | |
| 105 | // Inject CAUTION at top of new content if threat detection warning was raised |
| 106 | const { detectionCaution } = assembleMarkdownBodyParts({ |
| 107 | includeFooter: false, |
| 108 | workflowName, |
| 109 | runUrl, |
| 110 | }); |
| 111 | const contentWithCaution = detectionCaution ? `${detectionCaution}\n\n${sanitizedNewContent}` : sanitizedNewContent; |
| 112 | |
| 113 | if (operation === "replace") { |
| 114 | // Replace: use new content with optional AI footer |
| 115 | core.info("Operation: replace (full body replacement)"); |
| 116 | return contentWithCaution + aiFooter + workflowIdMarker; |
| 117 | } |
| 118 | |
| 119 | if (operation === "replace-island") { |
| 120 | // Try to find existing island for this workflow ID |
| 121 | const island = findIsland(currentBody, workflowId); |
| 122 | const startMarker = buildIslandStartMarker(workflowId); |
| 123 | const endMarker = buildIslandEndMarker(workflowId); |
| 124 | const islandContent = `${startMarker}\n${contentWithCaution}${aiFooter}${workflowIdMarker}\n${endMarker}`; |
| 125 | |
| 126 | if (island.found) { |
| 127 | // Replace the island content |
| 128 | core.info(`Operation: replace-island (updating existing island for workflow ${workflowId})`); |
| 129 | const before = currentBody.substring(0, island.startIndex); |
| 130 | const after = currentBody.substring(island.endIndex); |
| 131 | return before + islandContent + after; |
| 132 | } else { |
| 133 | // Island not found, fall back to append mode |
| 134 | core.info(`Operation: replace-island (island not found for workflow ${workflowId}, falling back to append)`); |
| 135 | return currentBody + `\n\n---\n\n${islandContent}`; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | if (operation === "prepend") { |
| 140 | // Prepend: add content, AI footer (if enabled), and horizontal line at the start |
| 141 | core.info("Operation: prepend (add to start with separator)"); |
| 142 | const prependSection = `${contentWithCaution}${aiFooter}${workflowIdMarker}\n\n---\n\n`; |
| 143 | return prependSection + currentBody; |
| 144 | } |
| 145 | |
| 146 | // Default to append |
| 147 | core.info("Operation: append (add to end with separator)"); |
| 148 | const appendSection = `\n\n---\n\n${contentWithCaution}${aiFooter}${workflowIdMarker}`; |
| 149 | return currentBody + appendSection; |
| 150 | } |
| 151 | |
| 152 | module.exports = { |
no test coverage detected