Skip to content

Commit 1f993a4

Browse files
ritikrishuclaude
andauthored
Remove dead renderer/output-dir options, add artifact link to PR comments (#6)
- Remove `renderer` and `output-dir` inputs from action.yml (service is the only renderer; output dir is hardcoded) - Delete src/renderers/metadata.ts (unused since service renderer is mandatory) - Clean up types, config, and main.ts to remove all RendererType/outputDir refs - Update service-api-key description with correct tier limits - Wire artifactUrl into CommentData/DiffCommentData so PR comments include a download link for screenshot artifacts - Fix createArtifactsSummary leading \n\n (spacing handled by comment builder) - Remove renderer row from README inputs table Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 60fc343 commit 1f993a4

11 files changed

Lines changed: 86 additions & 290 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ The base tier works automatically via GitHub's OIDC tokens — just add `id-toke
9393
| `image-quality` | `90` | Quality for webp/jpeg (1-100) |
9494
| `max-frames-per-file` | `20` | Max frames to render per file (0 = unlimited) |
9595
| `upload-artifacts` | `true` | Upload screenshots as workflow artifacts |
96-
| `renderer` | `service` | `service` (screenshots) or `metadata` (frame info only) |
9796
| `service-api-key` | — | API key (optional, for higher limits) |
9897

9998
### Outputs

action.yml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ inputs:
1111
description: 'GitHub token for API access (usually secrets.GITHUB_TOKEN)'
1212
required: true
1313

14-
renderer:
15-
description: 'Renderer mode: "service" (generates screenshots) or "metadata" (frame info only)'
16-
required: false
17-
default: 'service'
18-
1914
review-mode:
2015
description: 'Review mode: "full" (render all frames) or "diff" (show only changes with before/after comparison)'
2116
required: false
@@ -27,13 +22,8 @@ inputs:
2722
default: 'https://pencil.remotestate.com'
2823

2924
service-api-key:
30-
description: 'API key for paid tier (unlimited screenshots). If omitted, uses free tier via GitHub OIDC (100 screenshots/month). Free tier requires "permissions: id-token: write".'
31-
required: false
32-
33-
output-dir:
34-
description: 'Directory to store generated screenshots'
25+
description: 'API key for higher limits (5,000/month). Without a key, free tier gives 1,000/month via GitHub OIDC (requires "permissions: id-token: write"). Contact us for 10,000/month.'
3526
required: false
36-
default: '.pencil-screenshots'
3727

3828
comment-mode:
3929
description: 'How to post comments: "create" (always new), "update" (update existing), "none" (skip commenting)'

dist/index.js

Lines changed: 36 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
22
/******/ var __webpack_modules__ = ({
33

44
/***/ 69287:
5-
/***/ ((__unused_webpack_module, exports) => {
5+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
66

77
"use strict";
88

@@ -19,6 +19,7 @@ exports.calculateSummary = calculateSummary;
1919
exports.buildNoChangesComment = buildNoChangesComment;
2020
exports.buildDiffComment = buildDiffComment;
2121
exports.calculateDiffSummary = calculateDiffSummary;
22+
const artifacts_1 = __nccwpck_require__(98157);
2223
// Unique identifier for our comments (for upsert logic)
2324
exports.COMMENT_MARKER = '<!-- pencil-design-review -->';
2425
/**
@@ -55,6 +56,12 @@ function buildComment(data, commentId) {
5556
lines.push(buildFileSection(file));
5657
lines.push('');
5758
}
59+
// Add artifact download link
60+
const artifactLink = (0, artifacts_1.createArtifactsSummary)(data.artifactUrl, data.summary.successfulRenders);
61+
if (artifactLink) {
62+
lines.push(artifactLink);
63+
lines.push('');
64+
}
5865
// Add footer
5966
lines.push('---');
6067
lines.push(buildFooter(data.commitSha));
@@ -135,7 +142,7 @@ function buildFrameWithScreenshot(frame) {
135142
return lines.join('\n');
136143
}
137144
/**
138-
* Build a table of frames (metadata mode)
145+
* Build a table of frames (fallback for render failures)
139146
*/
140147
function buildFrameTable(frames) {
141148
const lines = [
@@ -263,6 +270,13 @@ function buildDiffComment(data, commentId) {
263270
lines.push(buildDiffFileSection(file));
264271
lines.push('');
265272
}
273+
// Add artifact download link
274+
const totalRendered = data.summary.totalAddedFrames + data.summary.totalModifiedFrames;
275+
const artifactLink = (0, artifacts_1.createArtifactsSummary)(data.artifactUrl, totalRendered);
276+
if (artifactLink) {
277+
lines.push(artifactLink);
278+
lines.push('');
279+
}
266280
lines.push('---');
267281
lines.push(buildFooter(data.commitSha));
268282
return lines.join('\n');
@@ -465,19 +479,15 @@ exports.getInputs = getInputs;
465479
exports.validateInputs = validateInputs;
466480
const core = __importStar(__nccwpck_require__(37484));
467481
function getInputs() {
468-
const renderer = (core.getInput('renderer') || 'service');
469482
const serviceUrl = core.getInput('service-url');
470483
const serviceApiKey = core.getInput('service-api-key');
471-
// Validate renderer configuration
472-
if (renderer === 'service' && !serviceUrl) {
473-
throw new Error('service-url is required when using the "service" renderer');
484+
if (!serviceUrl) {
485+
throw new Error('service-url is required');
474486
}
475487
const inputs = {
476488
githubToken: core.getInput('github-token', { required: true }),
477-
renderer: renderer,
478489
serviceUrl: serviceUrl || undefined,
479490
serviceApiKey: serviceApiKey || undefined,
480-
outputDir: core.getInput('output-dir') || '.pencil-screenshots',
481491
commentMode: core.getInput('comment-mode') || 'update',
482492
commentId: core.getInput('comment-id') || '',
483493
uploadArtifacts: core.getBooleanInput('upload-artifacts'),
@@ -498,9 +508,6 @@ function validateInputs(inputs) {
498508
if (!inputs.githubToken) {
499509
throw new Error('github-token is required');
500510
}
501-
if (!['metadata', 'service'].includes(inputs.renderer)) {
502-
throw new Error(`Invalid renderer: ${inputs.renderer}. Must be "service" or "metadata"`);
503-
}
504511
if (!['create', 'update', 'none'].includes(inputs.commentMode)) {
505512
throw new Error(`Invalid comment-mode: ${inputs.commentMode}. Must be "create", "update", or "none"`);
506513
}
@@ -637,7 +644,7 @@ function createArtifactsSummary(artifactUrl, fileCount) {
637644
if (!artifactUrl) {
638645
return '';
639646
}
640-
return `\n\n📦 [View all screenshots (${fileCount} files)](${artifactUrl})`;
647+
return `📦 [Download all screenshots (${fileCount} files)](${artifactUrl})`;
641648
}
642649
/**
643650
* Clean up screenshots directory
@@ -1065,8 +1072,8 @@ const files_1 = __nccwpck_require__(62605);
10651072
const comments_1 = __nccwpck_require__(64758);
10661073
const artifacts_1 = __nccwpck_require__(98157);
10671074
const comment_builder_1 = __nccwpck_require__(69287);
1068-
const metadata_1 = __nccwpck_require__(19554);
10691075
const service_1 = __nccwpck_require__(35300);
1076+
const OUTPUT_DIR = '.pencil-screenshots';
10701077
async function run() {
10711078
try {
10721079
// Validate we're in a PR context
@@ -1078,7 +1085,6 @@ async function run() {
10781085
const inputs = (0, config_1.getInputs)();
10791086
(0, config_1.validateInputs)(inputs);
10801087
core.info('🎨 Starting Pencil Design Review');
1081-
core.info(`Renderer: ${inputs.renderer}`);
10821088
core.info(`Review mode: ${inputs.reviewMode}`);
10831089
core.info(`Comment mode: ${inputs.commentMode}`);
10841090
// Initialize GitHub client
@@ -1095,13 +1101,10 @@ async function run() {
10951101
return;
10961102
}
10971103
core.info(`Found ${changedFiles.length} changed .pen files`);
1098-
if (inputs.reviewMode === 'diff' && inputs.renderer === 'service') {
1104+
if (inputs.reviewMode === 'diff') {
10991105
await runDiffMode(inputs, octokit, prContext, changedFiles);
11001106
}
11011107
else {
1102-
if (inputs.reviewMode === 'diff' && inputs.renderer !== 'service') {
1103-
core.warning('Diff review mode requires renderer: "service". Falling back to full mode.');
1104-
}
11051108
await runFullMode(inputs, octokit, prContext, changedFiles);
11061109
}
11071110
}
@@ -1124,7 +1127,7 @@ async function runFullMode(inputs, octokit, prContext, changedFiles) {
11241127
// Process each file
11251128
const fileResults = [];
11261129
let totalFramesRendered = 0;
1127-
(0, artifacts_1.ensureScreenshotsDir)(inputs.outputDir);
1130+
(0, artifacts_1.ensureScreenshotsDir)(OUTPUT_DIR);
11281131
for (const file of changedFiles) {
11291132
core.info(`Processing: ${file.path}`);
11301133
if (file.status === 'deleted') {
@@ -1148,7 +1151,7 @@ async function runFullMode(inputs, octokit, prContext, changedFiles) {
11481151
// Render each frame
11491152
const frameResults = [];
11501153
for (const frame of framesToProcess) {
1151-
const outputPath = getOutputPath(inputs.outputDir, file.path, frame, inputs.imageFormat);
1154+
const outputPath = getOutputPath(OUTPUT_DIR, file.path, frame, inputs.imageFormat);
11521155
const result = await renderer.renderFrame(file.path, frame, outputPath);
11531156
frameResults.push({
11541157
id: frame.id,
@@ -1185,7 +1188,7 @@ async function runFullMode(inputs, octokit, prContext, changedFiles) {
11851188
// Upload screenshots as artifacts
11861189
let artifactUrl;
11871190
if (inputs.uploadArtifacts) {
1188-
const uploadResult = await (0, artifacts_1.uploadScreenshots)(inputs.outputDir);
1191+
const uploadResult = await (0, artifacts_1.uploadScreenshots)(OUTPUT_DIR);
11891192
artifactUrl = uploadResult.artifactUrl;
11901193
}
11911194
// Build and post comment
@@ -1196,6 +1199,7 @@ async function runFullMode(inputs, octokit, prContext, changedFiles) {
11961199
summary,
11971200
prNumber: prContext.prNumber,
11981201
commitSha: prContext.headSha,
1202+
artifactUrl,
11991203
};
12001204
const commentBody = (0, comment_builder_1.buildComment)(commentData, inputs.commentId);
12011205
const postedCommentId = await (0, comments_1.postComment)(octokit, prContext.prNumber, commentBody, inputs.commentMode, inputs.commentId);
@@ -1205,7 +1209,7 @@ async function runFullMode(inputs, octokit, prContext, changedFiles) {
12051209
}
12061210
// Set outputs
12071211
setOutputs({
1208-
screenshotsPath: inputs.outputDir,
1212+
screenshotsPath: OUTPUT_DIR,
12091213
changedFiles: changedFiles.map(f => f.path),
12101214
framesRendered: totalFramesRendered,
12111215
});
@@ -1224,7 +1228,7 @@ async function runDiffMode(inputs, octokit, prContext, changedFiles) {
12241228
try {
12251229
const fileResults = [];
12261230
let totalFramesRendered = 0;
1227-
(0, artifacts_1.ensureScreenshotsDir)(inputs.outputDir);
1231+
(0, artifacts_1.ensureScreenshotsDir)(OUTPUT_DIR);
12281232
for (const file of changedFiles) {
12291233
core.info(`Processing (diff): ${file.path}`);
12301234
if (file.status === 'deleted') {
@@ -1270,8 +1274,10 @@ async function runDiffMode(inputs, octokit, prContext, changedFiles) {
12701274
}
12711275
}
12721276
// Upload artifacts
1277+
let artifactUrl;
12731278
if (inputs.uploadArtifacts) {
1274-
await (0, artifacts_1.uploadScreenshots)(inputs.outputDir);
1279+
const uploadResult = await (0, artifacts_1.uploadScreenshots)(OUTPUT_DIR);
1280+
artifactUrl = uploadResult.artifactUrl;
12751281
}
12761282
// Build and post comment
12771283
if (inputs.commentMode !== 'none') {
@@ -1281,6 +1287,7 @@ async function runDiffMode(inputs, octokit, prContext, changedFiles) {
12811287
summary,
12821288
prNumber: prContext.prNumber,
12831289
commitSha: prContext.headSha,
1290+
artifactUrl,
12841291
};
12851292
const commentBody = (0, comment_builder_1.buildDiffComment)(commentData, inputs.commentId);
12861293
const postedCommentId = await (0, comments_1.postComment)(octokit, prContext.prNumber, commentBody, inputs.commentMode, inputs.commentId);
@@ -1289,7 +1296,7 @@ async function runDiffMode(inputs, octokit, prContext, changedFiles) {
12891296
}
12901297
}
12911298
setOutputs({
1292-
screenshotsPath: inputs.outputDir,
1299+
screenshotsPath: OUTPUT_DIR,
12931300
changedFiles: changedFiles.map(f => f.path),
12941301
framesRendered: totalFramesRendered,
12951302
});
@@ -1311,7 +1318,7 @@ async function renderFullFile(renderer, file, inputs) {
13111318
: frames;
13121319
const frameResults = [];
13131320
for (const frame of framesToProcess) {
1314-
const outputPath = getOutputPath(inputs.outputDir, file.path, frame, inputs.imageFormat);
1321+
const outputPath = getOutputPath(OUTPUT_DIR, file.path, frame, inputs.imageFormat);
13151322
const result = await renderer.renderFrame(file.path, frame, outputPath);
13161323
frameResults.push({
13171324
id: frame.id,
@@ -1327,15 +1334,8 @@ async function renderFullFile(renderer, file, inputs) {
13271334
* Initialize the appropriate renderer based on configuration
13281335
*/
13291336
async function initializeRenderer(inputs) {
1330-
let renderer;
1331-
if (inputs.renderer === 'service' && inputs.serviceUrl) {
1332-
core.info('Using service renderer (pencil-screenshot-service)');
1333-
renderer = (0, service_1.createServiceRenderer)(inputs.serviceUrl, inputs.serviceApiKey, inputs.imageFormat, inputs.imageScale, inputs.imageQuality);
1334-
}
1335-
else {
1336-
core.info('Using metadata renderer (no screenshots)');
1337-
renderer = new metadata_1.MetadataRenderer();
1338-
}
1337+
core.info('Using service renderer (pencil-screenshot-service)');
1338+
const renderer = (0, service_1.createServiceRenderer)(inputs.serviceUrl, inputs.serviceApiKey, inputs.imageFormat, inputs.imageScale, inputs.imageQuality);
13391339
await renderer.initialize();
13401340
return renderer;
13411341
}
@@ -1376,7 +1376,7 @@ run();
13761376
* Parser for .pen design files
13771377
*
13781378
* .pen files are JSON-based design files from Pencil.dev
1379-
* This module extracts frame information for the metadata renderer
1379+
* This module extracts frame information from .pen design files
13801380
*/
13811381
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13821382
if (k2 === undefined) k2 = k;
@@ -1525,116 +1525,6 @@ function createErrorResult(frame, filePath, error) {
15251525

15261526
/***/ }),
15271527

1528-
/***/ 19554:
1529-
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
1530-
1531-
"use strict";
1532-
1533-
/**
1534-
* Metadata-only renderer
1535-
*
1536-
* This renderer doesn't generate actual screenshots.
1537-
* It extracts frame information from .pen files for display in PR comments.
1538-
* Used when no screenshot service is configured.
1539-
*/
1540-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
1541-
if (k2 === undefined) k2 = k;
1542-
var desc = Object.getOwnPropertyDescriptor(m, k);
1543-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1544-
desc = { enumerable: true, get: function() { return m[k]; } };
1545-
}
1546-
Object.defineProperty(o, k2, desc);
1547-
}) : (function(o, m, k, k2) {
1548-
if (k2 === undefined) k2 = k;
1549-
o[k2] = m[k];
1550-
}));
1551-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
1552-
Object.defineProperty(o, "default", { enumerable: true, value: v });
1553-
}) : function(o, v) {
1554-
o["default"] = v;
1555-
});
1556-
var __importStar = (this && this.__importStar) || (function () {
1557-
var ownKeys = function(o) {
1558-
ownKeys = Object.getOwnPropertyNames || function (o) {
1559-
var ar = [];
1560-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
1561-
return ar;
1562-
};
1563-
return ownKeys(o);
1564-
};
1565-
return function (mod) {
1566-
if (mod && mod.__esModule) return mod;
1567-
var result = {};
1568-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1569-
__setModuleDefault(result, mod);
1570-
return result;
1571-
};
1572-
})();
1573-
Object.defineProperty(exports, "__esModule", ({ value: true }));
1574-
exports.MetadataRenderer = void 0;
1575-
const core = __importStar(__nccwpck_require__(37484));
1576-
const base_1 = __nccwpck_require__(35458);
1577-
const fs = __importStar(__nccwpck_require__(79896));
1578-
const path = __importStar(__nccwpck_require__(16928));
1579-
class MetadataRenderer extends base_1.BaseRenderer {
1580-
name = 'metadata';
1581-
async initialize() {
1582-
core.info('Initializing metadata renderer (no screenshots will be generated)');
1583-
}
1584-
async isAvailable() {
1585-
// Metadata renderer is always available
1586-
return true;
1587-
}
1588-
/**
1589-
* For metadata mode, we don't generate actual screenshots
1590-
* We just validate that the frame exists and return success
1591-
*/
1592-
async renderFrame(penFilePath, frame, outputPath) {
1593-
core.debug(`Processing frame metadata: ${frame.name} (${frame.id})`);
1594-
// Create a placeholder file with frame info (for artifact upload)
1595-
const placeholderPath = outputPath.replace(/\.(png|jpe?g|webp)$/i, '.json');
1596-
try {
1597-
const frameInfo = {
1598-
id: frame.id,
1599-
name: frame.name,
1600-
type: frame.type,
1601-
width: frame.width,
1602-
height: frame.height,
1603-
x: frame.x,
1604-
y: frame.y,
1605-
reusable: frame.reusable,
1606-
sourceFile: penFilePath,
1607-
renderedAt: new Date().toISOString(),
1608-
renderer: 'metadata',
1609-
};
1610-
// Ensure output directory exists
1611-
const outputDir = path.dirname(placeholderPath);
1612-
if (!fs.existsSync(outputDir)) {
1613-
fs.mkdirSync(outputDir, { recursive: true });
1614-
}
1615-
fs.writeFileSync(placeholderPath, JSON.stringify(frameInfo, null, 2));
1616-
return (0, base_1.createSuccessResult)(frame, penFilePath, placeholderPath);
1617-
}
1618-
catch (error) {
1619-
return {
1620-
frameId: frame.id,
1621-
frameName: frame.name,
1622-
filePath: penFilePath,
1623-
screenshotPath: '',
1624-
success: false,
1625-
error: error instanceof Error ? error.message : 'Unknown error',
1626-
};
1627-
}
1628-
}
1629-
async cleanup() {
1630-
// Nothing to clean up for metadata renderer
1631-
}
1632-
}
1633-
exports.MetadataRenderer = MetadataRenderer;
1634-
//# sourceMappingURL=metadata.js.map
1635-
1636-
/***/ }),
1637-
16381528
/***/ 35300:
16391529
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
16401530

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)