lula2 0.6.3-nightly.0 → 0.6.3-nightly.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -123,155 +123,209 @@ function containsLulaAnnotations(text) {
123
123
  const lines = text.split("\n");
124
124
  return lines.some((line) => line.includes("@lulaStart") || line.includes("@lulaEnd"));
125
125
  }
126
- function crawlCommand() {
127
- return new Command().command("crawl").description("Detect compliance-related changes between @lulaStart and @lulaEnd in PR files").addOption(
128
- new Option("--post-mode <mode>", "How to post findings").choices(["review", "comment"]).default("review")
129
- ).action(async (opts) => {
130
- let leavePost = false;
131
- const { owner, repo, pull_number } = getPRContext();
132
- console.log(`Analyzing PR #${pull_number} in ${owner}/${repo} for compliance changes...`);
133
- const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
134
- const pr = await octokit.pulls.get({ owner, repo, pull_number });
135
- const prBranch = pr.data.head.ref;
136
- const { data: files } = await octokit.pulls.listFiles({ owner, repo, pull_number });
137
- let commentBody = `${LULA_SIGNATURE}
126
+ function createInitialCommentBody(filesCount) {
127
+ return `${LULA_SIGNATURE}
138
128
  ## Lula Compliance Overview
139
129
 
140
130
  Please review the changes to ensure they meet compliance standards.
141
131
 
142
132
  ### Reviewed Changes
143
133
 
144
- Lula reviewed ${files.length} files changed that affect compliance.
134
+ Lula reviewed ${filesCount} files changed that affect compliance.
145
135
 
146
136
  `;
147
- const deletedFilesWithAnnotations = [];
148
- for (const file of files) {
149
- if (file.status === "removed") {
150
- try {
151
- const oldText = await fetchRawFileViaAPI({
152
- octokit,
153
- owner,
154
- repo,
155
- path: file.filename,
156
- ref: "main"
157
- });
158
- if (containsLulaAnnotations(oldText)) {
159
- deletedFilesWithAnnotations.push(file.filename);
160
- }
161
- } catch (err) {
162
- console.error(`Error checking deleted file ${file.filename}: ${err}`);
137
+ }
138
+ async function analyzeDeletedFiles(context) {
139
+ const { octokit, owner, repo, files } = context;
140
+ const deletedFilesWithAnnotations = [];
141
+ for (const file of files) {
142
+ if (file.status === "removed") {
143
+ try {
144
+ const oldText = await fetchRawFileViaAPI({
145
+ octokit,
146
+ owner,
147
+ repo,
148
+ path: file.filename,
149
+ ref: "main"
150
+ });
151
+ if (containsLulaAnnotations(oldText)) {
152
+ deletedFilesWithAnnotations.push(file.filename);
163
153
  }
154
+ } catch (err) {
155
+ console.error(`Error checking deleted file ${file.filename}: ${err}`);
164
156
  }
165
157
  }
166
- if (deletedFilesWithAnnotations.length > 0) {
167
- leavePost = true;
168
- commentBody += `
158
+ }
159
+ if (deletedFilesWithAnnotations.length === 0) {
160
+ return { hasFindings: false, warningContent: "" };
161
+ }
162
+ let warningContent = `
169
163
 
170
164
  **Compliance Warning: Files with Lula annotations were deleted**
171
165
 
172
166
  `;
173
- commentBody += `The following files contained compliance annotations (\`@lulaStart\`/\`@lulaEnd\`) and were deleted in this PR. This may affect compliance coverage:
167
+ warningContent += `The following files contained compliance annotations (\`@lulaStart\`/\`@lulaEnd\`) and were deleted in this PR. This may affect compliance coverage:
174
168
 
175
169
  `;
176
- for (const filename of deletedFilesWithAnnotations) {
177
- commentBody += `- \`${filename}\`
170
+ for (const filename of deletedFilesWithAnnotations) {
171
+ warningContent += `- \`${filename}\`
178
172
  `;
179
- }
180
- commentBody += `
173
+ }
174
+ warningContent += `
181
175
  Please review whether:
182
176
  `;
183
- commentBody += `- The compliance coverage provided by these files is still needed
177
+ warningContent += `- The compliance coverage provided by these files is still needed
184
178
  `;
185
- commentBody += `- Alternative compliance measures have been implemented
179
+ warningContent += `- Alternative compliance measures have been implemented
186
180
  `;
187
- commentBody += `- The deletion is intentional and compliance-approved
181
+ warningContent += `- The deletion is intentional and compliance-approved
188
182
 
189
183
  `;
190
- commentBody += `---
184
+ warningContent += `---
191
185
 
192
186
  `;
193
- }
194
- for (const file of files) {
195
- if (file.status === "added" || file.status === "removed") continue;
196
- try {
197
- const [oldText, newText] = await Promise.all([
198
- fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: "main" }),
199
- fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: prBranch })
200
- ]);
201
- const changedBlocks = getChangedBlocks(oldText, newText);
202
- const removedBlocks = getRemovedBlocks(oldText, newText);
203
- for (const block of changedBlocks) {
204
- console.log(`Commenting regarding \`${file.filename}\`.`);
205
- leavePost = true;
206
- commentBody += `
187
+ return { hasFindings: true, warningContent };
188
+ }
189
+ function generateChangedBlocksContent(filename, changedBlocks, newText) {
190
+ let content = "";
191
+ for (const block of changedBlocks) {
192
+ console.log(`Commenting regarding \`${filename}\`.`);
193
+ content += `
207
194
 
208
195
  ---
209
196
  | File | Lines Changed |
210
197
  | ---- | ------------- |
211
198
  `;
212
- const newBlockText = newText.split("\n").slice(block.startLine, block.endLine).join("\n");
213
- const blockSha256 = createHash("sha256").update(newBlockText).digest("hex");
214
- commentBody += `| \`${file.filename}\` | \`${block.startLine + 1}\u2013${block.endLine}\` |
199
+ const newBlockText = newText.split("\n").slice(block.startLine, block.endLine).join("\n");
200
+ const blockSha256 = createHash("sha256").update(newBlockText).digest("hex");
201
+ content += `| \`${filename}\` | \`${block.startLine + 1}\u2013${block.endLine}\` |
215
202
  > **uuid**-\`${block.uuid}\`
216
203
  **sha256** \`${blockSha256}\`
217
204
 
218
205
  `;
219
- }
220
- if (removedBlocks.length > 0) {
221
- leavePost = true;
222
- console.log(`Found removed annotations in \`${file.filename}\`.`);
223
- commentBody += `
206
+ }
207
+ return content;
208
+ }
209
+ function generateRemovedBlocksContent(filename, removedBlocks, oldText) {
210
+ if (removedBlocks.length === 0) {
211
+ return "";
212
+ }
213
+ console.log(`Found removed annotations in \`${filename}\`.`);
214
+ let content = `
224
215
 
225
- **Compliance Warning: Lula annotations were removed from \`${file.filename}\`**
216
+ **Compliance Warning: Lula annotations were removed from \`${filename}\`**
226
217
 
227
218
  `;
228
- commentBody += `The following compliance annotation blocks were present in the original file but are missing in the updated version:
219
+ content += `The following compliance annotation blocks were present in the original file but are missing in the updated version:
229
220
 
230
221
  `;
231
- commentBody += `| File | Original Lines | UUID |
222
+ content += `| File | Original Lines | UUID |
232
223
  `;
233
- commentBody += `| ---- | -------------- | ---- |
224
+ content += `| ---- | -------------- | ---- |
234
225
  `;
235
- for (const block of removedBlocks) {
236
- const oldBlockText = oldText.split("\n").slice(block.startLine, block.endLine).join("\n");
237
- const blockSha256 = createHash("sha256").update(oldBlockText).digest("hex");
238
- commentBody += `| \`${file.filename}\` | \`${block.startLine + 1}\u2013${block.endLine}\` | \`${block.uuid}\` |
226
+ for (const block of removedBlocks) {
227
+ const oldBlockText = oldText.split("\n").slice(block.startLine, block.endLine).join("\n");
228
+ const blockSha256 = createHash("sha256").update(oldBlockText).digest("hex");
229
+ content += `| \`${filename}\` | \`${block.startLine + 1}\u2013${block.endLine}\` | \`${block.uuid}\` |
239
230
  `;
240
- commentBody += `> **sha256** \`${blockSha256}\`
231
+ content += `> **sha256** \`${blockSha256}\`
241
232
 
242
233
  `;
243
- }
244
- commentBody += `Please review whether:
234
+ }
235
+ content += `Please review whether:
245
236
  `;
246
- commentBody += `- The removal of these compliance annotations is intentional
237
+ content += `- The removal of these compliance annotations is intentional
247
238
  `;
248
- commentBody += `- Alternative compliance measures have been implemented
239
+ content += `- Alternative compliance measures have been implemented
249
240
  `;
250
- commentBody += `- The compliance coverage is still adequate
241
+ content += `- The compliance coverage is still adequate
251
242
 
252
243
  `;
253
- commentBody += `---
244
+ content += `---
254
245
 
255
246
  `;
256
- }
257
- } catch (err) {
258
- console.error(`Error processing ${file.filename}: ${err}`);
247
+ return content;
248
+ }
249
+ async function analyzeModifiedFiles(context) {
250
+ const { octokit, owner, repo, prBranch, files } = context;
251
+ let changesContent = "";
252
+ let hasFindings = false;
253
+ for (const file of files) {
254
+ if (file.status === "added" || file.status === "removed") continue;
255
+ try {
256
+ const [oldText, newText] = await Promise.all([
257
+ fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: "main" }),
258
+ fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: prBranch })
259
+ ]);
260
+ const changedBlocks = getChangedBlocks(oldText, newText);
261
+ const removedBlocks = getRemovedBlocks(oldText, newText);
262
+ if (changedBlocks.length > 0) {
263
+ hasFindings = true;
264
+ changesContent += generateChangedBlocksContent(file.filename, changedBlocks, newText);
259
265
  }
266
+ if (removedBlocks.length > 0) {
267
+ hasFindings = true;
268
+ changesContent += generateRemovedBlocksContent(file.filename, removedBlocks, oldText);
269
+ }
270
+ } catch (err) {
271
+ console.error(`Error processing ${file.filename}: ${err}`);
260
272
  }
261
- if (opts.postMode === "comment") {
262
- await deleteOldIssueComments({ octokit, owner, repo, pull_number });
263
- } else {
264
- await dismissOldReviews({ octokit, owner, repo, pull_number });
265
- await deleteOldReviewComments({ octokit, owner, repo, pull_number });
266
- }
267
- if (leavePost) {
273
+ }
274
+ return { hasFindings, changesContent };
275
+ }
276
+ async function performComplianceAnalysis(context) {
277
+ let commentBody = createInitialCommentBody(context.files.length);
278
+ let hasFindings = false;
279
+ const deletedAnalysis = await analyzeDeletedFiles(context);
280
+ if (deletedAnalysis.hasFindings) {
281
+ hasFindings = true;
282
+ commentBody += deletedAnalysis.warningContent;
283
+ }
284
+ const modifiedAnalysis = await analyzeModifiedFiles(context);
285
+ if (modifiedAnalysis.hasFindings) {
286
+ hasFindings = true;
287
+ commentBody += modifiedAnalysis.changesContent;
288
+ }
289
+ return { hasFindings, commentBody };
290
+ }
291
+ async function cleanupOldPosts(context, postMode) {
292
+ const { octokit, owner, repo, pull_number } = context;
293
+ if (postMode === "comment") {
294
+ await deleteOldIssueComments({ octokit, owner, repo, pull_number });
295
+ } else {
296
+ await dismissOldReviews({ octokit, owner, repo, pull_number });
297
+ await deleteOldReviewComments({ octokit, owner, repo, pull_number });
298
+ }
299
+ }
300
+ function crawlCommand() {
301
+ return new Command().command("crawl").description("Detect compliance-related changes between @lulaStart and @lulaEnd in PR files").addOption(
302
+ new Option("--post-mode <mode>", "How to post findings").choices(["review", "comment"]).default("review")
303
+ ).action(async (opts) => {
304
+ const { owner, repo, pull_number } = getPRContext();
305
+ console.log(`Analyzing PR #${pull_number} in ${owner}/${repo} for compliance changes...`);
306
+ const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
307
+ const pr = await octokit.pulls.get({ owner, repo, pull_number });
308
+ const prBranch = pr.data.head.ref;
309
+ const { data: files } = await octokit.pulls.listFiles({ owner, repo, pull_number });
310
+ const context = {
311
+ octokit,
312
+ owner,
313
+ repo,
314
+ pull_number,
315
+ prBranch,
316
+ files
317
+ };
318
+ const analysisResult = await performComplianceAnalysis(context);
319
+ await cleanupOldPosts(context, opts.postMode);
320
+ if (analysisResult.hasFindings) {
321
+ const finalBody = analysisResult.commentBody + closingBody;
268
322
  await postFinding({
269
323
  octokit,
270
324
  postMode: opts.postMode,
271
325
  owner,
272
326
  repo,
273
327
  pull_number,
274
- body: commentBody + closingBody
328
+ body: finalBody
275
329
  });
276
330
  const header = `Posted (${opts.postMode})`;
277
331
  const underline = "-".repeat(header.length);
@@ -279,7 +333,7 @@ Please review whether:
279
333
  ${header}
280
334
  ${underline}
281
335
 
282
- ${commentBody + closingBody}
336
+ ${finalBody}
283
337
 
284
338
  `);
285
339
  }
@@ -372,15 +426,22 @@ async function dismissOldReviews({
372
426
  }
373
427
  export {
374
428
  LULA_SIGNATURE,
429
+ analyzeDeletedFiles,
430
+ analyzeModifiedFiles,
431
+ cleanupOldPosts,
375
432
  containsLulaAnnotations,
376
433
  crawlCommand,
434
+ createInitialCommentBody,
377
435
  deleteOldIssueComments,
378
436
  deleteOldReviewComments,
379
437
  dismissOldReviews,
380
438
  extractMapBlocks,
381
439
  fetchRawFileViaAPI,
440
+ generateChangedBlocksContent,
441
+ generateRemovedBlocksContent,
382
442
  getChangedBlocks,
383
443
  getPRContext,
384
444
  getRemovedBlocks,
445
+ performComplianceAnalysis,
385
446
  postFinding
386
447
  };
package/dist/index.html CHANGED
@@ -6,28 +6,28 @@
6
6
  <link rel="icon" href="/lula.png" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1" />
8
8
 
9
- <link rel="modulepreload" href="/_app/immutable/entry/start.D2hMBZNv.js">
10
- <link rel="modulepreload" href="/_app/immutable/chunks/rc9CiIba.js">
11
- <link rel="modulepreload" href="/_app/immutable/chunks/DTWPdvjs.js">
12
- <link rel="modulepreload" href="/_app/immutable/entry/app.C9fkwjMz.js">
9
+ <link rel="modulepreload" href="/_app/immutable/entry/start.DWsnY-61.js">
10
+ <link rel="modulepreload" href="/_app/immutable/chunks/D74fr9ax.js">
11
+ <link rel="modulepreload" href="/_app/immutable/chunks/DmBJsPtc.js">
12
+ <link rel="modulepreload" href="/_app/immutable/entry/app.CY89YrVW.js">
13
13
  <link rel="modulepreload" href="/_app/immutable/chunks/DsnmJJEf.js">
14
- <link rel="modulepreload" href="/_app/immutable/chunks/BXUi170M.js">
15
- <link rel="modulepreload" href="/_app/immutable/chunks/WlyXjfrM.js">
16
- <link rel="modulepreload" href="/_app/immutable/chunks/CRa0j_Fx.js">
14
+ <link rel="modulepreload" href="/_app/immutable/chunks/BaV6jU6m.js">
15
+ <link rel="modulepreload" href="/_app/immutable/chunks/DBdrJbLi.js">
16
+ <link rel="modulepreload" href="/_app/immutable/chunks/CynYS-Ma.js">
17
17
  </head>
18
18
  <body data-sveltekit-preload-data="hover">
19
19
  <div style="display: contents">
20
20
  <script>
21
21
  {
22
- __sveltekit_1jux1ml = {
22
+ __sveltekit_1iek8ky = {
23
23
  base: ""
24
24
  };
25
25
 
26
26
  const element = document.currentScript.parentElement;
27
27
 
28
28
  Promise.all([
29
- import("/_app/immutable/entry/start.D2hMBZNv.js"),
30
- import("/_app/immutable/entry/app.C9fkwjMz.js")
29
+ import("/_app/immutable/entry/start.DWsnY-61.js"),
30
+ import("/_app/immutable/entry/app.CY89YrVW.js")
31
31
  ]).then(([kit, app]) => {
32
32
  kit.start(app, element);
33
33
  });