@docupace/pipeline 1.0.39-matttest.22 → 1.0.39-matttest.24

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.39-matttest.22",
3
+ "version": "1.0.39-matttest.24",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -23,6 +23,7 @@
23
23
  "commander": "^12.1.0",
24
24
  "dotenv": "^16.4.7",
25
25
  "fs-extra": "^11.3.0",
26
+ "inquirer": "^12.6.1",
26
27
  "js-yaml": "^4.1.0",
27
28
  "lodash": "^4.17.21",
28
29
  "openai": "^4.76.3",
@@ -42,6 +43,7 @@
42
43
  "test-deploy-core": "dp-next-cli deploy-core-pipeline dev template",
43
44
  "test-deploy-from-site": "dp-next-cli deploy-from-site --from-env dev --to-env dev --from-site financialdev --to-site template --deploy-core true",
44
45
  "test-run-pipline": "dp-next-cli run-pipeline -r docupace-next-e2e -b master -p run-tests-qa",
45
- "test-validate": "dp-changset-cli validate"
46
+ "test-validate": "dp-changset-cli validate",
47
+ "test-create": "dp-changset-cli create-changeset"
46
48
  }
47
49
  }
@@ -1,146 +1,72 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
3
  import { $ } from 'zx';
4
- import path from 'path';
5
4
  import { validateChangesets } from './validate.js';
6
- import fs from 'fs';
7
- import OpenAI from 'openai';
8
- import { zodResponseFormat } from 'openai/helpers/zod';
9
- import z from 'zod';
10
5
  import dotenv from 'dotenv';
11
- import { makeJiraRequest, updateComponentVersion } from '../next/jira.js';
6
+ import { getChangedAppPackages, isMonoRepo, setGitInfo } from '../next/util.js';
7
+ import { updateJiraWithVersion, versionCommand } from './version.js';
8
+ import { createChangeset } from './create.js';
9
+ import { getPackage } from './util.js';
10
+
12
11
  dotenv.config({ path: ['.env.pipeline.local', 'config/.env.pipeline.local'] });
13
- import { setGitInfo } from '../next/util.js';
14
12
 
15
13
  const program = new Command();
16
14
 
17
15
  const args = process.argv;
18
16
 
19
- async function createChangesetDirectory() {
20
- try {
21
- // Use path.join to build a safe path to `.changeset`
22
- const targetDir = path.join(process.cwd(), '.changeset');
17
+ async function commitTagCommand(releases) {
18
+ console.log('📌 Checking for updates to commit...');
23
19
 
24
- // Create the directory recursively if it doesn't exist
25
- await fs.promises.mkdir(targetDir, { recursive: true });
26
- } catch (error) {
27
- console.error('Error creating .changeset directory:', error);
20
+ // Check if there are changes to commit
21
+ const status = (await $`git status --porcelain`).stdout.trim();
22
+ if (!status) {
23
+ console.log('✅ No changes to commit. Exiting.');
24
+ return;
28
25
  }
29
- }
30
-
31
- function run(command) {
32
- return new Promise((resolve, reject) => {
33
- exec(command, { shell: true }, (error, stdout, stderr) => {
34
- if (error) {
35
- reject(error);
36
- } else {
37
- resolve({ stdout, stderr });
38
- }
39
- });
40
- });
41
- }
42
26
 
43
- async function fileExists(filePath) {
44
- try {
45
- await fs.promises.access(filePath);
46
- return true;
47
- } catch {
48
- return false;
49
- }
50
- }
27
+ console.log('📌 Committing and tagging the new version...');
28
+ await setGitInfo();
29
+ await $`git add .`;
51
30
 
52
- async function getMainPackage() {
53
- const mainModulePath = process.cwd();
54
- if (mainModulePath) {
55
- const packageJsonPath = path.join(mainModulePath, 'package.json');
56
- if (await fileExists(packageJsonPath)) {
57
- const fileContent = await fs.promises.readFile(packageJsonPath, 'utf-8');
58
- const packageJson = JSON.parse(fileContent);
59
- return packageJson;
60
- }
31
+ if (isMonoRepo()) {
32
+ await commitTagMono(releases);
33
+ } else {
34
+ await commitTag();
61
35
  }
62
- throw new Error('Main package.json not found');
63
36
  }
64
37
 
65
- const changeSetPackage = `{
66
- "name": "changeset-package",
67
- "version": "1.0.0",
68
- "description": "",
69
- "scripts": {
70
- },
71
- "type": "module",
72
- "keywords": [],
73
- "author": "",
74
- "license": "ISC",
75
- "dependencies": {},
76
- "devDependencies": {
77
- "@changesets/cli": "^2.27.10"
78
- }
38
+ export function getAppReleases(releases) {
39
+ const appReleases = releases.filter((release) =>
40
+ release.name.endsWith('-app'),
41
+ );
42
+ return appReleases;
79
43
  }
80
- `;
81
-
82
- async function versionCommand(closeVersion = false) {
83
- console.log('📦 Running Changeset versioning...');
84
- await setGitInfo();
85
- await $`mv package.json package.json.bak`;
86
- await $`mv pnpm-lock.yaml pnpm-lock.yaml.bak`;
87
- await fs.promises.writeFile('package.json', changeSetPackage);
88
- await $`pnpm install`;
89
- await $`rm package.json pnpm-lock.yaml`;
90
- await $`mv package.json.bak package.json`;
91
- await $`mv pnpm-lock.yaml.bak pnpm-lock.yaml`;
92
- if (closeVersion) {
93
- await $`pnpm changeset pre exit`;
94
- }
95
44
 
96
- await $`pnpm changeset version`;
45
+ function getAppNameFromPackageName(packageName) {
46
+ const appName = packageName.includes('/')
47
+ ? packageName.split('/')[1]
48
+ : packageName;
97
49
 
98
- // Read the updated package.json to get the new version and package name
99
- const packageJson = JSON.parse(
100
- await fs.promises.readFile('package.json', 'utf-8'),
101
- );
102
- const version = packageJson.version;
103
- const packageName = packageJson.name;
50
+ return appName;
51
+ }
104
52
 
105
- if (closeVersion) {
106
- return { version, packageName };
53
+ async function commitTagMono(releases) {
54
+ let versions = [];
55
+ for (const release of getAppReleases(releases)) {
56
+ const newVersion = release.newVersion;
57
+ const appName = getAppNameFromPackageName(release.name);
58
+ versions.push(`${appName}@${newVersion}`);
107
59
  }
108
-
109
- // Get the last commit message and extract Jira ticket
110
- const lastCommit = (await $`git log -1 --pretty=%B`).stdout.trim();
111
- console.log(`Last commit '${lastCommit}' being processed to get Jira ticket`);
112
-
113
- const jiraTicketMatch = lastCommit.match(/([A-Z]+-\d+)/);
114
- const jiraTicketId = jiraTicketMatch ? jiraTicketMatch[0] : null;
115
-
116
- // If we have all the necessary data, update the component version in Jira
117
- if (jiraTicketId && version && packageName) {
118
- try {
119
- await updateComponentVersion(jiraTicketId, packageName, version);
120
- } catch (error) {
121
- console.error(
122
- `Failed to update Jira component version: ${error.message}`,
123
- );
124
- }
60
+ await $`git commit -m "Version bump to ${versions.join(',')} and changelog"`;
61
+ for (const newVersion of versions) {
62
+ await $`git tag v${newVersion}`;
63
+ console.log(`✅ Version ${newVersion} tagged.`);
125
64
  }
126
-
127
- console.log('✅ Changeset versioning complete.');
128
- return { version, packageName };
65
+ await $`git push origin --tags`;
66
+ console.log(`✅ Version pushed.`);
129
67
  }
130
68
 
131
- async function commitTagCommand() {
132
- console.log('📌 Checking for updates to commit...');
133
-
134
- // Check if there are changes to commit
135
- const status = (await $`git status --porcelain`).stdout.trim();
136
- if (!status) {
137
- console.log('✅ No changes to commit. Exiting.');
138
- return;
139
- }
140
-
141
- console.log('📌 Committing and tagging the new version...');
142
- await setGitInfo();
143
- await $`git add .`;
69
+ async function commitTag() {
144
70
  const newVersion = (
145
71
  await $`node -p "require('./package.json').version"`
146
72
  ).stdout.trim();
@@ -163,7 +89,7 @@ program
163
89
  try {
164
90
  await validateChangesets();
165
91
  console.log('✅ Changeset validation passed.');
166
- } catch (error) {
92
+ } catch {
167
93
  console.error(
168
94
  '❌ No changeset found. Please add a changeset to this PR. Please see more information at https://docupacellc.atlassian.net/wiki/spaces/PM/pages/1350893571/Creating+changesets+for+Docupace+Next',
169
95
  );
@@ -192,8 +118,9 @@ program
192
118
  .description('Run versioning and commit-and-tag in sequence')
193
119
  .action(async () => {
194
120
  console.log('📦 Running all steps...');
195
- await versionCommand();
196
- await commitTagCommand();
121
+ const releases = await versionCommand();
122
+ await updateJiraWithVersion(releases);
123
+ await commitTagCommand(releases);
197
124
  });
198
125
 
199
126
  program
@@ -201,15 +128,21 @@ program
201
128
  .description('Closes a version')
202
129
  .action(async () => {
203
130
  console.log('📦 Running all steps...');
204
- const { version } = await versionCommand(true);
205
- await commitTagCommand();
131
+ const releases = await versionCommand(true);
132
+ await commitTagCommand(releases);
206
133
 
207
- // Get current branch
208
134
  const { stdout: currentBranch } = await $`git rev-parse --abbrev-ref HEAD`;
209
135
 
210
- // Create and push release branch
211
- await $`git checkout -b release/${version}`;
212
- await $`git push origin release/${version}`;
136
+ if (isMonoRepo()) {
137
+ for (const release of getAppReleases(releases)) {
138
+ const appName = getAppNameFromPackageName(release.name);
139
+ await $`git checkout -b release/${appName}/${release.newVersion}`;
140
+ await $`git push origin release/${appName}/${release.newVersion}`;
141
+ }
142
+ } else {
143
+ await $`git checkout -b release/${releases[0].newVersion}`;
144
+ await $`git push origin release/${releases[0].newVersion}`;
145
+ }
213
146
 
214
147
  // Return to original branch
215
148
  await $`git checkout ${currentBranch.trim()}`;
@@ -227,100 +160,7 @@ program
227
160
  'Creates a changeset based on the current branch and Jira ticket information',
228
161
  )
229
162
  .action(async () => {
230
- const mainPackage = await getMainPackage();
231
- const componentName = mainPackage.name;
232
-
233
- try {
234
- // Step 1: Get the current branch name
235
- const branchName = (await $`git branch --show-current`).stdout.trim();
236
- console.log(`Current branch: ${branchName}`);
237
-
238
- // Step 2: Extract Jira ticket number (e.g., matching JIRA-1234 pattern)
239
- const jiraTicketMatch = branchName.match(/([A-Z]+-\d+)/);
240
- if (!jiraTicketMatch) {
241
- throw new Error('No Jira ticket found in the branch name.');
242
- }
243
- const jiraTicketId = jiraTicketMatch[0];
244
-
245
- const jiraBaseUrl = 'https://docupacellc.atlassian.net';
246
- const jiraEmail = process.env.JIRA_API_EMAIL;
247
- const jiraApiKey = process.env.JIRA_API_KEY;
248
- const jiraFullApiKey = `${jiraEmail}:${jiraApiKey}`;
249
- const jiraUrl = `${jiraBaseUrl}/rest/api/2/issue/${jiraTicketId}`;
250
- const jiraResponse = await fetch(jiraUrl, {
251
- headers: {
252
- Authorization: `Basic ${Buffer.from(jiraFullApiKey).toString('base64')}`,
253
- 'Content-Type': 'application/json',
254
- },
255
- });
256
-
257
- if (!jiraResponse.ok) {
258
- throw new Error(
259
- `Failed to fetch Jira ticket. Status: ${jiraResponse.status}`,
260
- );
261
- }
262
- const jiraTicketData = await jiraResponse.json();
263
-
264
- const jiraSummary = jiraTicketData.fields.summary;
265
-
266
- console.log(
267
- `Generating release notes for ${jiraTicketId} - ${jiraSummary}`,
268
- );
269
-
270
- const openaiClient = new OpenAI({
271
- apiKey: process.env['OPENAI_API_KEY'],
272
- });
273
-
274
- const ChangeRequestSchema = z.object({
275
- change_type: z.enum(['patch', 'minor']),
276
- summary: z.string(),
277
- jira_ticket_id: z.string(),
278
- });
279
-
280
- const openAiResponse = await openaiClient.chat.completions.create({
281
- model: 'gpt-4o-mini',
282
- messages: [
283
- {
284
- role: 'system',
285
- content: `Process JSON from a Jira ticket to generate simple maximum 2 sentence release note for the ticket and determine the change type for bug it should be a patch for new feature it should be a minor change`,
286
- },
287
- {
288
- role: 'user',
289
- content: JSON.stringify(jiraTicketData),
290
- },
291
- ],
292
- response_format: zodResponseFormat(
293
- ChangeRequestSchema,
294
- 'changeset_schema',
295
- ),
296
- temperature: 0,
297
- });
298
-
299
- const assistantResponse = openAiResponse.choices[0].message.content;
300
- const parsedResponse = JSON.parse(assistantResponse);
301
-
302
- const { change_type, summary } = parsedResponse;
303
- console.log(`Change type: ${change_type}`);
304
- console.log(`Release note: ${summary}`);
305
-
306
- // Step 5: Create a changeset .md file
307
- const changesetContent = `---
308
- "${componentName}": ${change_type}
309
- ---
310
-
311
- ${summary} [${jiraTicketId}]
312
- `;
313
- const changesetFile = `./.changeset/${jiraTicketId}.md`;
314
-
315
- await createChangesetDirectory();
316
- await fs.promises.writeFile(changesetFile, changesetContent);
317
- console.log(`Created changeset file at ${changesetFile}`);
318
-
319
- console.log('Done!');
320
- } catch (err) {
321
- console.error(`Error: ${err.message}`);
322
- process.exit(1);
323
- }
163
+ await createChangeset();
324
164
  });
325
165
 
326
166
  // Parse arguments
@@ -0,0 +1,182 @@
1
+ import { $ } from 'zx';
2
+ import OpenAI from 'openai';
3
+ import z from 'zod';
4
+ import { zodResponseFormat } from 'openai/helpers/zod';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { getAllAppPackages, isMonoRepo } from '../next/util.js';
8
+ import inquirer from 'inquirer';
9
+ import { getMainPackage, getPackage } from './util.js';
10
+
11
+ async function createChangesetDirectory() {
12
+ try {
13
+ // Use path.join to build a safe path to `.changeset`
14
+ const targetDir = path.join(process.cwd(), '.changeset');
15
+
16
+ // Create the directory recursively if it doesn't exist
17
+ await fs.promises.mkdir(targetDir, { recursive: true });
18
+ } catch (error) {
19
+ console.error('Error creating .changeset directory:', error);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Gets the current git branch name
25
+ */
26
+ async function getCurrentBranch() {
27
+ const branchName = (await $`git branch --show-current`).stdout.trim();
28
+ console.log(`Current branch: ${branchName}`);
29
+ return branchName;
30
+ }
31
+
32
+ /**
33
+ * Extracts a Jira ticket ID from a branch name
34
+ */
35
+ function extractJiraTicketId(branchName) {
36
+ const jiraTicketMatch = branchName.match(/([A-Z]+-\d+)/);
37
+ if (!jiraTicketMatch) {
38
+ throw new Error('No Jira ticket found in the branch name.');
39
+ }
40
+ return jiraTicketMatch[0];
41
+ }
42
+
43
+ /**
44
+ * Fetches Jira ticket data from Jira API
45
+ */
46
+ async function fetchJiraTicketData(jiraTicketId) {
47
+ const jiraBaseUrl = 'https://docupacellc.atlassian.net';
48
+ const jiraEmail = process.env.JIRA_API_EMAIL;
49
+ const jiraApiKey = process.env.JIRA_API_KEY;
50
+ const jiraFullApiKey = `${jiraEmail}:${jiraApiKey}`;
51
+ const jiraUrl = `${jiraBaseUrl}/rest/api/2/issue/${jiraTicketId}`;
52
+
53
+ const jiraResponse = await fetch(jiraUrl, {
54
+ headers: {
55
+ Authorization: `Basic ${Buffer.from(jiraFullApiKey).toString('base64')}`,
56
+ 'Content-Type': 'application/json',
57
+ },
58
+ });
59
+
60
+ if (!jiraResponse.ok) {
61
+ throw new Error(
62
+ `Failed to fetch Jira ticket. Status: ${jiraResponse.status}`,
63
+ );
64
+ }
65
+
66
+ return await jiraResponse.json();
67
+ }
68
+
69
+ /**
70
+ * Generates release notes using OpenAI
71
+ */
72
+ async function generateReleaseNotes(jiraTicketData) {
73
+ const openaiClient = new OpenAI({
74
+ apiKey: process.env['OPENAI_API_KEY'],
75
+ });
76
+
77
+ const ChangeRequestSchema = z.object({
78
+ change_type: z.enum(['patch', 'minor']),
79
+ summary: z.string(),
80
+ jira_ticket_id: z.string(),
81
+ });
82
+
83
+ const openAiResponse = await openaiClient.chat.completions.create({
84
+ model: 'gpt-4o-mini',
85
+ messages: [
86
+ {
87
+ role: 'system',
88
+ content: `Process JSON from a Jira ticket to generate simple maximum 2 sentence release note for the ticket and determine the change type for bug it should be a patch for new feature it should be a minor change`,
89
+ },
90
+ {
91
+ role: 'user',
92
+ content: JSON.stringify(jiraTicketData),
93
+ },
94
+ ],
95
+ response_format: zodResponseFormat(ChangeRequestSchema, 'changeset_schema'),
96
+ temperature: 0,
97
+ });
98
+
99
+ const assistantResponse = openAiResponse.choices[0].message.content;
100
+ return JSON.parse(assistantResponse);
101
+ }
102
+
103
+ /**
104
+ * Writes the changeset file
105
+ */
106
+ async function writeChangesetFile(
107
+ componentName,
108
+ jiraTicketId,
109
+ changeType,
110
+ summary,
111
+ ) {
112
+ const changesetContent = `---
113
+ "${componentName}": ${changeType}
114
+ ---
115
+
116
+ ${summary} [${jiraTicketId}]
117
+ `;
118
+ const changesetFile = `./.changeset/${jiraTicketId}.md`;
119
+
120
+ await createChangesetDirectory();
121
+ await fs.promises.writeFile(changesetFile, changesetContent);
122
+ console.log(`Created changeset file at ${changesetFile}`);
123
+ }
124
+
125
+ /**
126
+ * Main function to create a changeset
127
+ */
128
+
129
+ export async function createChangeset() {
130
+ if (isMonoRepo()) {
131
+ const appPackages = await getAllAppPackages();
132
+ const response = await inquirer.prompt([
133
+ {
134
+ type: 'list',
135
+ name: 'package',
136
+ message: 'Which package do you want to generate changesetfor?',
137
+ choices: appPackages.map((appPackage) => appPackage.name),
138
+ },
139
+ ]);
140
+
141
+ const selectedPackage = appPackages.find(
142
+ (appPackage) => appPackage.name == response.package,
143
+ );
144
+
145
+ const selectedPackageContent = await getPackage(selectedPackage.path);
146
+ await createChangesetForPackage(selectedPackageContent);
147
+ } else {
148
+ const mainPackage = await getMainPackage();
149
+ await createChangesetForPackage(mainPackage);
150
+ }
151
+ }
152
+
153
+ export async function createChangesetForPackage(mainPackage) {
154
+ const componentName = mainPackage.name;
155
+ try {
156
+ // Step 1: Get the current branch name
157
+ const branchName = await getCurrentBranch();
158
+
159
+ // Step 2: Extract Jira ticket number
160
+ const jiraTicketId = extractJiraTicketId(branchName);
161
+
162
+ // Step 3: Fetch Jira ticket data
163
+ const jiraTicketData = await fetchJiraTicketData(jiraTicketId);
164
+ const jiraSummary = jiraTicketData.fields.summary;
165
+ console.log(
166
+ `Generating release notes for ${jiraTicketId} - ${jiraSummary}`,
167
+ );
168
+
169
+ // Step 4: Generate release notes using OpenAI
170
+ const { change_type, summary } = await generateReleaseNotes(jiraTicketData);
171
+ console.log(`Change type: ${change_type}`);
172
+ console.log(`Release note: ${summary}`);
173
+
174
+ // Step 5: Create a changeset .md file
175
+ await writeChangesetFile(componentName, jiraTicketId, change_type, summary);
176
+
177
+ console.log('Done!');
178
+ } catch (err) {
179
+ console.error(`Error: ${err.message}`);
180
+ process.exit(1);
181
+ }
182
+ }
@@ -0,0 +1,27 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+
4
+ async function fileExists(filePath) {
5
+ try {
6
+ await fs.promises.access(filePath);
7
+ return true;
8
+ } catch {
9
+ return false;
10
+ }
11
+ }
12
+ export async function getMainPackage() {
13
+ const mainModulePath = process.cwd();
14
+ return getPackage(mainModulePath);
15
+ }
16
+
17
+ export async function getPackage(mainModulePath) {
18
+ if (mainModulePath) {
19
+ const packageJsonPath = path.join(mainModulePath, 'package.json');
20
+ if (await fileExists(packageJsonPath)) {
21
+ const fileContent = await fs.promises.readFile(packageJsonPath, 'utf-8');
22
+ const packageJson = JSON.parse(fileContent);
23
+ return packageJson;
24
+ }
25
+ }
26
+ throw new Error('Main package.json not found');
27
+ }
@@ -2,39 +2,25 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { $ } from 'zx';
4
4
 
5
- import { getChangedPackages, isMonoRepo, setGitInfo } from '../next/util.js';
5
+ import { isMonoRepo, setGitInfo } from '../next/util.js';
6
+ import { versionStatus } from './version.js';
7
+ import { getAppReleases } from './cli.js';
6
8
 
7
9
  const CHANGESET_DIR = '.changeset';
8
10
 
9
11
  export async function validateChangesets() {
10
- /*if (isMonoRepo()) {
11
- const branch = process.env.BITBUCKET_BRANCH;
12
+ if (isMonoRepo()) {
13
+ await setGitInfo();
12
14
  const destBranch = process.env.BITBUCKET_PR_DESTINATION_BRANCH;
13
-
14
- const changePackages = await getChangedPackages(destBranch, branch);
15
-
16
- const appPackages = changePackages.filter((appPackage) =>
17
- appPackage.name.endsWith('-app'),
18
- );
19
-
20
- let appPaths;
21
- if (appPackages.length > 0) {
22
- appPaths = appPackages.map((appPackage) => appPackage.path);
23
- for (const appPath of appPaths) {
24
- const changesetPath = path.resolve(appPath, CHANGESET_DIR);
25
- await validateChangesetPath(changesetPath);
26
- }
27
- } else {
28
- throw new Error('No changeset for at least one app');
15
+ await $`git fetch origin ${destBranch}:${destBranch}`;
16
+ const releases = await versionStatus(destBranch);
17
+ const appReleases = getAppReleases(releases);
18
+ if (appReleases.length == 0) {
19
+ throw new Error('Must have a changeset for at lease one app');
29
20
  }
30
21
  } else {
31
22
  await validateChangesetPath(path.resolve(process.cwd(), CHANGESET_DIR));
32
- }*/
33
-
34
- await setGitInfo();
35
- const destBranch = process.env.BITBUCKET_PR_DESTINATION_BRANCH;
36
- await $`git fetch origin ${destBranch}:${destBranch}`;
37
- await $`changeset status --since=${destBranch}`;
23
+ }
38
24
  }
39
25
 
40
26
  export async function validateChangesetPath(directoryPath) {
@@ -0,0 +1,89 @@
1
+ import { setGitInfo } from '../next/util.js';
2
+ import { $ } from 'zx';
3
+ import fs from 'fs';
4
+ import { updateComponentVersion } from '../next/jira.js';
5
+
6
+ const changeSetPackage = `{
7
+ "name": "changeset-package",
8
+ "version": "1.0.0",
9
+ "description": "",
10
+ "scripts": {
11
+ },
12
+ "type": "module",
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "dependencies": {},
17
+ "devDependencies": {
18
+ "@changesets/cli": "^2.27.10"
19
+ }
20
+ }
21
+ `;
22
+
23
+ export async function versionStatus(sinceBranch) {
24
+ const outputPath = './changeset-output.json';
25
+
26
+ if (sinceBranch) {
27
+ await $`pnpm changeset status --output=${outputPath} --since=${sinceBranch}`;
28
+ } else {
29
+ await $`pnpm changeset status --output=${outputPath}`;
30
+ }
31
+
32
+ // Read the file and parse JSON
33
+ const jsonOutput = JSON.parse(await fs.promises.readFile(outputPath, 'utf8'));
34
+
35
+ await fs.promises.rm(outputPath);
36
+ return jsonOutput.releases;
37
+ }
38
+
39
+ export async function versionCommand(closeVersion = false) {
40
+ console.log('📦 Running Changeset versioning...');
41
+ await setGitInfo();
42
+ await $`mv package.json package.json.bak`;
43
+ await $`mv pnpm-lock.yaml pnpm-lock.yaml.bak`;
44
+ await fs.promises.writeFile('package.json', changeSetPackage);
45
+ await $`pnpm install`;
46
+ await $`rm package.json pnpm-lock.yaml`;
47
+ await $`mv package.json.bak package.json`;
48
+ await $`mv pnpm-lock.yaml.bak pnpm-lock.yaml`;
49
+ if (closeVersion) {
50
+ await $`pnpm changeset pre exit`;
51
+ }
52
+
53
+ try {
54
+ const releases = await versionStatus();
55
+
56
+ await $`pnpm changeset version`;
57
+
58
+ return releases;
59
+ } catch {
60
+ return [];
61
+ }
62
+ }
63
+
64
+ export async function updateJiraWithVersion(releases) {
65
+ const lastCommit = (await $`git log -1 --pretty=%B`).stdout.trim();
66
+ console.log(`Last commit '${lastCommit}' being processed to get Jira ticket`);
67
+
68
+ const jiraTicketMatch = lastCommit.match(/([A-Z]+-\d+)/);
69
+ const jiraTicketId = jiraTicketMatch ? jiraTicketMatch[0] : null;
70
+
71
+ // If we have all the necessary data, update the component version in Jira
72
+ if (jiraTicketId) {
73
+ for (const release of releases) {
74
+ try {
75
+ await updateComponentVersion(
76
+ jiraTicketId,
77
+ release.name,
78
+ release.newVersion,
79
+ );
80
+ } catch (error) {
81
+ console.error(
82
+ `Failed to update Jira component version: ${error.message}`,
83
+ );
84
+ }
85
+ }
86
+ }
87
+
88
+ console.log('✅ Changeset versioning complete.');
89
+ }
package/src/next/jira.js CHANGED
@@ -12,11 +12,6 @@ const jiraClient = axios.create({
12
12
  },
13
13
  });
14
14
 
15
- const packageComponents = {
16
- 'docupace-ui': 'next-ui',
17
- 'docupace-graphql-server': 'graphql-server',
18
- '@docupace/template': 'template',
19
- };
20
15
  /**
21
16
  * Updates the component version custom field in Jira
22
17
  * @param {string} issueKey - The Jira issue key
@@ -24,7 +19,7 @@ const packageComponents = {
24
19
  * @param {string} version - The version to set
25
20
  */
26
21
  export async function updateComponentVersion(issueKey, packageName, version) {
27
- const component = packageComponents[packageName] ?? packageName;
22
+ const component = packageName;
28
23
  console.log(
29
24
  `Updating ${issueKey} for package ${packageName} translated to component ${component} with version ${version}`,
30
25
  );
@@ -33,12 +33,18 @@ export async function publish(gitSha) {
33
33
 
34
34
  await loginRegistry();
35
35
 
36
- const manifestCheck =
37
- await $`docker manifest inspect ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`
38
- .quiet()
39
- .catch(() => null);
36
+ let manifestExists = false;
37
+ try {
38
+ $.verbose = false; // Silence output temporarily
39
+ await $`docker manifest inspect ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
40
+ manifestExists = true;
41
+ } catch {
42
+ manifestExists = false;
43
+ } finally {
44
+ $.verbose = true; // Restore normal output
45
+ }
40
46
 
41
- if (manifestCheck?.exitCode === 0) {
47
+ if (manifestExists) {
42
48
  console.log(
43
49
  `Tag sha-${gitSha} already exists in the remote repository. Skipping push.`,
44
50
  );
@@ -50,12 +56,13 @@ export async function publish(gitSha) {
50
56
  await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${BUILD_IMAGE_NAME}`;
51
57
  await $`docker push ${JF_REGISTRY_FULL_URL}/${BUILD_IMAGE_NAME}`;
52
58
 
53
- const GIT_TAGS = (await $`git tag --points-at HEAD`).stdout
59
+ const gitTags = (await $`git tag --points-at HEAD`).stdout
54
60
  .trim()
55
61
  .split('\n')
56
62
  .filter(Boolean);
57
- for (const GIT_TAG of GIT_TAGS) {
58
- const tagName = `${BITBUCKET_REPO_SLUG}:${GIT_TAG}`;
63
+ for (const gitTag of gitTags) {
64
+ const version = gitTag.includes('@') ? 'v' + gitTag.split('@')[1] : gitTag;
65
+ const tagName = `${IMAGE_PREFIX}:${version}`;
59
66
  await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${tagName}`;
60
67
  await $`docker push ${JF_REGISTRY_FULL_URL}/${tagName}`;
61
68
  }
package/src/next/util.js CHANGED
@@ -3,8 +3,6 @@ import { join } from 'path';
3
3
  import { $, nothrow } from 'zx';
4
4
  import path from 'path';
5
5
 
6
- const GIT_SHA = (await $`git log --pretty=format:'%h' -n 1`).stdout.trim();
7
-
8
6
  export function isMonoRepo() {
9
7
  // Check for the presence of turbo.json which indicates a Turborepo monorepo
10
8
  return existsSync(join(process.cwd(), 'turbo.json'));
@@ -41,6 +39,33 @@ export async function getChangedPackagesInternal(fromRef, toRef) {
41
39
  }
42
40
  }
43
41
 
42
+ export async function getAllPackages() {
43
+ try {
44
+ const turboDryOutput = await $`turbo run build --dry=json`;
45
+ const dryRunJson = turboDryOutput.stdout.trim();
46
+ const dryRun = JSON.parse(dryRunJson);
47
+
48
+ const packages = dryRun.tasks.map((task) => ({
49
+ name: task.package,
50
+ directory: task.directory,
51
+ path: path.resolve(process.cwd(), task.directory),
52
+ }));
53
+
54
+ return packages;
55
+ } catch (error) {
56
+ console.error('Error getting changed packages:', error);
57
+ return [];
58
+ }
59
+ }
60
+
61
+ export async function getAllAppPackages() {
62
+ const changedPackages = await getAllPackages();
63
+ const appPackages = changedPackages.filter((appPackage) =>
64
+ appPackage.directory.startsWith('apps'),
65
+ );
66
+ return appPackages;
67
+ }
68
+
44
69
  export async function getChangedPackages() {
45
70
  const branch = process.env.BITBUCKET_BRANCH;
46
71
  const destBranch = process.env.BITBUCKET_PR_DESTINATION_BRANCH;
@@ -60,24 +85,6 @@ export async function getChangedAppPackages() {
60
85
  return appPackages;
61
86
  }
62
87
 
63
- export async function buildChangePackages() {
64
- const appPackages = await getChangedAppPackages();
65
- if (appPackages.length == 0) {
66
- throw new Error('Nothing to build');
67
- }
68
- for (const appPackage of appPackages) {
69
- await dockerBuild(appPackage);
70
- }
71
- }
72
-
73
- export async function dockerBuild(appPackage) {
74
- process.env.DOCKER_HOST = '';
75
- const shortName = appPackage.name.replace('@docupace/', '');
76
- const imageName = `${process.env.BITBUCKET_REPO_SLUG}-${shortName}:sha-${GIT_SHA}-withMaps`;
77
- console.log(`Building Docker image ${imageName}...`);
78
- await $`docker build --secret id=npm_token,env=DOCUPACE_NPM_TOKEN . --file ${path.resolve(appPackage.path, 'Dockerfile')} --target builder --tag ${imageName}`;
79
- }
80
-
81
88
  export async function setGitInfo() {
82
89
  await $`git config --global user.email "gitops@docupace.com"`;
83
90
  await $`git config --global user.name "Gitops"`;