@docupace/pipeline 1.0.105 → 1.0.106

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docupace/pipeline",
3
- "version": "1.0.105",
3
+ "version": "1.0.106",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -16,50 +16,83 @@ export async function uploadToCanny(releaseNote, labelIDs) {
16
16
  }
17
17
 
18
18
  try {
19
- // Prepare the content for Canny based on the release notes
20
19
  const title = releaseNote.title;
21
20
  let content = '';
21
+ let entryType;
22
22
 
23
- // Include user-facing description if available
24
- if (
25
- releaseNote.userFacingDescription &&
26
- releaseNote.userFacingDescription.__line.trim()
27
- ) {
28
- content += `${releaseNote.summary}\n\n`;
29
- content += `${releaseNote.userFacingDescription.__line}\n\n`;
30
- } else {
23
+ if (Array.isArray(releaseNote.whatsNew)) {
24
+ // New format
31
25
  content += `${releaseNote.summary}\n\n`;
32
- }
33
-
34
- // Include technical details if available
35
- if (
36
- releaseNote.technicalDescription &&
37
- releaseNote.technicalDescription.__line.trim()
38
- ) {
39
- content += `**Technical Details**\n\n${releaseNote.technicalDescription.__line}\n\n`;
40
- }
41
-
42
- // Add JIRA reference
43
- content += `**Reference**: JIRA ticket [${releaseNote.ticketId}]`;
44
26
 
45
- // Map our changeType to Canny's type parameter
46
- let entryType;
47
- if (releaseNote.changeType === 'New') {
48
- entryType = 'new';
49
- } else if (releaseNote.changeType === 'Improved') {
50
- entryType = 'improved';
51
- } else if (releaseNote.changeType === 'Fixed') {
52
- entryType = 'fixed';
27
+ content += `**What's New**\n\n`;
28
+ releaseNote.whatsNew.forEach((item) => (content += `- ${item}\n`));
29
+ content += '\n';
30
+
31
+ content += `**Why This Matters**\n\n${releaseNote.whyThisMatters}\n\n`;
32
+
33
+ if (releaseNote.whoIsImpacted?.length) {
34
+ content += `**Who Is Impacted**\n\n`;
35
+ releaseNote.whoIsImpacted.forEach((item) => (content += `- ${item}\n`));
36
+ content += '\n';
37
+ }
38
+
39
+ if (releaseNote.actionRequired?.length) {
40
+ content += `**Action Required**\n\n`;
41
+ releaseNote.actionRequired.forEach(
42
+ (item) => (content += `- ${item}\n`),
43
+ );
44
+ content += '\n';
45
+ }
46
+
47
+ if (releaseNote.technicalDetails?.length) {
48
+ content += `**Technical Details**\n\n`;
49
+ releaseNote.technicalDetails.forEach(
50
+ (item) => (content += `- ${item}\n`),
51
+ );
52
+ }
53
+ } else {
54
+ // Old format (backwards compatibility)
55
+ if (
56
+ releaseNote.userFacingDescription &&
57
+ releaseNote.userFacingDescription.__line?.trim()
58
+ ) {
59
+ content += `${releaseNote.summary}\n\n`;
60
+ content += `${releaseNote.userFacingDescription.__line}\n\n`;
61
+ } else {
62
+ content += `${releaseNote.summary}\n\n`;
63
+ }
64
+
65
+ if (
66
+ releaseNote.technicalDescription &&
67
+ releaseNote.technicalDescription.__line?.trim()
68
+ ) {
69
+ content += `**Technical Details**\n\n${releaseNote.technicalDescription.__line}\n\n`;
70
+ }
71
+
72
+ content += `**Reference**: JIRA ticket [${releaseNote.ticketId}]`;
73
+
74
+ if (releaseNote.changeType === 'New') {
75
+ entryType = 'new';
76
+ } else if (releaseNote.changeType === 'Improved') {
77
+ entryType = 'improved';
78
+ } else if (releaseNote.changeType === 'Fixed') {
79
+ entryType = 'fixed';
80
+ }
53
81
  }
54
82
 
55
- const body = JSON.stringify({
83
+ const bodyPayload = {
56
84
  apiKey: CANNY_API_KEY,
57
85
  title: title,
58
86
  details: content,
59
- type: entryType,
60
87
  published: false, // Keep as draft initially
61
88
  labelIDs,
62
- });
89
+ };
90
+
91
+ if (entryType) {
92
+ bodyPayload.type = entryType;
93
+ }
94
+
95
+ const body = JSON.stringify(bodyPayload);
63
96
 
64
97
  // Create a new changelog entry in Canny
65
98
  const createResponse = await fetch(
@@ -196,12 +196,12 @@ program
196
196
  });
197
197
 
198
198
  program
199
- .name('create-changeset')
199
+ .command('create-changeset [jiraTicketKey]')
200
200
  .description(
201
201
  'Creates a changeset based on the current branch and Jira ticket information',
202
202
  )
203
- .action(async () => {
204
- await createChangeset();
203
+ .action(async (jiraTicketKey) => {
204
+ await createChangeset(jiraTicketKey);
205
205
  });
206
206
 
207
207
  // Command: convert-prepare
@@ -21,27 +21,20 @@ const CHANGESET_DIR = path.join(process.cwd(), '.release-notes');
21
21
 
22
22
  // Define the Zod schema for OpenAI response
23
23
  const openAiResponseSchema = z.object({
24
- title: z
25
- .string()
26
- .describe('A concise title for the release note (3-8 words)'),
27
- summary: z.string().describe('A brief user-facing summary of changes'),
28
- technicalDescription: z
29
- .string()
30
- .optional()
31
- .describe('Developer-friendly description of technical changes'),
32
- userFacingDescription: z
33
- .string()
34
- .optional()
35
- .describe('Plain-language description of changes from a user perspective'),
36
- technicalOnly: z
37
- .boolean()
38
- .describe(
39
- 'Whether this change is technical-only with no user-visible impact',
40
- ),
41
- changeSize: z
42
- .enum(['Small', 'Medium', 'Large'])
43
- .describe('Size/scope of the change'),
44
- changeType: z.enum(['New', 'Improved', 'Fixed']).describe('Type of change'),
24
+ title: z.string().describe('Title with [Audience] prefix'),
25
+ summary: z.string().describe('1-2 sentence executive summary'),
26
+ whatsNew: z
27
+ .array(z.string())
28
+ .describe('Flat bullets of user-visible behavior'),
29
+ whyThisMatters: z.string().describe('1-3 sentences on practical impact'),
30
+ whoIsImpacted: z.array(z.string()).describe('Audience bullets'),
31
+ actionRequired: z
32
+ .array(z.string())
33
+ .describe('Action bullets or ["No action required."]'),
34
+ technicalDetails: z
35
+ .array(z.string())
36
+ .describe('Technical detail bullets ending with Reference'),
37
+ tags: z.array(z.string()).describe('Approved tags'),
45
38
  });
46
39
 
47
40
  // Define the Zod schema for changelog summary
@@ -332,31 +325,67 @@ export async function generateEnhancedReleaseNotes(ticketData) {
332
325
  if (!ticketData) return null;
333
326
 
334
327
  try {
335
- const systemPrompt = `Process the provided JSON from a Jira ticket to generate structured release notes in JSON format.
336
- Follow this strict schema to generate your response:
328
+ const systemPrompt = `
329
+ Generate client-facing release notes in JSON from the provided Jira ticket JSON.
330
+
331
+ Return ONLY valid JSON matching this schema exactly (no extra keys):
337
332
 
338
333
  {
339
- "title": "A concise title for the release note (3-8 words)",
340
- "summary": "A brief user-facing summary of changes (max 2 sentences)",
341
- "technicalDescription": "Developer-friendly description of technical changes in markdown format (max 5 sentences)",
342
- "userFacingDescription": "Provide only if changes made to user interface. Plain-language description of changes from a user perspective in markdown format (max 5 sentences)",
343
- "technicalOnly": boolean (true/false whether this change is only technical with no user-visible impact),
344
- "changeType": "New" | "Improved" | "Fixed",
345
- "changeSize": "Small" | "Medium" | "Large"
334
+ “title”: “[Audience] Concise, Title-Case Summary”,
335
+ “summary”: “1–2 sentences.”,
336
+ “whatsNew”: [“Flat bullet”],
337
+ “whyThisMatters”: “1–3 sentences.”,
338
+ “whoIsImpacted”: [“Flat bullet or 'All users'”],
339
+ “actionRequired”: [“Flat bullet or exactly 'No action required.'”],
340
+ “technicalDetails”: [“Flat bullet”, “Reference: ABC-1234”],
341
+ “tags”: [“ApprovedTag”]
346
342
  }
347
343
 
348
- When creating your response:
349
- - Title: Create a concise title summarizing the change (3–8 words). Avoid repeating the Jira ticket title.
350
- - Summary: Write a maximum two-sentence summary in user-facing language.
351
- - Technical Description: Use developer-friendly language to explain what changed at the system or code level. Include only if specified: API impacts, architectural changes, or deployment considerations. Format using markdown. Use backticks for code (\`like_this\`), bold for important terms, and line breaks for readability. Avoid headings like Technical Changes
352
- - User-Facing Description: Provide only if changes are made to the user interface. Use plain language to explain what users will see or benefit from. Include affected UI elements, workflows, or systems. Prefer bullet points if listing multiple effects or changes. Use markdown formatting for clarity.
353
- - Technical Only: Set to true if the change has no visible effect to end users. Examples for technical only are API changes, refactoring of code or architectual changes that do not have changes to the user interface
354
- - Change Type: Classify as “New”, “Improved”, or “Fixed”.
355
- - Change Size: Estimate the impact as “Small”, “Medium”, or “Large”.
356
-
357
- For Descriptions:
358
- Avoid large blocks of text. Break content into short paragraphs or lists. Use markdown consistently: code, bold, italic, and single level bullet lists (- Item). Make your response easy to scan, especially the descriptions. Focus on what changed, how it works, and where it applies.
359
- Avoid restating the ticket title. Focus on what changed, how it works, and where it applies.
344
+ ALL FIELDS ARE REQUIRED.
345
+
346
+ TITLE
347
+ - Must start with [Audience] where Audience is one of: All, Admins, Devs, Front Office, Back Office
348
+ - If the Jira explicitly states “all users”, use [All].
349
+
350
+ SUMMARY
351
+ - 1–2 sentences, present tense, executive-level, no speculation.
352
+
353
+ WHAT'S NEW
354
+ - Flat bullets only, present tense, user-visible behavior only.
355
+
356
+ WHY THIS MATTERS
357
+ - 1–3 sentences, practical impact directly inferable from What's New. Do not restate What's New.
358
+
359
+ WHO IS IMPACTED
360
+ - Must align with the Title audience. Use “All users” if broadly applicable.
361
+
362
+ ACTION REQUIRED
363
+ - Flat bullets only.
364
+ - If none: [“No action required.”] exactly.
365
+ - If separate deployment/enablement/manual activation is mentioned, include a customer-facing action bullet.
366
+
367
+ TECHNICAL DETAILS
368
+ - Flat bullets only.
369
+ - Describe the functional change with concrete specificity (behavioral change, validation logic, configuration impact, or integration touchpoints).
370
+ - Do not include internal architecture, endpoints, schemas, environments, or internal tools.
371
+ - Final bullet MUST be: “Reference: <JIRA-KEY>” verbatim.
372
+
373
+ TAGS
374
+ Use only:
375
+ Technical, Enterprise Core, Account Opening, Admin Settings, APIs & Integrations, Authentication & SSO, Compliance & Disclosures, CRM Connections, Custodians, Documents & Uploads, eSignature, Form Fields & Validations, Performance & Speed, Security, System Configuration, User Experience, Workflows
376
+
377
+ FAILURE FLAGS (MANDATORY)
378
+ If any field can only be completed by guessing:
379
+ - Include what is supported by the Jira input and add as the final sentence (string fields) or final bullet (array fields):
380
+ “[PARTIAL — ADDITIONAL SOURCE DETAIL REQUIRED]”
381
+ If no reliable content can be produced for a field:
382
+ - For string fields set the value to:
383
+ “[UNABLE TO GENERATE — INSUFFICIENT SOURCE DETAIL]”
384
+ - For array fields set the value to:
385
+ [“[UNABLE TO GENERATE — INSUFFICIENT SOURCE DETAIL]”]
386
+
387
+ Use active voice. Short sentences. No marketing language.
388
+ Return JSON only.
360
389
  `;
361
390
 
362
391
  const userPrompt = JSON.stringify(ticketData, null, 2);
@@ -382,46 +411,51 @@ Avoid restating the ticket title. Focus on what changed, how it works, and where
382
411
  properties: {
383
412
  title: {
384
413
  type: 'string',
385
- description:
386
- 'A concise title for the release note (3-8 words)',
414
+ description: 'Title with [Audience] prefix',
387
415
  },
388
416
  summary: {
389
417
  type: 'string',
390
- description:
391
- 'A brief user-facing summary of changes (max 2 sentences)',
418
+ description: '1-2 sentence executive summary',
392
419
  },
393
- technicalDescription: {
394
- type: 'string',
395
- description:
396
- 'Developer-friendly description of technical changes (max 5 sentences)',
420
+ whatsNew: {
421
+ type: 'array',
422
+ items: { type: 'string' },
423
+ description: 'Flat bullets of user-visible behavior',
397
424
  },
398
- userFacingDescription: {
425
+ whyThisMatters: {
399
426
  type: 'string',
400
- description:
401
- 'Plain-language description of changes from a user perspective (max 5 sentences)',
427
+ description: '1-3 sentences on practical impact',
402
428
  },
403
- technicalOnly: {
404
- type: 'boolean',
405
- description:
406
- 'Whether this change is technical-only with no user-visible impact',
429
+ whoIsImpacted: {
430
+ type: 'array',
431
+ items: { type: 'string' },
432
+ description: 'Audience bullets',
407
433
  },
408
- changeSize: {
409
- type: 'string',
410
- enum: ['Small', 'Medium', 'Large'],
411
- description: 'Size/scope of the change',
434
+ actionRequired: {
435
+ type: 'array',
436
+ items: { type: 'string' },
437
+ description: 'Action bullets or ["No action required."]',
412
438
  },
413
- changeType: {
414
- type: 'string',
415
- enum: ['New', 'Improved', 'Fixed'],
416
- description: 'Type of change',
439
+ technicalDetails: {
440
+ type: 'array',
441
+ items: { type: 'string' },
442
+ description: 'Technical detail bullets ending with Reference',
443
+ },
444
+ tags: {
445
+ type: 'array',
446
+ items: { type: 'string' },
447
+ description: 'Approved tags',
417
448
  },
418
449
  },
419
450
  required: [
420
451
  'title',
421
452
  'summary',
422
- 'technicalOnly',
423
- 'changeSize',
424
- 'changeType',
453
+ 'whatsNew',
454
+ 'whyThisMatters',
455
+ 'whoIsImpacted',
456
+ 'actionRequired',
457
+ 'technicalDetails',
458
+ 'tags',
425
459
  ],
426
460
  additionalProperties: false,
427
461
  },
@@ -464,52 +498,20 @@ export async function writeYamlFile(mainTicketId, enhancedNotes) {
464
498
  ticketId: mainTicketId,
465
499
  title: enhancedNotes.title,
466
500
  summary: enhancedNotes.summary,
467
- technicalDescription: {
468
- __line: enhancedNotes.technicalDescription,
469
- },
470
- userFacingDescription: {
471
- __line: enhancedNotes.userFacingDescription,
472
- },
473
- technicalOnly: enhancedNotes.technicalOnly,
474
- changeSize: enhancedNotes.changeSize,
475
- changeType: enhancedNotes.changeType,
501
+ whatsNew: enhancedNotes.whatsNew,
502
+ whyThisMatters: enhancedNotes.whyThisMatters,
503
+ whoIsImpacted: enhancedNotes.whoIsImpacted,
504
+ actionRequired: enhancedNotes.actionRequired,
505
+ technicalDetails: enhancedNotes.technicalDetails,
506
+ tags: enhancedNotes.tags,
476
507
  },
477
508
  {
478
509
  lineWidth: -1, // Don't wrap lines
479
510
  noRefs: true,
480
- schema: yaml.DEFAULT_SCHEMA.extend({
481
- implicit: [
482
- new yaml.Type('tag:yaml.org,2002:str', {
483
- kind: 'scalar',
484
- instanceOf: Object,
485
- resolve: function (object) {
486
- return object !== null && object['__line'];
487
- },
488
- predicate: function (object) {
489
- return object['__line'];
490
- },
491
- construct: function (object) {
492
- return object.__line;
493
- },
494
- represent: function (object) {
495
- return { __line: object.__line };
496
- },
497
- }),
498
- ],
499
- }),
500
511
  },
501
512
  );
502
513
 
503
- // Replace the problematic YAML output with properly formatted literal block scalars
504
- const fixedYaml = yamlContent
505
- .replace(/technicalDescription: '?(.*?)'?$/m, () => {
506
- return `technicalDescription: |\n ${enhancedNotes.technicalDescription.replace(/\n/g, '\n ')}`;
507
- })
508
- .replace(/userFacingDescription: '?(.*?)'?$/m, () => {
509
- return `userFacingDescription: |\n ${enhancedNotes.userFacingDescription.replace(/\n/g, '\n ')}`;
510
- });
511
-
512
- fs.writeFileSync(yamlFilePath, fixedYaml, 'utf8');
514
+ fs.writeFileSync(yamlFilePath, yamlContent, 'utf8');
513
515
  }
514
516
 
515
517
  export async function getReleaseNotes(ticketId) {