Skip to content

Commit b199bde

Browse files
committed
bugfix-314-error-merging-release-branch-after-successful-deployment: Enhance logging functionality by introducing accumulated log management. Added methods to clear and retrieve accumulated logs, and updated log functions to support accumulation. Implemented tests to verify the correct behavior of log accumulation and formatting, ensuring robust logging capabilities.
1 parent b910620 commit b199bde

File tree

10 files changed

+320
-30
lines changed

10 files changed

+320
-30
lines changed

build/cli/index.js

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46694,6 +46694,7 @@ const queue_utils_1 = __nccwpck_require__(9800);
4669446694
async function mainRun(execution) {
4669546695
const results = [];
4669646696
await execution.setup();
46697+
(0, logger_1.clearAccumulatedLogs)();
4669746698
if (!execution.welcome) {
4669846699
/**
4669946700
* Wait for previous runs to finish
@@ -51378,8 +51379,24 @@ This PR merges **${head}** into **${base}**.
5137851379
// haven't registered yet, or this PR/base has no required checks.
5137951380
waitForPrChecksAttempts++;
5138051381
if (waitForPrChecksAttempts >= maxWaitForPrChecksAttempts) {
51381-
checksCompleted = true;
51382-
(0, logger_1.logDebugInfo)(`No check runs for this PR after ${maxWaitForPrChecksAttempts} polls; proceeding to merge (branch may have no required checks).`);
51382+
// Give up waiting for PR-specific check runs; fall back to status checks
51383+
// before proceeding to merge (PR may have required status checks).
51384+
const pendingChecksFallback = commitStatus.statuses.filter(status => {
51385+
(0, logger_1.logDebugInfo)(`Status check (fallback): ${status.context} (State: ${status.state})`);
51386+
return status.state === 'pending';
51387+
});
51388+
if (pendingChecksFallback.length === 0) {
51389+
checksCompleted = true;
51390+
(0, logger_1.logDebugInfo)(`No check runs for this PR after ${maxWaitForPrChecksAttempts} polls; no pending status checks; proceeding to merge.`);
51391+
}
51392+
else {
51393+
(0, logger_1.logDebugInfo)(`No check runs for this PR after ${maxWaitForPrChecksAttempts} polls; falling back to status checks. Waiting for ${pendingChecksFallback.length} status checks to complete.`);
51394+
pendingChecksFallback.forEach(check => {
51395+
(0, logger_1.logDebugInfo)(` - ${check.context} (State: ${check.state})`);
51396+
});
51397+
await new Promise(resolve => setTimeout(resolve, iteration * 1000));
51398+
attempts++;
51399+
}
5138351400
}
5138451401
else {
5138551402
(0, logger_1.logDebugInfo)('Check runs exist on ref but none for this PR yet; waiting for workflows to register.');
@@ -60265,6 +60282,9 @@ exports.getRandomElement = getRandomElement;
6026560282
"use strict";
6026660283

6026760284
Object.defineProperty(exports, "__esModule", ({ value: true }));
60285+
exports.getAccumulatedLogEntries = getAccumulatedLogEntries;
60286+
exports.getAccumulatedLogsAsText = getAccumulatedLogsAsText;
60287+
exports.clearAccumulatedLogs = clearAccumulatedLogs;
6026860288
exports.setGlobalLoggerDebug = setGlobalLoggerDebug;
6026960289
exports.setStructuredLogging = setStructuredLogging;
6027060290
exports.logInfo = logInfo;
@@ -60277,6 +60297,25 @@ exports.logDebugError = logDebugError;
6027760297
let loggerDebug = false;
6027860298
let loggerRemote = false;
6027960299
let structuredLogging = false;
60300+
const accumulatedLogEntries = [];
60301+
function pushLogEntry(entry) {
60302+
accumulatedLogEntries.push(entry);
60303+
}
60304+
function getAccumulatedLogEntries() {
60305+
return [...accumulatedLogEntries];
60306+
}
60307+
function getAccumulatedLogsAsText() {
60308+
return accumulatedLogEntries
60309+
.map((e) => {
60310+
const prefix = `[${e.level.toUpperCase()}]`;
60311+
const meta = e.metadata?.stack ? `\n${String(e.metadata.stack)}` : '';
60312+
return `${prefix} ${e.message}${meta}`;
60313+
})
60314+
.join('\n');
60315+
}
60316+
function clearAccumulatedLogs() {
60317+
accumulatedLogEntries.length = 0;
60318+
}
6028060319
function setGlobalLoggerDebug(debug, isRemote = false) {
6028160320
loggerDebug = debug;
6028260321
loggerRemote = isRemote;
@@ -60287,7 +60326,10 @@ function setStructuredLogging(enabled) {
6028760326
function formatStructuredLog(entry) {
6028860327
return JSON.stringify(entry);
6028960328
}
60290-
function logInfo(message, previousWasSingleLine = false, metadata) {
60329+
function logInfo(message, previousWasSingleLine = false, metadata, skipAccumulation) {
60330+
if (!skipAccumulation) {
60331+
pushLogEntry({ level: 'info', message, timestamp: Date.now(), metadata });
60332+
}
6029160333
if (previousWasSingleLine && !loggerRemote) {
6029260334
console.log();
6029360335
}
@@ -60304,6 +60346,7 @@ function logInfo(message, previousWasSingleLine = false, metadata) {
6030460346
}
6030560347
}
6030660348
function logWarn(message, metadata) {
60349+
pushLogEntry({ level: 'warn', message, timestamp: Date.now(), metadata });
6030760350
if (structuredLogging) {
6030860351
console.warn(formatStructuredLog({
6030960352
level: 'warn',
@@ -60321,15 +60364,17 @@ function logWarning(message) {
6032160364
}
6032260365
function logError(message, metadata) {
6032360366
const errorMessage = message instanceof Error ? message.message : String(message);
60367+
const metaWithStack = {
60368+
...metadata,
60369+
stack: message instanceof Error ? message.stack : undefined
60370+
};
60371+
pushLogEntry({ level: 'error', message: errorMessage, timestamp: Date.now(), metadata: metaWithStack });
6032460372
if (structuredLogging) {
6032560373
console.error(formatStructuredLog({
6032660374
level: 'error',
6032760375
message: errorMessage,
6032860376
timestamp: Date.now(),
60329-
metadata: {
60330-
...metadata,
60331-
stack: message instanceof Error ? message.stack : undefined
60332-
}
60377+
metadata: metaWithStack
6033360378
}));
6033460379
}
6033560380
else {
@@ -60338,6 +60383,7 @@ function logError(message, metadata) {
6033860383
}
6033960384
function logDebugInfo(message, previousWasSingleLine = false, metadata) {
6034060385
if (loggerDebug) {
60386+
pushLogEntry({ level: 'debug', message, timestamp: Date.now(), metadata });
6034160387
if (structuredLogging) {
6034260388
console.log(formatStructuredLog({
6034360389
level: 'debug',
@@ -60347,7 +60393,7 @@ function logDebugInfo(message, previousWasSingleLine = false, metadata) {
6034760393
}));
6034860394
}
6034960395
else {
60350-
logInfo(message, previousWasSingleLine);
60396+
logInfo(message, previousWasSingleLine, undefined, true);
6035160397
}
6035260398
}
6035360399
}

build/cli/src/utils/logger.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ export interface LogEntry {
44
timestamp: number;
55
metadata?: Record<string, unknown>;
66
}
7+
export declare function getAccumulatedLogEntries(): LogEntry[];
8+
export declare function getAccumulatedLogsAsText(): string;
9+
export declare function clearAccumulatedLogs(): void;
710
export declare function setGlobalLoggerDebug(debug: boolean, isRemote?: boolean): void;
811
export declare function setStructuredLogging(enabled: boolean): void;
9-
export declare function logInfo(message: string, previousWasSingleLine?: boolean, metadata?: Record<string, unknown>): void;
12+
export declare function logInfo(message: string, previousWasSingleLine?: boolean, metadata?: Record<string, unknown>, skipAccumulation?: boolean): void;
1013
export declare function logWarn(message: string, metadata?: Record<string, unknown>): void;
1114
export declare function logWarning(message: string): void;
1215
export declare function logError(message: unknown, metadata?: Record<string, unknown>): void;

build/github_action/index.js

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42212,6 +42212,7 @@ const queue_utils_1 = __nccwpck_require__(9800);
4221242212
async function mainRun(execution) {
4221342213
const results = [];
4221442214
await execution.setup();
42215+
(0, logger_1.clearAccumulatedLogs)();
4221542216
if (!execution.welcome) {
4221642217
/**
4221742218
* Wait for previous runs to finish
@@ -46446,8 +46447,24 @@ This PR merges **${head}** into **${base}**.
4644646447
// haven't registered yet, or this PR/base has no required checks.
4644746448
waitForPrChecksAttempts++;
4644846449
if (waitForPrChecksAttempts >= maxWaitForPrChecksAttempts) {
46449-
checksCompleted = true;
46450-
(0, logger_1.logDebugInfo)(`No check runs for this PR after ${maxWaitForPrChecksAttempts} polls; proceeding to merge (branch may have no required checks).`);
46450+
// Give up waiting for PR-specific check runs; fall back to status checks
46451+
// before proceeding to merge (PR may have required status checks).
46452+
const pendingChecksFallback = commitStatus.statuses.filter(status => {
46453+
(0, logger_1.logDebugInfo)(`Status check (fallback): ${status.context} (State: ${status.state})`);
46454+
return status.state === 'pending';
46455+
});
46456+
if (pendingChecksFallback.length === 0) {
46457+
checksCompleted = true;
46458+
(0, logger_1.logDebugInfo)(`No check runs for this PR after ${maxWaitForPrChecksAttempts} polls; no pending status checks; proceeding to merge.`);
46459+
}
46460+
else {
46461+
(0, logger_1.logDebugInfo)(`No check runs for this PR after ${maxWaitForPrChecksAttempts} polls; falling back to status checks. Waiting for ${pendingChecksFallback.length} status checks to complete.`);
46462+
pendingChecksFallback.forEach(check => {
46463+
(0, logger_1.logDebugInfo)(` - ${check.context} (State: ${check.state})`);
46464+
});
46465+
await new Promise(resolve => setTimeout(resolve, iteration * 1000));
46466+
attempts++;
46467+
}
4645146468
}
4645246469
else {
4645346470
(0, logger_1.logDebugInfo)('Check runs exist on ref but none for this PR yet; waiting for workflows to register.');
@@ -52586,14 +52603,30 @@ ${errors}
5258652603
Check your project configuration, if everything is okay consider [opening an issue](https://github.com/vypdev/copilot/issues/new/choose).
5258752604
`;
5258852605
}
52606+
let debugLogSection = '';
52607+
if (param.debug) {
52608+
const logsText = (0, logger_1.getAccumulatedLogsAsText)();
52609+
if (logsText.length > 0) {
52610+
debugLogSection = `
52611+
52612+
<details>
52613+
<summary>Debug log</summary>
52614+
52615+
\`\`\`
52616+
${logsText}
52617+
\`\`\`
52618+
</details>
52619+
`;
52620+
}
52621+
}
5258952622
const commentBody = `# ${title}
5259052623
${content}
5259152624
${errors.length > 0 ? errors : ''}
5259252625

5259352626
${stupidGif}
5259452627

5259552628
${footer}
52596-
52629+
${debugLogSection}
5259752630
🚀 Happy coding!
5259852631
`;
5259952632
if (content.length === 0) {
@@ -55552,6 +55585,9 @@ exports.getRandomElement = getRandomElement;
5555255585
"use strict";
5555355586

5555455587
Object.defineProperty(exports, "__esModule", ({ value: true }));
55588+
exports.getAccumulatedLogEntries = getAccumulatedLogEntries;
55589+
exports.getAccumulatedLogsAsText = getAccumulatedLogsAsText;
55590+
exports.clearAccumulatedLogs = clearAccumulatedLogs;
5555555591
exports.setGlobalLoggerDebug = setGlobalLoggerDebug;
5555655592
exports.setStructuredLogging = setStructuredLogging;
5555755593
exports.logInfo = logInfo;
@@ -55564,6 +55600,25 @@ exports.logDebugError = logDebugError;
5556455600
let loggerDebug = false;
5556555601
let loggerRemote = false;
5556655602
let structuredLogging = false;
55603+
const accumulatedLogEntries = [];
55604+
function pushLogEntry(entry) {
55605+
accumulatedLogEntries.push(entry);
55606+
}
55607+
function getAccumulatedLogEntries() {
55608+
return [...accumulatedLogEntries];
55609+
}
55610+
function getAccumulatedLogsAsText() {
55611+
return accumulatedLogEntries
55612+
.map((e) => {
55613+
const prefix = `[${e.level.toUpperCase()}]`;
55614+
const meta = e.metadata?.stack ? `\n${String(e.metadata.stack)}` : '';
55615+
return `${prefix} ${e.message}${meta}`;
55616+
})
55617+
.join('\n');
55618+
}
55619+
function clearAccumulatedLogs() {
55620+
accumulatedLogEntries.length = 0;
55621+
}
5556755622
function setGlobalLoggerDebug(debug, isRemote = false) {
5556855623
loggerDebug = debug;
5556955624
loggerRemote = isRemote;
@@ -55574,7 +55629,10 @@ function setStructuredLogging(enabled) {
5557455629
function formatStructuredLog(entry) {
5557555630
return JSON.stringify(entry);
5557655631
}
55577-
function logInfo(message, previousWasSingleLine = false, metadata) {
55632+
function logInfo(message, previousWasSingleLine = false, metadata, skipAccumulation) {
55633+
if (!skipAccumulation) {
55634+
pushLogEntry({ level: 'info', message, timestamp: Date.now(), metadata });
55635+
}
5557855636
if (previousWasSingleLine && !loggerRemote) {
5557955637
console.log();
5558055638
}
@@ -55591,6 +55649,7 @@ function logInfo(message, previousWasSingleLine = false, metadata) {
5559155649
}
5559255650
}
5559355651
function logWarn(message, metadata) {
55652+
pushLogEntry({ level: 'warn', message, timestamp: Date.now(), metadata });
5559455653
if (structuredLogging) {
5559555654
console.warn(formatStructuredLog({
5559655655
level: 'warn',
@@ -55608,15 +55667,17 @@ function logWarning(message) {
5560855667
}
5560955668
function logError(message, metadata) {
5561055669
const errorMessage = message instanceof Error ? message.message : String(message);
55670+
const metaWithStack = {
55671+
...metadata,
55672+
stack: message instanceof Error ? message.stack : undefined
55673+
};
55674+
pushLogEntry({ level: 'error', message: errorMessage, timestamp: Date.now(), metadata: metaWithStack });
5561155675
if (structuredLogging) {
5561255676
console.error(formatStructuredLog({
5561355677
level: 'error',
5561455678
message: errorMessage,
5561555679
timestamp: Date.now(),
55616-
metadata: {
55617-
...metadata,
55618-
stack: message instanceof Error ? message.stack : undefined
55619-
}
55680+
metadata: metaWithStack
5562055681
}));
5562155682
}
5562255683
else {
@@ -55625,6 +55686,7 @@ function logError(message, metadata) {
5562555686
}
5562655687
function logDebugInfo(message, previousWasSingleLine = false, metadata) {
5562755688
if (loggerDebug) {
55689+
pushLogEntry({ level: 'debug', message, timestamp: Date.now(), metadata });
5562855690
if (structuredLogging) {
5562955691
console.log(formatStructuredLog({
5563055692
level: 'debug',
@@ -55634,7 +55696,7 @@ function logDebugInfo(message, previousWasSingleLine = false, metadata) {
5563455696
}));
5563555697
}
5563655698
else {
55637-
logInfo(message, previousWasSingleLine);
55699+
logInfo(message, previousWasSingleLine, undefined, true);
5563855700
}
5563955701
}
5564055702
}

build/github_action/src/utils/logger.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ export interface LogEntry {
44
timestamp: number;
55
metadata?: Record<string, unknown>;
66
}
7+
export declare function getAccumulatedLogEntries(): LogEntry[];
8+
export declare function getAccumulatedLogsAsText(): string;
9+
export declare function clearAccumulatedLogs(): void;
710
export declare function setGlobalLoggerDebug(debug: boolean, isRemote?: boolean): void;
811
export declare function setStructuredLogging(enabled: boolean): void;
9-
export declare function logInfo(message: string, previousWasSingleLine?: boolean, metadata?: Record<string, unknown>): void;
12+
export declare function logInfo(message: string, previousWasSingleLine?: boolean, metadata?: Record<string, unknown>, skipAccumulation?: boolean): void;
1013
export declare function logWarn(message: string, metadata?: Record<string, unknown>): void;
1114
export declare function logWarning(message: string): void;
1215
export declare function logError(message: unknown, metadata?: Record<string, unknown>): void;

src/actions/__tests__/common_action.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jest.mock('@actions/core', () => ({
2121
jest.mock('../../utils/logger', () => ({
2222
logInfo: jest.fn(),
2323
logError: jest.fn(),
24+
clearAccumulatedLogs: jest.fn(),
2425
}));
2526

2627
jest.mock('../../utils/queue_utils', () => ({
@@ -66,6 +67,7 @@ jest.mock('../../usecase/commit_use_case', () => ({
6667
}));
6768

6869
const core = require('@actions/core');
70+
const logger = require('../../utils/logger');
6971
const { waitForPreviousRuns } = require('../../utils/queue_utils');
7072

7173
function mockExecution(overrides: Record<string, unknown> = {}): Execution {
@@ -103,11 +105,12 @@ describe('mainRun', () => {
103105
mockCommitInvoke.mockResolvedValue([]);
104106
});
105107

106-
it('calls execution.setup()', async () => {
108+
it('calls execution.setup() and clearAccumulatedLogs()', async () => {
107109
const setupMock = jest.fn().mockResolvedValue(undefined);
108110
const execution = mockExecution({ setup: setupMock });
109111
await mainRun(execution);
110112
expect(setupMock).toHaveBeenCalledTimes(1);
113+
expect(logger.clearAccumulatedLogs).toHaveBeenCalledTimes(1);
111114
});
112115

113116
it('waits for previous runs when welcome is false', async () => {

src/actions/common_action.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { IssueUseCase } from '../usecase/issue_use_case';
77
import { PullRequestReviewCommentUseCase } from '../usecase/pull_request_review_comment_use_case';
88
import { PullRequestUseCase } from '../usecase/pull_request_use_case';
99
import { SingleActionUseCase } from '../usecase/single_action_use_case';
10-
import { logError, logInfo } from '../utils/logger';
10+
import { clearAccumulatedLogs, logError, logInfo } from '../utils/logger';
1111
import { TITLE } from '../utils/constants';
1212
import chalk from 'chalk';
1313
import boxen from 'boxen';
@@ -17,6 +17,7 @@ export async function mainRun(execution: Execution): Promise<Result[]> {
1717
const results: Result[] = []
1818

1919
await execution.setup();
20+
clearAccumulatedLogs();
2021

2122
if (!execution.welcome) {
2223
/**

0 commit comments

Comments
 (0)