* Execute the issue update API call * @param {any} github - GitHub API client * @param {any} context - GitHub Actions context * @param {number} issueNumber - Issue number to update * @param {any} updateData - Data to update * @returns {Promise } Updated issue
(github, context, issueNumber, updateData)
| 31 | * @returns {Promise<any>} Updated issue |
| 32 | */ |
| 33 | async function executeIssueUpdate(github, context, issueNumber, updateData) { |
| 34 | // Handle body operation (append/prepend/replace/replace-island) |
| 35 | // Default to "append" to add footer with AI attribution |
| 36 | const operation = updateData._operation || "append"; |
| 37 | let rawBody = updateData._rawBody; |
| 38 | const includeFooter = updateData._includeFooter !== false; // Default to true |
| 39 | const titlePrefix = updateData._titlePrefix || ""; |
| 40 | const labelsWereProvided = updateData.labels !== undefined; |
| 41 | const labelSpecs = labelsWereProvided ? normalizeIssueIntentLabelSpecs(updateData.labels) : undefined; |
| 42 | const useIssueIntentLabels = Boolean(labelSpecs) && hasIssueIntentsRuntimeFeature(); |
| 43 | |
| 44 | // Remove internal fields |
| 45 | const { _operation, _rawBody, _includeFooter, _titlePrefix, _workflowRepo, ...apiData } = updateData; |
| 46 | if (labelSpecs) { |
| 47 | apiData.labels = getIssueIntentLabelNames(labelSpecs); |
| 48 | } |
| 49 | if (useIssueIntentLabels) { |
| 50 | delete apiData.labels; |
| 51 | } |
| 52 | |
| 53 | /** @type {any | null} */ |
| 54 | let currentIssue = null; |
| 55 | |
| 56 | // Fetch current issue if needed (title prefix validation or body update) |
| 57 | if (titlePrefix || rawBody !== undefined || useIssueIntentLabels) { |
| 58 | const response = await github.rest.issues.get({ |
| 59 | owner: context.repo.owner, |
| 60 | repo: context.repo.repo, |
| 61 | issue_number: issueNumber, |
| 62 | }); |
| 63 | currentIssue = response.data; |
| 64 | |
| 65 | // Validate title prefix if specified |
| 66 | if (titlePrefix) { |
| 67 | const currentTitle = currentIssue.title || ""; |
| 68 | if (!currentTitle.startsWith(titlePrefix)) { |
| 69 | throw new Error(`${ERR_VALIDATION}: Issue title "${currentTitle}" does not start with required prefix "${titlePrefix}"`); |
| 70 | } |
| 71 | core.info(`✓ Title prefix validation passed: "${titlePrefix}"`); |
| 72 | } |
| 73 | |
| 74 | if (rawBody !== undefined) { |
| 75 | // Load and apply temporary project URL replacements FIRST |
| 76 | // This resolves any temporary project IDs (e.g., #aw_abc123def456) to actual project URLs |
| 77 | const temporaryProjectMap = loadTemporaryProjectMap(); |
| 78 | if (temporaryProjectMap.size > 0) { |
| 79 | rawBody = replaceTemporaryProjectReferences(rawBody, temporaryProjectMap); |
| 80 | core.debug(`Applied ${temporaryProjectMap.size} temporary project URL replacement(s)`); |
| 81 | } |
| 82 | |
| 83 | const currentBody = currentIssue.body || ""; |
| 84 | |
| 85 | // Get workflow run URL for AI attribution. |
| 86 | // Use the original workflow repo (_workflowRepo) rather than context.repo, because |
| 87 | // context may be effectiveContext with repo overridden to a cross-repo target. |
| 88 | const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; |
| 89 | const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; |
| 90 | const callerWorkflowId = process.env.GH_AW_CALLER_WORKFLOW_ID || ""; |
nothing calls this directly
no test coverage detected