Skip to content

Commit 74e4d55

Browse files
authored
Merge pull request #32 from yoavf/feat/progressive-comment-updates
feat: progressive comment updates
2 parents 5bc7cef + 344f3c7 commit 74e4d55

File tree

5 files changed

+306
-90
lines changed

5 files changed

+306
-90
lines changed

dist/index.js

Lines changed: 123 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -89300,31 +89300,32 @@ var __importStar = (this && this.__importStar) || (function () {
8930089300
};
8930189301
})();
8930289302
Object.defineProperty(exports, "__esModule", ({ value: true }));
89303-
exports.postComment = postComment;
89303+
exports.postInitialComment = postInitialComment;
89304+
exports.updateComment = updateComment;
8930489305
const github = __importStar(__nccwpck_require__(75380));
8930589306
const logger_1 = __nccwpck_require__(61661);
8930689307
const COMMENT_MARKER = '<!-- auto-pr-screenshots -->';
89307-
async function postComment(screenshots, errors, options) {
89308-
const { token, context, config } = options;
89308+
async function postInitialComment(options) {
89309+
const { token, context } = options;
8930989310
// Only post comments on pull requests
8931089311
if (context.eventName !== 'pull_request' || !context.payload.pull_request) {
8931189312
logger_1.commentLogger.warn('Not in a pull request context, skipping comment');
89312-
return;
89313+
return null;
8931389314
}
8931489315
const octokit = github.getOctokit(token);
8931589316
const { owner, repo } = context.repo;
8931689317
const prNumber = context.payload.pull_request.number;
89317-
logger_1.commentLogger.info(`💬 Posting comment to PR #${prNumber}`);
89318+
const commitSha = context.payload.pull_request.head.sha.substring(0, 7);
89319+
logger_1.commentLogger.info(`💬 Posting initial comment to PR #${prNumber}`);
8931889320
try {
89321+
const commentBody = generateInitialCommentBody(commitSha);
8931989322
// Find existing comment
8932089323
const { data: comments } = await octokit.rest.issues.listComments({
8932189324
owner,
8932289325
repo,
8932389326
issue_number: prNumber,
8932489327
});
8932589328
const existingComment = comments.find((comment) => comment.body?.includes(COMMENT_MARKER) && comment.user?.type === 'Bot');
89326-
// Generate comment body
89327-
const commentBody = generateCommentBody(screenshots, errors, context, config, options.showAttribution);
8932889329
if (existingComment) {
8932989330
// Update existing comment
8933089331
await octokit.rest.issues.updateComment({
@@ -89333,30 +89334,70 @@ async function postComment(screenshots, errors, options) {
8933389334
comment_id: existingComment.id,
8933489335
body: commentBody,
8933589336
});
89336-
logger_1.commentLogger.success('✅ Updated existing comment');
89337+
logger_1.commentLogger.success('✅ Updated existing comment with initial status');
89338+
return existingComment.id;
8933789339
}
8933889340
else {
8933989341
// Create new comment
89340-
await octokit.rest.issues.createComment({
89342+
const { data: comment } = await octokit.rest.issues.createComment({
8934189343
owner,
8934289344
repo,
8934389345
issue_number: prNumber,
8934489346
body: commentBody,
8934589347
});
89346-
logger_1.commentLogger.success('✅ Created new comment');
89348+
logger_1.commentLogger.success('✅ Created initial comment');
89349+
return comment.id;
8934789350
}
8934889351
}
8934989352
catch (error) {
89350-
logger_1.commentLogger.error('Failed to post comment:', error instanceof Error ? error.message : String(error));
89351-
throw error;
89353+
logger_1.commentLogger.error('Failed to post initial comment:', error instanceof Error ? error.message : String(error));
89354+
return null;
89355+
}
89356+
}
89357+
async function updateComment(commentId, screenshots, errors, options, status) {
89358+
const { token, context, config } = options;
89359+
if (context.eventName !== 'pull_request' || !context.payload.pull_request) {
89360+
return;
89361+
}
89362+
const octokit = github.getOctokit(token);
89363+
const { owner, repo } = context.repo;
89364+
const commitSha = context.payload.pull_request.head.sha.substring(0, 7);
89365+
try {
89366+
const commentBody = generateCommentBody(screenshots, errors, context, config, options.showAttribution, status, commitSha);
89367+
await octokit.rest.issues.updateComment({
89368+
owner,
89369+
repo,
89370+
comment_id: commentId,
89371+
body: commentBody,
89372+
});
89373+
logger_1.commentLogger.success(`✅ Updated comment (${status})`);
89374+
}
89375+
catch (error) {
89376+
logger_1.commentLogger.error('Failed to update comment:', error instanceof Error ? error.message : String(error));
8935289377
}
8935389378
}
89354-
function generateCommentBody(screenshots, errors, context, config, showAttribution = false) {
89379+
function generateInitialCommentBody(commitSha) {
89380+
const timestamp = new Date().toISOString();
89381+
let body = `${COMMENT_MARKER}\n`;
89382+
body += '## 📸 Auto PR Screenshots\n\n';
89383+
body += `🔄 Screenshot capture has started for commit \`${commitSha}\`\n\n`;
89384+
body += `*Started <relative-time datetime="${timestamp}">${timestamp}</relative-time>*\n\n`;
89385+
body += '*Capturing screenshots...*';
89386+
return body;
89387+
}
89388+
function generateCommentBody(screenshots, errors, context, config, showAttribution = false, status = 'complete', commitSha) {
8935589389
const timestamp = new Date().toISOString();
8935689390
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
8935789391
let body = `${COMMENT_MARKER}\n`;
8935889392
body += '## 📸 Auto PR Screenshots\n\n';
89359-
body += `*Updated: ${timestamp}*\n\n`;
89393+
if (status === 'in_progress') {
89394+
body += `🔄 Screenshot capture in progress for commit \`${commitSha}\`\n\n`;
89395+
body += `*Last updated <relative-time datetime="${timestamp}">${timestamp}</relative-time>*\n\n`;
89396+
}
89397+
else {
89398+
body += `✅ Screenshot capture complete for commit \`${commitSha}\`\n\n`;
89399+
body += `*Completed <relative-time datetime="${timestamp}">${timestamp}</relative-time>*\n\n`;
89400+
}
8936089401
if (screenshots.length === 0 && errors.length === 0) {
8936189402
body += `⚠️ No screenshots were captured. Check the [action logs](${runUrl}) for details.\n`;
8936289403
return body;
@@ -90004,9 +90045,49 @@ async function run() {
9000490045
if (context.eventName !== 'pull_request' && !process.env.LOCAL_TEST) {
9000590046
logger_1.logger.warn('⚠️ Not running in a pull request context, some features may be limited');
9000690047
}
90007-
// Capture screenshots
90048+
// Post initial comment
90049+
let commentId = null;
90050+
if (!skipComment && context.eventName === 'pull_request') {
90051+
commentId = await (0, comment_poster_1.postInitialComment)({
90052+
token,
90053+
context,
90054+
config,
90055+
showAttribution,
90056+
});
90057+
}
90058+
// Track uploaded screenshots to avoid re-uploading
90059+
const uploadedScreenshots = [];
90060+
let lastUploadedCount = 0;
90061+
// Capture screenshots with progress updates
9000890062
logger_1.logger.info('📸 Capturing screenshots...');
90009-
const captureResult = await (0, screenshot_capture_1.captureScreenshots)(config, { browsers });
90063+
const captureResult = await (0, screenshot_capture_1.captureScreenshots)(config, {
90064+
browsers,
90065+
onProgress: async (progress) => {
90066+
// Only upload and update if we have more than one screenshot configured
90067+
if (config.screenshots.length <= 1)
90068+
return;
90069+
// Upload any new screenshots
90070+
const newScreenshots = progress.successful.slice(lastUploadedCount);
90071+
if (newScreenshots.length > 0) {
90072+
const newUploaded = await (0, screenshot_uploader_1.uploadScreenshots)(newScreenshots, {
90073+
branch,
90074+
token,
90075+
context,
90076+
});
90077+
uploadedScreenshots.push(...newUploaded);
90078+
lastUploadedCount = progress.successful.length;
90079+
}
90080+
// Update comment with progress
90081+
if (commentId && !skipComment) {
90082+
await (0, comment_poster_1.updateComment)(commentId, uploadedScreenshots, progress.failed, {
90083+
token,
90084+
context,
90085+
config,
90086+
showAttribution,
90087+
}, 'in_progress');
90088+
}
90089+
},
90090+
});
9001090091
const screenshots = captureResult.successful;
9001190092
const screenshotErrors = captureResult.failed;
9001290093
if (screenshotErrors.length > 0) {
@@ -90021,38 +90102,40 @@ async function run() {
9002190102
}
9002290103
else {
9002390104
logger_1.logger.warn('⚠️ Continuing despite no screenshots (fail-on-error is false)');
90024-
// Post comment with just errors if we're in a PR context
90025-
if (!skipComment && context.eventName === 'pull_request') {
90026-
logger_1.logger.info('💬 Posting error comment to PR...');
90027-
await (0, comment_poster_1.postComment)([], screenshotErrors, {
90105+
// Update comment with just errors if we're in a PR context
90106+
if (commentId && !skipComment) {
90107+
await (0, comment_poster_1.updateComment)(commentId, [], screenshotErrors, {
9002890108
token,
9002990109
context,
9003090110
config,
9003190111
showAttribution,
90032-
});
90033-
logger_1.logger.success('✅ Error comment posted');
90112+
}, 'complete');
9003490113
}
9003590114
return; // Exit early but don't fail
9003690115
}
9003790116
}
9003890117
logger_1.logger.success(`✅ Captured ${screenshots.length} screenshot(s)`);
90039-
// Upload to branch
90040-
logger_1.logger.info(`📤 Uploading screenshots to branch: ${branch}`);
90041-
const uploadedUrls = await (0, screenshot_uploader_1.uploadScreenshots)(screenshots, {
90042-
branch,
90043-
token,
90044-
context,
90045-
});
90046-
// Post comment to PR
90047-
if (!skipComment && context.eventName === 'pull_request') {
90048-
logger_1.logger.info('💬 Posting comment to PR...');
90049-
await (0, comment_poster_1.postComment)(uploadedUrls, screenshotErrors, {
90118+
// Upload any remaining screenshots that weren't uploaded during progress
90119+
const remainingScreenshots = screenshots.slice(lastUploadedCount);
90120+
if (remainingScreenshots.length > 0) {
90121+
logger_1.logger.info(`📤 Uploading ${remainingScreenshots.length} remaining screenshot(s) to branch: ${branch}`);
90122+
const remainingUploaded = await (0, screenshot_uploader_1.uploadScreenshots)(remainingScreenshots, {
90123+
branch,
90124+
token,
90125+
context,
90126+
});
90127+
uploadedScreenshots.push(...remainingUploaded);
90128+
}
90129+
// Post final comment update
90130+
if (commentId && !skipComment) {
90131+
logger_1.logger.info('💬 Updating comment with final results...');
90132+
await (0, comment_poster_1.updateComment)(commentId, uploadedScreenshots, screenshotErrors, {
9005090133
token,
9005190134
context,
9005290135
config,
9005390136
showAttribution,
90054-
});
90055-
logger_1.logger.success('✅ Comment posted successfully');
90137+
}, 'complete');
90138+
logger_1.logger.success('✅ Comment updated successfully');
9005690139
}
9005790140
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
9005890141
logger_1.logger.success(`🎉 Auto PR Screenshots completed in ${duration}s`);
@@ -90384,7 +90467,7 @@ const BROWSER_MAP = {
9038490467
webkit: playwright_1.webkit,
9038590468
};
9038690469
async function captureScreenshots(config, options = {}) {
90387-
const { browsers = 'chromium' } = options;
90470+
const { browsers = 'chromium', onProgress } = options;
9038890471
const browserList = browsers.split(',').map((b) => b.trim());
9038990472
logger_1.captureLogger.info(`Starting screenshot capture with browsers: ${browserList.join(', ')}`);
9039090473
const screenshotsDir = path.join(process.cwd(), 'screenshots');
@@ -90409,6 +90492,10 @@ async function captureScreenshots(config, options = {}) {
9040990492
else {
9041090493
failed.push(result.error);
9041190494
}
90495+
// Call progress callback after each screenshot
90496+
if (onProgress) {
90497+
await onProgress({ successful: [...successful], failed: [...failed] });
90498+
}
9041290499
}
9041390500
}
9041490501
finally {

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)