Skip to content

Commit 536ea1b

Browse files
chore: sync actions from gh-aw@v0.65.4 (#61)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent bfdf388 commit 536ea1b

5 files changed

Lines changed: 102 additions & 60 deletions

File tree

setup/js/add_comment.cjs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,14 @@ async function main(config = {}) {
599599
/** @type {{ id: string | number, html_url: string }} */
600600
let comment;
601601
if (isDiscussion) {
602-
comment = await commentOnDiscussion(githubClient, repoParts.owner, repoParts.repo, itemNumber, processedBody, null);
602+
// When triggered by a discussion_comment event (without explicit item_number),
603+
// reply as a threaded comment to the triggering comment instead of posting top-level.
604+
const hasExplicitItemNumber = message.item_number !== undefined && message.item_number !== null;
605+
const replyToId = context.eventName === "discussion_comment" && !hasExplicitItemNumber ? context.payload?.comment?.node_id : null;
606+
if (replyToId) {
607+
core.info(`Replying as threaded comment to discussion comment node ID: ${replyToId}`);
608+
}
609+
comment = await commentOnDiscussion(githubClient, repoParts.owner, repoParts.repo, itemNumber, processedBody, replyToId);
603610
} else {
604611
// Use REST API for issues/PRs
605612
const { data } = await githubClient.rest.issues.createComment({

setup/js/check_workflow_timestamp_api.cjs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,48 @@ async function main() {
3030
core.info(` Source: ${workflowMdPath}`);
3131
core.info(` Lock file: ${lockFilePath}`);
3232

33-
const { owner, repo } = context.repo;
34-
const ref = context.sha;
33+
// Determine workflow source repository from GITHUB_WORKFLOW_REF for cross-repo support.
34+
// GITHUB_WORKFLOW_REF format: owner/repo/.github/workflows/file.yml@ref
35+
// This env var always reflects the repo where the workflow file is defined,
36+
// not the repo where the triggering event occurred (context.repo).
37+
// When running cross-repo via org rulesets, context.repo points to the target
38+
// repository, not the repository that defines the workflow files.
39+
const workflowEnvRef = process.env.GITHUB_WORKFLOW_REF || "";
40+
const currentRepo = process.env.GITHUB_REPOSITORY || `${context.repo.owner}/${context.repo.repo}`;
41+
42+
// Parse owner, repo, and optional ref from GITHUB_WORKFLOW_REF as a single unit so that
43+
// repo and ref are always consistent with each other. The @ref segment may be absent (e.g.
44+
// when the env var was set without a ref suffix), so treat it as optional.
45+
const workflowRefMatch = workflowEnvRef.match(/^([^/]+)\/([^/]+)\/.+?(?:@(.+))?$/);
46+
47+
// Use the workflow source repo if parseable, otherwise fall back to context.repo
48+
const owner = workflowRefMatch ? workflowRefMatch[1] : context.repo.owner;
49+
const repo = workflowRefMatch ? workflowRefMatch[2] : context.repo.repo;
50+
const workflowRepo = `${owner}/${repo}`;
51+
52+
// Determine ref in a way that keeps repo+ref consistent:
53+
// - If a ref is present in GITHUB_WORKFLOW_REF, use it.
54+
// - For same-repo runs without a parsed ref, fall back to context.sha (existing behavior).
55+
// - For cross-repo runs without a parsed ref, omit ref so the API uses the default branch
56+
// (avoids mixing source repo owner/name with a SHA that only exists in the triggering repo).
57+
let ref;
58+
if (workflowRefMatch && workflowRefMatch[3]) {
59+
ref = workflowRefMatch[3];
60+
} else if (workflowRepo === currentRepo) {
61+
ref = context.sha;
62+
} else {
63+
ref = undefined;
64+
}
65+
66+
core.info(`GITHUB_WORKFLOW_REF: ${workflowEnvRef || "(not set)"}`);
67+
core.info(`GITHUB_REPOSITORY: ${currentRepo}`);
68+
core.info(`Resolved source repo: ${owner}/${repo} @ ${ref || "(default branch)"}`);
69+
70+
if (workflowRepo !== currentRepo) {
71+
core.info(`Cross-repo invocation detected: workflow source is "${workflowRepo}", current repo is "${currentRepo}"`);
72+
} else {
73+
core.info(`Same-repo invocation: checking out ${workflowRepo} @ ${ref}`);
74+
}
3575

3676
// Helper function to compute and compare frontmatter hashes
3777
// Returns: { match: boolean, storedHash: string, recomputedHash: string } or null on error

setup/js/create_code_scanning_alert.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ async function main(config = {}) {
2828
core.info(`Create code scanning alert configuration: max=${maxFindings === 0 ? "unlimited" : maxFindings}`);
2929
core.info(`Driver name: ${driverName}`);
3030
core.info(`Workflow filename for rule ID prefix: ${workflowFilename}`);
31+
core.info(`Working directory: ${process.cwd()}`);
32+
core.info(`GitHub ref: ${process.env.GITHUB_REF || "(not set)"}`);
33+
core.info(`GitHub SHA: ${process.env.GITHUB_SHA || "(not set)"}`);
34+
core.info(`GitHub repository: ${process.env.GITHUB_REPOSITORY || "(not set)"}`);
3135

3236
// Track how many items we've processed for max limit
3337
let processedCount = 0;
@@ -39,6 +43,7 @@ async function main(config = {}) {
3943
// SARIF file path
4044
const sarifFileName = "code-scanning-alert.sarif";
4145
const sarifFilePath = path.join(process.cwd(), sarifFileName);
46+
core.info(`SARIF file will be written to: ${sarifFilePath}`);
4247

4348
/**
4449
* Generate and write SARIF file with all collected findings

setup/js/messages_run_status.cjs

Lines changed: 20 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// @ts-check
2-
/// <reference types="@actions/github-script" />
32

43
/**
54
* Run Status Message Module
@@ -10,6 +9,19 @@
109

1110
const { getMessages, renderTemplate, toSnakeCase } = require("./messages_core.cjs");
1211

12+
/**
13+
* Renders a message using a custom template from config or a default template.
14+
* @param {string} messageKey - Key in the messages config (e.g., "runStarted")
15+
* @param {string} defaultTemplate - Default template string with {placeholder} syntax
16+
* @param {Object} ctx - Context object for template substitution
17+
* @returns {string} Rendered message
18+
*/
19+
function renderConfiguredMessage(messageKey, defaultTemplate, ctx) {
20+
const messages = getMessages();
21+
const template = messages?.[messageKey] ?? defaultTemplate;
22+
return renderTemplate(template, toSnakeCase(ctx));
23+
}
24+
1325
/**
1426
* @typedef {Object} RunStartedContext
1527
* @property {string} workflowName - Name of the workflow
@@ -23,16 +35,7 @@ const { getMessages, renderTemplate, toSnakeCase } = require("./messages_core.cj
2335
* @returns {string} Run-started message
2436
*/
2537
function getRunStartedMessage(ctx) {
26-
const messages = getMessages();
27-
28-
// Create context with both camelCase and snake_case keys
29-
const templateContext = toSnakeCase(ctx);
30-
31-
// Default run-started template
32-
const defaultMessage = "🚀 [{workflow_name}]({run_url}) has started processing this {event_type}";
33-
34-
// Use custom message if configured
35-
return messages?.runStarted ? renderTemplate(messages.runStarted, templateContext) : renderTemplate(defaultMessage, templateContext);
38+
return renderConfiguredMessage("runStarted", "🚀 [{workflow_name}]({run_url}) has started processing this {event_type}", ctx);
3639
}
3740

3841
/**
@@ -47,16 +50,7 @@ function getRunStartedMessage(ctx) {
4750
* @returns {string} Run-success message
4851
*/
4952
function getRunSuccessMessage(ctx) {
50-
const messages = getMessages();
51-
52-
// Create context with both camelCase and snake_case keys
53-
const templateContext = toSnakeCase(ctx);
54-
55-
// Default run-success template
56-
const defaultMessage = "✅ [{workflow_name}]({run_url}) completed successfully!";
57-
58-
// Use custom message if configured
59-
return messages?.runSuccess ? renderTemplate(messages.runSuccess, templateContext) : renderTemplate(defaultMessage, templateContext);
53+
return renderConfiguredMessage("runSuccess", "✅ [{workflow_name}]({run_url}) completed successfully!", ctx);
6054
}
6155

6256
/**
@@ -72,16 +66,7 @@ function getRunSuccessMessage(ctx) {
7266
* @returns {string} Run-failure message
7367
*/
7468
function getRunFailureMessage(ctx) {
75-
const messages = getMessages();
76-
77-
// Create context with both camelCase and snake_case keys
78-
const templateContext = toSnakeCase(ctx);
79-
80-
// Default run-failure template
81-
const defaultMessage = "❌ [{workflow_name}]({run_url}) {status}. Please review the logs for details.";
82-
83-
// Use custom message if configured
84-
return messages?.runFailure ? renderTemplate(messages.runFailure, templateContext) : renderTemplate(defaultMessage, templateContext);
69+
return renderConfiguredMessage("runFailure", "❌ [{workflow_name}]({run_url}) {status}. Please review the logs for details.", ctx);
8570
}
8671

8772
/**
@@ -96,16 +81,7 @@ function getRunFailureMessage(ctx) {
9681
* @returns {string} Detection-failure message
9782
*/
9883
function getDetectionFailureMessage(ctx) {
99-
const messages = getMessages();
100-
101-
// Create context with both camelCase and snake_case keys
102-
const templateContext = toSnakeCase(ctx);
103-
104-
// Default detection-failure template
105-
const defaultMessage = "⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.";
106-
107-
// Use custom message if configured
108-
return messages?.detectionFailure ? renderTemplate(messages.detectionFailure, templateContext) : renderTemplate(defaultMessage, templateContext);
84+
return renderConfiguredMessage("detectionFailure", "⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.", ctx);
10985
}
11086

11187
/**
@@ -120,10 +96,7 @@ function getDetectionFailureMessage(ctx) {
12096
* @returns {string} Pull-request-created message
12197
*/
12298
function getPullRequestCreatedMessage(ctx) {
123-
const messages = getMessages();
124-
const templateContext = toSnakeCase(ctx);
125-
const defaultMessage = "Pull request created: [#{item_number}]({item_url})";
126-
return messages?.pullRequestCreated ? renderTemplate(messages.pullRequestCreated, templateContext) : renderTemplate(defaultMessage, templateContext);
99+
return renderConfiguredMessage("pullRequestCreated", "Pull request created: [#{item_number}]({item_url})", ctx);
127100
}
128101

129102
/**
@@ -138,10 +111,7 @@ function getPullRequestCreatedMessage(ctx) {
138111
* @returns {string} Issue-created message
139112
*/
140113
function getIssueCreatedMessage(ctx) {
141-
const messages = getMessages();
142-
const templateContext = toSnakeCase(ctx);
143-
const defaultMessage = "Issue created: [#{item_number}]({item_url})";
144-
return messages?.issueCreated ? renderTemplate(messages.issueCreated, templateContext) : renderTemplate(defaultMessage, templateContext);
114+
return renderConfiguredMessage("issueCreated", "Issue created: [#{item_number}]({item_url})", ctx);
145115
}
146116

147117
/**
@@ -157,10 +127,7 @@ function getIssueCreatedMessage(ctx) {
157127
* @returns {string} Commit-pushed message
158128
*/
159129
function getCommitPushedMessage(ctx) {
160-
const messages = getMessages();
161-
const templateContext = toSnakeCase(ctx);
162-
const defaultMessage = "Commit pushed: [`{short_sha}`]({commit_url})";
163-
return messages?.commitPushed ? renderTemplate(messages.commitPushed, templateContext) : renderTemplate(defaultMessage, templateContext);
130+
return renderConfiguredMessage("commitPushed", "Commit pushed: [`{short_sha}`]({commit_url})", ctx);
164131
}
165132

166133
module.exports = {

setup/js/push_repo_memory.cjs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,24 +384,47 @@ async function main() {
384384
}
385385

386386
// Validate total patch size before committing
387+
// Only additions (new content) are counted toward the patch size limit.
388+
// Deletions are ignored since removing content is acceptable and does not
389+
// contribute to the size of the content being pushed.
387390
try {
388391
const patchContent = execGitSync(["diff", "--cached"], { stdio: "pipe" });
389-
const patchSizeBytes = Buffer.byteLength(patchContent, "utf8");
392+
// Count only added lines (starting with '+', excluding '+++' file-header lines)
393+
const addedSizeBytes = patchContent
394+
.split("\n")
395+
.filter(line => line.startsWith("+") && !line.startsWith("+++"))
396+
.reduce((sum, line) => sum + Buffer.byteLength(line + "\n", "utf8"), 0);
397+
const patchSizeBytes = addedSizeBytes;
390398
const patchSizeKb = Math.ceil(patchSizeBytes / 1024);
391399
const maxPatchSizeKb = Math.floor(maxPatchSize / 1024);
392400
// Allow 20% overhead to account for git diff format (headers, context lines, etc.)
393401
const effectiveMaxPatchSize = Math.floor(maxPatchSize * 1.2);
394402
const effectiveMaxPatchSizeKb = Math.floor(effectiveMaxPatchSize / 1024);
395-
core.info(`Patch size: ${patchSizeKb} KB (${patchSizeBytes} bytes) (configured limit: ${maxPatchSizeKb} KB (${maxPatchSize} bytes), effective with 20% overhead: ${effectiveMaxPatchSizeKb} KB (${effectiveMaxPatchSize} bytes))`);
403+
const patchSizeMessage = `Patch additions size: ${patchSizeKb} KB (${patchSizeBytes} bytes) (configured limit: ${maxPatchSizeKb} KB (${maxPatchSize} bytes), effective with 20% overhead: ${effectiveMaxPatchSizeKb} KB (${effectiveMaxPatchSize} bytes))`;
396404
if (patchSizeBytes > effectiveMaxPatchSize) {
405+
// Warn at warning level so the size is visible even without verbose mode
406+
core.warning(patchSizeMessage);
407+
// Add per-file diff stats to diagnose what's causing the large patch
408+
// (e.g. a full rewrite of an accumulated history file shows old + new content in the diff)
409+
try {
410+
const diffStat = execGitSync(["diff", "--cached", "--stat"], { stdio: "pipe" });
411+
core.warning(`Patch content breakdown (git diff --stat):\n${diffStat}`);
412+
} catch (statError) {
413+
core.warning(`Could not retrieve diff stat: ${getErrorMessage(statError)}`);
414+
}
397415
core.setOutput("patch_size_exceeded", "true");
398416
core.setFailed(
399-
`Patch size (${patchSizeKb} KB, ${patchSizeBytes} bytes) exceeds maximum allowed size (${effectiveMaxPatchSizeKb} KB, ${effectiveMaxPatchSize} bytes, configured limit: ${maxPatchSizeKb} KB with 20% overhead allowance). Reduce the number or size of changes, or increase max-patch-size.`
417+
`Patch additions size (${patchSizeKb} KB, ${patchSizeBytes} bytes) exceeds maximum allowed size (${effectiveMaxPatchSizeKb} KB, ${effectiveMaxPatchSize} bytes, configured limit: ${maxPatchSizeKb} KB with 20% overhead allowance). Reduce the number or size of changes, or increase max-patch-size.`
400418
);
401419
return;
420+
} else if (patchSizeBytes > maxPatchSize) {
421+
// Within the 20% overhead window — still log as a warning so it's visible
422+
core.warning(patchSizeMessage);
423+
} else {
424+
core.info(patchSizeMessage);
402425
}
403426
} catch (error) {
404-
core.setFailed(`Failed to compute patch size: ${getErrorMessage(error)}`);
427+
core.setFailed(`Failed to compute patch additions size: ${getErrorMessage(error)}`);
405428
return;
406429
}
407430

0 commit comments

Comments
 (0)