@docupace/pipeline 1.0.0-alpha.68 → 1.0.0-alpha.7
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/bin/next-changeset-validate.sh +1 -2
- package/next/changeset.sh +2 -0
- package/next/deploy.sh +29 -29
- package/next/validateChangeset.cjs +43 -0
- package/package.json +4 -12
- package/src/changeset/cli.js +0 -228
- package/src/changeset/validate.js +0 -44
- package/src/next/cli.js +0 -59
- package/src/next/copy.js +0 -21
- package/src/next/deploy.js +0 -118
- package/src/next/publish.js +0 -46
- package/src/next/pull.js +0 -7
- package/src/next/sonar.js +0 -23
package/next/changeset.sh
CHANGED
|
@@ -8,6 +8,8 @@ DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
8
8
|
validate_changesets() {
|
|
9
9
|
if [ ! -z "$PR_ID" ]; then
|
|
10
10
|
echo "🔍 Validating changesets..."
|
|
11
|
+
echo "Current Dir $DIR"
|
|
12
|
+
echo "1=$1"
|
|
11
13
|
pnpm node $DIR/validateChangeset.cjs $1 || {
|
|
12
14
|
if [ $? -eq 1 ]; then
|
|
13
15
|
echo "❌ 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"
|
package/next/deploy.sh
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
set -e # Enable command tracing
|
|
4
|
+
# Variables
|
|
5
|
+
REPO_NAME="gitops-dev"
|
|
6
|
+
REPO_URL="https://x-token-auth:$GITOPS_REP_TOKEN@bitbucket.org/dp-cloud/${REPO_NAME}.git"
|
|
7
|
+
FILE_PATH="dp/$2/$1.values.yaml"
|
|
8
|
+
BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER
|
|
9
|
+
GITOPS_BRANCH=master
|
|
10
|
+
if [ -n "$VERSION_TAG" ]; then
|
|
11
|
+
DEPLOY_TAG=$VERSION_TAG
|
|
12
|
+
else
|
|
13
|
+
DEPLOY_TAG="build-$BUILD_NUMBER"
|
|
14
|
+
fi
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
# Clone the repository
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
git config user.email qxebpukjnzljnwty1knte7ym53aogk@bots.bitbucket.org
|
|
21
|
+
git clone $REPO_URL
|
|
22
|
+
cd ${REPO_NAME} || exit
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# Checkout the branch
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
# Modify the YAML file
|
|
27
|
+
sed -i "s/tag: .*/tag: $DEPLOY_TAG/" $FILE_PATH
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
# Add changes to git
|
|
30
|
+
git add $FILE_PATH
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
# Commit changes
|
|
33
|
+
git commit -m "Update image tag to $DEPLOY_TAG"
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
# Push changes
|
|
36
|
+
git push origin $GITOPS_BRANCH
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
# Clean up
|
|
39
|
+
cd ..
|
|
40
|
+
rm -rf ${REPO_NAME}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const directoryPath = process.argv[2];
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
// Step 1: Read the directory for md files excluding README.md
|
|
8
|
+
const allFiles = fs.readdirSync(directoryPath);
|
|
9
|
+
const mdFiles = allFiles.filter(file => file.endsWith('.md') && file !== 'README.md');
|
|
10
|
+
|
|
11
|
+
// Step 2: Check for pre.json and parse it
|
|
12
|
+
const preJsonPath = path.join(directoryPath, 'pre.json');
|
|
13
|
+
let preJson;
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(preJsonPath) && mdFiles.length === 0) {
|
|
16
|
+
console.error("Error: No pre.json and no md files found.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (fs.existsSync(preJsonPath)) {
|
|
21
|
+
preJson = JSON.parse(fs.readFileSync(preJsonPath, 'utf-8'));
|
|
22
|
+
|
|
23
|
+
if(preJson.mode == 'pre') {
|
|
24
|
+
// Step 4a: Get list of changesets from pre.json
|
|
25
|
+
const changesets = preJson.changesets || [];
|
|
26
|
+
const changesetNames = changesets.map(change => change);
|
|
27
|
+
|
|
28
|
+
// Step 4b: Match files with the list of changesets
|
|
29
|
+
const mdFileNamesWithoutExt = mdFiles.map(file => path.basename(file, '.md'));
|
|
30
|
+
const unmatchedFiles = mdFileNamesWithoutExt.filter(fileName => !changesetNames.includes(fileName));
|
|
31
|
+
|
|
32
|
+
if (unmatchedFiles.length == 0) {
|
|
33
|
+
console.error("No new MD files found:", unmatchedFiles);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log("Validation successful.");
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error("Error while processing:", error);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docupace/pipeline",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"type": "module",
|
|
7
6
|
"bin": {
|
|
8
|
-
"
|
|
9
|
-
"dp-next-cli": "src/next/cli.js"
|
|
7
|
+
"next-changeset-validate": "./bin/next-changeset-validate.sh"
|
|
10
8
|
},
|
|
11
9
|
"keywords": [
|
|
12
10
|
"bash"
|
|
13
11
|
],
|
|
14
12
|
"author": "",
|
|
15
13
|
"license": "ISC",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"js-yaml": "^4.1.0",
|
|
19
|
-
"openai": "^4.76.3",
|
|
20
|
-
"zx": "^8.2.4"
|
|
21
|
-
},
|
|
22
|
-
"devDependencies": {
|
|
23
|
-
"esbuild": "^0.24.0"
|
|
14
|
+
"scripts": {
|
|
15
|
+
"next-changeset-validate": "bash next/changeset.sh validate"
|
|
24
16
|
}
|
|
25
17
|
}
|
package/src/changeset/cli.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import { $ } from 'zx';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import {validateChangesets} from "./validate.js";
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import OpenAI from "openai";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const program = new Command();
|
|
11
|
-
|
|
12
|
-
const args = process.argv;
|
|
13
|
-
|
|
14
|
-
const DIR = path.resolve(process.cwd());
|
|
15
|
-
|
|
16
|
-
// Helper function to set Git info
|
|
17
|
-
async function setGitInfo() {
|
|
18
|
-
await $`git config --global user.email "gitops@docupace.com"`;
|
|
19
|
-
await $`git config --global user.name "Gitops"`;
|
|
20
|
-
await $`git remote set-url origin https://x-token-auth:${process.env.THIS_REP_TOKEN}@bitbucket.org/${process.env.BITBUCKET_REPO_FULL_NAME}.git`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const changeSetPackage = `{
|
|
24
|
-
"name": "changeset-package",
|
|
25
|
-
"version": "1.0.0",
|
|
26
|
-
"description": "",
|
|
27
|
-
"scripts": {
|
|
28
|
-
},
|
|
29
|
-
"type": "module",
|
|
30
|
-
"keywords": [],
|
|
31
|
-
"author": "",
|
|
32
|
-
"license": "ISC",
|
|
33
|
-
"dependencies": {},
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@changesets/cli": "^2.27.10"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
async function versionCommand() {
|
|
41
|
-
console.log('📦 Running Changeset versioning...');
|
|
42
|
-
await setGitInfo();
|
|
43
|
-
await $`mv package.json package.json.bak`
|
|
44
|
-
await $`mv pnpm-lock.yaml pnpm-lock.yaml.bak`
|
|
45
|
-
await fs.promises.writeFile('package.json', changeSetPackage);
|
|
46
|
-
await $`pnpm install`;
|
|
47
|
-
await $`rm package.json pnpm-lock.yaml`
|
|
48
|
-
await $`mv package.json.bak package.json`
|
|
49
|
-
await $`mv pnpm-lock.yaml.bak pnpm-lock.yaml`
|
|
50
|
-
await $`pnpm changeset version`;
|
|
51
|
-
console.log('✅ Changeset versioning complete.');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function commitTagCommand() {
|
|
55
|
-
console.log('📌 Committing and tagging the new version...');
|
|
56
|
-
await setGitInfo();
|
|
57
|
-
await $`git add .`;
|
|
58
|
-
const newVersion = (await $`node -p "require('./package.json').version"`).stdout.trim();
|
|
59
|
-
await $`git commit -m "Version bump to ${newVersion} and changelog"`;
|
|
60
|
-
await $`git push origin`;
|
|
61
|
-
await $`git tag v${newVersion}`;
|
|
62
|
-
await $`git push origin --tags`;
|
|
63
|
-
console.log(`✅ Version ${newVersion} tagged and pushed.`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Command: validate
|
|
67
|
-
program
|
|
68
|
-
.command('validate <path>')
|
|
69
|
-
.description('Validate changesets for the provided PR')
|
|
70
|
-
.action(async (path) => {
|
|
71
|
-
if(!process.env.BITBUCKET_PR_ID) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
console.log('🔍 Validating changesets...');
|
|
75
|
-
try {
|
|
76
|
-
await validateChangesets(path);
|
|
77
|
-
console.log('✅ Changeset validation passed.');
|
|
78
|
-
} catch (error) {
|
|
79
|
-
console.error(
|
|
80
|
-
'❌ 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'
|
|
81
|
-
);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
// Command: version
|
|
86
|
-
program
|
|
87
|
-
.command('version')
|
|
88
|
-
.description('Run Changeset versioning')
|
|
89
|
-
.action(async () => {
|
|
90
|
-
await versionCommand();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Command: commit-and-tag
|
|
94
|
-
program
|
|
95
|
-
.command('commit-tag')
|
|
96
|
-
.description('Commit and tag the new version')
|
|
97
|
-
.action(async () => {
|
|
98
|
-
await commitTagCommand();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Command: all
|
|
102
|
-
program
|
|
103
|
-
.command('version-commit-tag')
|
|
104
|
-
.description('Run versioning and commit-and-tag in sequence')
|
|
105
|
-
.action(async () => {
|
|
106
|
-
console.log('📦 Running all steps...');
|
|
107
|
-
await versionCommand();
|
|
108
|
-
await commitTagCommand();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
program
|
|
112
|
-
.name('create-changeset')
|
|
113
|
-
.description('Creates a changeset based on the current branch and Jira ticket information')
|
|
114
|
-
.action(async () => {
|
|
115
|
-
try {
|
|
116
|
-
// Step 1: Get the current branch name
|
|
117
|
-
const branchName = (await $`git branch --show-current`).stdout.trim();
|
|
118
|
-
console.log(`Current branch: ${branchName}`);
|
|
119
|
-
|
|
120
|
-
// Step 2: Extract Jira ticket number (e.g., matching JIRA-1234 pattern)
|
|
121
|
-
const jiraTicketMatch = branchName.match(/([A-Z]+-\d+)/);
|
|
122
|
-
if (!jiraTicketMatch) {
|
|
123
|
-
throw new Error('No Jira ticket found in the branch name.');
|
|
124
|
-
}
|
|
125
|
-
const jiraTicketId = jiraTicketMatch[0];
|
|
126
|
-
console.log(`Extracted Jira ticket ID: ${jiraTicketId}`);
|
|
127
|
-
|
|
128
|
-
// Step 3: Fetch Jira ticket information
|
|
129
|
-
const jiraBaseUrl = process.env.JIRA_BASE_URL;
|
|
130
|
-
const jiraApiKey = process.env.JIRA_API_KEY;
|
|
131
|
-
const jiraUrl = `${jiraBaseUrl}/rest/api/2/issue/${jiraTicketId}`;
|
|
132
|
-
console.log(jiraApiKey);
|
|
133
|
-
console.log(jiraUrl);
|
|
134
|
-
const jiraResponse = await fetch(jiraUrl, {
|
|
135
|
-
headers: {
|
|
136
|
-
Authorization: `Basic ${Buffer.from(jiraApiKey).toString('base64')}`,
|
|
137
|
-
'Content-Type': 'application/json',
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
if (!jiraResponse.ok) {
|
|
142
|
-
throw new Error(`Failed to fetch Jira ticket. Status: ${jiraResponse.status}`);
|
|
143
|
-
}
|
|
144
|
-
const jiraTicketData = await jiraResponse.json();
|
|
145
|
-
const summary = jiraTicketData.fields.summary;
|
|
146
|
-
console.log(`Jira ticket summary: ${summary}`);
|
|
147
|
-
|
|
148
|
-
const openaiClient = new OpenAI({
|
|
149
|
-
apiKey: process.env['OPENAI_API_KEY'],
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const openAiResponse = await openaiClient.chat.completions.create({
|
|
153
|
-
model: "gpt-4",
|
|
154
|
-
messages: [
|
|
155
|
-
{
|
|
156
|
-
role: "system",
|
|
157
|
-
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`,
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
role: "user",
|
|
161
|
-
content: `Schema:
|
|
162
|
-
{
|
|
163
|
-
"name": "change_request",
|
|
164
|
-
"strict": true,
|
|
165
|
-
"schema": {
|
|
166
|
-
"type": "object",
|
|
167
|
-
"properties": {
|
|
168
|
-
"change_type": {
|
|
169
|
-
"type": "string",
|
|
170
|
-
"description": "The type of change requested, either a patch or minor update.",
|
|
171
|
-
"enum": [
|
|
172
|
-
"patch",
|
|
173
|
-
"minor"
|
|
174
|
-
]
|
|
175
|
-
},
|
|
176
|
-
"summary": {
|
|
177
|
-
"type": "string",
|
|
178
|
-
"description": "A brief summary of the change being requested."
|
|
179
|
-
},
|
|
180
|
-
"jira_ticket_id": {
|
|
181
|
-
"type": "string",
|
|
182
|
-
"description": "The ID of the related Jira ticket associated with this change request."
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
"required": [
|
|
186
|
-
"change_type",
|
|
187
|
-
"summary",
|
|
188
|
-
"jira_ticket_id"
|
|
189
|
-
],
|
|
190
|
-
"additionalProperties": false
|
|
191
|
-
}
|
|
192
|
-
}`,
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
role: "user",
|
|
196
|
-
content: JSON.stringify(jiraTicketData),
|
|
197
|
-
},
|
|
198
|
-
],
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const assistantResponse = openAiResponse.data.choices[0].message.content;
|
|
202
|
-
const parsedResponse = JSON.parse(assistantResponse);
|
|
203
|
-
|
|
204
|
-
const { change_type } = parsedResponse;
|
|
205
|
-
console.log(`Determined change type: ${change_type}`);
|
|
206
|
-
|
|
207
|
-
// Step 5: Create a changeset using pnpm
|
|
208
|
-
const changesetContent = `---
|
|
209
|
-
"${jiraTicketId}": ${change_type}
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
${summary}
|
|
213
|
-
`;
|
|
214
|
-
const changesetFile = `./.changeset/${jiraTicketId}.md`;
|
|
215
|
-
|
|
216
|
-
await $`mkdir -p ./.changeset`;
|
|
217
|
-
await $`echo ${JSON.stringify(changesetContent)} > ${changesetFile}`;
|
|
218
|
-
console.log(`Created changeset file at ${changesetFile}`);
|
|
219
|
-
|
|
220
|
-
console.log('Done!');
|
|
221
|
-
} catch (err) {
|
|
222
|
-
console.error(`Error: ${err.message}`);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// Parse arguments
|
|
228
|
-
program.parse(args);
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export async function validateChangesets(directoryPath) {
|
|
5
|
-
try {
|
|
6
|
-
// Step 1: Read the directory for md files excluding README.md
|
|
7
|
-
const allFiles = fs.readdirSync(directoryPath);
|
|
8
|
-
const mdFiles = allFiles.filter(file => file.endsWith('.md') && file !== 'README.md');
|
|
9
|
-
|
|
10
|
-
// Step 2: Check for pre.json and parse it
|
|
11
|
-
const preJsonPath = path.join(directoryPath, 'pre.json');
|
|
12
|
-
let preJson;
|
|
13
|
-
|
|
14
|
-
if (!fs.existsSync(preJsonPath) && mdFiles.length === 0) {
|
|
15
|
-
throw new Error("Error: No pre.json and no md files found.")
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (fs.existsSync(preJsonPath)) {
|
|
19
|
-
preJson = JSON.parse(fs.readFileSync(preJsonPath, 'utf-8'));
|
|
20
|
-
|
|
21
|
-
if(preJson.mode == 'pre') {
|
|
22
|
-
// Step 4a: Get list of changesets from pre.json
|
|
23
|
-
const changesets = preJson.changesets || [];
|
|
24
|
-
const changesetNames = changesets.map(change => change);
|
|
25
|
-
|
|
26
|
-
// Step 4b: Match files with the list of changesets
|
|
27
|
-
const mdFileNamesWithoutExt = mdFiles.map(file => path.basename(file, '.md'));
|
|
28
|
-
const unmatchedFiles = mdFileNamesWithoutExt.filter(fileName => !changesetNames.includes(fileName));
|
|
29
|
-
|
|
30
|
-
if (unmatchedFiles.length == 0) {
|
|
31
|
-
throw new Error("Error: No new MD files found:");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log("Validation successful.");
|
|
37
|
-
} catch (error) {
|
|
38
|
-
console.log(error.message);
|
|
39
|
-
throw(error);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
package/src/next/cli.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Command } from 'commander';
|
|
4
|
-
import { pull } from './pull.js';
|
|
5
|
-
import { sonar } from './sonar.js';
|
|
6
|
-
import { publish } from './publish.js';
|
|
7
|
-
import { deploy } from './deploy.js';
|
|
8
|
-
import { deployTemplate } from './deploy.js';
|
|
9
|
-
import { copy } from './copy.js';
|
|
10
|
-
|
|
11
|
-
const program = new Command();
|
|
12
|
-
|
|
13
|
-
// GIT SHA computation
|
|
14
|
-
import { $ } from 'zx';
|
|
15
|
-
const GIT_SHA = (await $`git log --pretty=format:'%h' -n 1`).stdout.trim();
|
|
16
|
-
|
|
17
|
-
program
|
|
18
|
-
.command('pull <imageName>')
|
|
19
|
-
.description('Pull a Docker image from the registry')
|
|
20
|
-
.action(async (imageName) => {
|
|
21
|
-
await pull(imageName);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
program
|
|
25
|
-
.command('sonar')
|
|
26
|
-
.description('Run Sonar analysis')
|
|
27
|
-
.action(async () => {
|
|
28
|
-
await sonar(GIT_SHA);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
program
|
|
32
|
-
.command('publish')
|
|
33
|
-
.description('Publish a Docker image')
|
|
34
|
-
.action(async () => {
|
|
35
|
-
await publish(GIT_SHA);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
program
|
|
39
|
-
.command('deploy <application> <site>')
|
|
40
|
-
.description('Deploy an application for a specific site')
|
|
41
|
-
.action(async (application, site) => {
|
|
42
|
-
await deploy(application, site);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
program
|
|
46
|
-
.command('deployTemplate <site>')
|
|
47
|
-
.description('Deploy an application for a specific site')
|
|
48
|
-
.action(async (site) => {
|
|
49
|
-
await deployTemplate(site);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
program
|
|
53
|
-
.command('copy')
|
|
54
|
-
.description('Copy a Docker image between registries')
|
|
55
|
-
.action(async () => {
|
|
56
|
-
await copy();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
program.parse(process.argv);
|
package/src/next/copy.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { $ } from 'zx';
|
|
2
|
-
|
|
3
|
-
export async function copy() {
|
|
4
|
-
const JF_REGISTRY_URL = 'registry.paperout.com';
|
|
5
|
-
const SOURCE_REGISTRY = `${JF_REGISTRY_URL}/${process.env.BITBUCKET_REPO_SLUG}-dev-docker-local`;
|
|
6
|
-
const TARGET_REGISTRY = `${JF_REGISTRY_URL}/${process.env.BITBUCKET_REPO_SLUG}-${process.env.TARGET_ENV}-docker-local`;
|
|
7
|
-
const IMAGE_NAME = `${process.env.BITBUCKET_REPO_SLUG}:${process.env.PUBLISH_TAG}`;
|
|
8
|
-
const SOURCE_FULL_IMAGE_NAME = `${SOURCE_REGISTRY}/${IMAGE_NAME}`;
|
|
9
|
-
const TARGET_FULL_IMAGE_NAME = `${TARGET_REGISTRY}/${IMAGE_NAME}`;
|
|
10
|
-
|
|
11
|
-
console.log(`Copying Docker image: ${SOURCE_FULL_IMAGE_NAME} -> ${TARGET_FULL_IMAGE_NAME}`);
|
|
12
|
-
|
|
13
|
-
// Login to source registry
|
|
14
|
-
await $`echo ${process.env.JF_REGISTRY_PASSWORD_DEV} | docker login --username ${process.env.JF_REGISTRY_USER_DEV} --password-stdin ${JF_REGISTRY_URL}`;
|
|
15
|
-
await $`docker pull ${SOURCE_FULL_IMAGE_NAME}`;
|
|
16
|
-
await $`docker tag ${SOURCE_FULL_IMAGE_NAME} ${TARGET_FULL_IMAGE_NAME}`;
|
|
17
|
-
|
|
18
|
-
// Login to target registry
|
|
19
|
-
await $`echo ${process.env.JF_REGISTRY_PASSWORD_QA} | docker login --username ${process.env.JF_REGISTRY_USER_QA} --password-stdin ${JF_REGISTRY_URL}`;
|
|
20
|
-
await $`docker push ${TARGET_FULL_IMAGE_NAME}`;
|
|
21
|
-
}
|
package/src/next/deploy.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import yaml from 'js-yaml';
|
|
4
|
-
import { $ } from 'zx';
|
|
5
|
-
|
|
6
|
-
const REPO_NAME = 'gitops-dev';
|
|
7
|
-
const REPO_URL = `https://x-token-auth:${process.env.GITOPS_DEV_REP_TOKEN}@bitbucket.org/dp-cloud/${REPO_NAME}.git`;
|
|
8
|
-
const GITOPS_BRANCH = 'master';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Clone the repository, read the YAML file, and return the parsed data and file paths.
|
|
12
|
-
* @param {string} application - The application name.
|
|
13
|
-
* @param {string} site - The site name.
|
|
14
|
-
* @returns {object} - The repository path, file path, and YAML data.
|
|
15
|
-
*/
|
|
16
|
-
export async function readDeployConfig(application, site) {
|
|
17
|
-
const repoPath = path.join(process.cwd(), REPO_NAME);
|
|
18
|
-
const deployConfigFilePath = path.join(repoPath, `dp/${site}/${application}.values.yaml`);
|
|
19
|
-
|
|
20
|
-
console.log(`Cloning repository: ${REPO_NAME}`);
|
|
21
|
-
await $`git clone ${REPO_URL}`;
|
|
22
|
-
console.log(`Repository cloned to: ${repoPath}`);
|
|
23
|
-
|
|
24
|
-
let deployConfig;
|
|
25
|
-
try {
|
|
26
|
-
deployConfig = yaml.load(fs.readFileSync(deployConfigFilePath, 'utf8'));
|
|
27
|
-
console.log(`YAML file loaded from: ${deployConfigFilePath}`);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error(`Error reading YAML file: ${error.message}`);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return { repoPath, deployConfigFilePath, deployConfig };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Update the `tag` field in the YAML data.
|
|
38
|
-
* @param {object} deployConfig - The parsed YAML data.
|
|
39
|
-
* @param {string} tag - The new tag to set.
|
|
40
|
-
* @returns {object} - The updated YAML data.
|
|
41
|
-
*/
|
|
42
|
-
export function setTag(deployConfig, tag) {
|
|
43
|
-
if (deployConfig.image && deployConfig.image.tag) {
|
|
44
|
-
console.log(`Current image tag: ${deployConfig.image.tag}`);
|
|
45
|
-
deployConfig.image.tag = tag;
|
|
46
|
-
console.log(`Updated image tag to: ${deployConfig.image.tag}`);
|
|
47
|
-
} else {
|
|
48
|
-
console.error('No "image.tag" field found in the YAML file.');
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
return deployConfig;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Write the updated YAML data back to the file, commit the changes, and push to the remote branch.
|
|
56
|
-
* @param {string} repoPath - The path to the cloned repository.
|
|
57
|
-
* @param {string} deployConfigFilePath - The path to the YAML file.
|
|
58
|
-
* @param {object} deployConfig - The updated YAML data.
|
|
59
|
-
*/
|
|
60
|
-
export async function writeDeployConfig(repoPath, deployConfigFilePath, deployConfig) {
|
|
61
|
-
try {
|
|
62
|
-
fs.writeFileSync(deployConfigFilePath, yaml.dump(deployConfig), 'utf8');
|
|
63
|
-
console.log(`Updated YAML file saved at: ${deployConfigFilePath}`);
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error(`Error writing YAML file: ${error.message}`);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
console.log('Committing changes to the repository...');
|
|
70
|
-
await $`cd ${repoPath} && git config user.email "gitops@docupace.com"`;
|
|
71
|
-
await $`cd ${repoPath} && git add ${deployConfigFilePath}`;
|
|
72
|
-
await $`cd ${repoPath} && git commit -m "Update image tag to ${deployConfig.image.tag}"`;
|
|
73
|
-
await $`cd ${repoPath} && git push origin ${GITOPS_BRANCH}`;
|
|
74
|
-
console.log('Changes pushed to the remote repository.');
|
|
75
|
-
|
|
76
|
-
console.log('Cleaning up...');
|
|
77
|
-
await $`rm -rf ${repoPath}`;
|
|
78
|
-
console.log('Cleanup complete.');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Main deploy function that orchestrates reading, updating, and writing the deployment config.
|
|
83
|
-
* @param {string} application - The application name.
|
|
84
|
-
* @param {string} site - The site name.
|
|
85
|
-
*/
|
|
86
|
-
|
|
87
|
-
async function getDeployTag() {
|
|
88
|
-
const gitTag = (await $`git tag --points-at HEAD | grep '^v' | head -n 1`).stdout.trim()
|
|
89
|
-
const deployTag = gitTag || `build-${process.env.BITBUCKET_BUILD_NUMBER}`;
|
|
90
|
-
return deployTag;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function deployTemplate(site) {
|
|
94
|
-
const deployTag = await getDeployTag();
|
|
95
|
-
console.log(`Deploying standard template for site: ${site}`);
|
|
96
|
-
console.log(`Using deployment tag: ${deployTag}`);
|
|
97
|
-
const { repoPath, deployConfigFilePath, deployConfig } = await readDeployConfig('graphql-server', site);
|
|
98
|
-
|
|
99
|
-
deployConfig.graphqlServer.standardConfigRemoteBranch = deployTag;
|
|
100
|
-
|
|
101
|
-
await writeDeployConfig(repoPath, deployConfigFilePath, deployConfig);
|
|
102
|
-
console.log('Deployment completed successfully.');
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
export async function deploy(application, site) {
|
|
108
|
-
const deployTag = getDeployTag();
|
|
109
|
-
|
|
110
|
-
console.log(`Deploying application: ${application} for site: ${site}`);
|
|
111
|
-
console.log(`Using deployment tag: ${deployTag}`);
|
|
112
|
-
|
|
113
|
-
const { repoPath, deployConfigFilePath, deployConfig } = await readDeployConfig(application, site);
|
|
114
|
-
const updatedConfigData = setTag(deployConfig, deployTag);
|
|
115
|
-
await writeDeployConfig(repoPath, deployConfigFilePath, updatedConfigData);
|
|
116
|
-
|
|
117
|
-
console.log('Deployment completed successfully.');
|
|
118
|
-
}
|
package/src/next/publish.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { $ } from 'zx';
|
|
2
|
-
|
|
3
|
-
export async function publish(GIT_SHA) {
|
|
4
|
-
const BITBUCKET_REPO_SLUG = process.env.BITBUCKET_REPO_SLUG;
|
|
5
|
-
const BUILD_IMAGE_NAME = `${BITBUCKET_REPO_SLUG}:build-${process.env.BITBUCKET_BUILD_NUMBER}`;
|
|
6
|
-
const IMAGE_NAME = `${BITBUCKET_REPO_SLUG}:sha-${GIT_SHA}`;
|
|
7
|
-
const JF_REGISTRY_FULL_URL = `${process.env.JF_REGISTRY_URL}/${process.env.JF_REGISTRY_REPO_NAME}`;
|
|
8
|
-
|
|
9
|
-
console.log(`Publishing Docker image: ${IMAGE_NAME}`);
|
|
10
|
-
|
|
11
|
-
// Docker login
|
|
12
|
-
await $`echo ${process.env.JF_REGISTRY_PASSWORD_DEV} | docker login --username ${process.env.JF_REGISTRY_USER_DEV} --password-stdin ${process.env.JF_REGISTRY_URL}`;
|
|
13
|
-
|
|
14
|
-
// Check if the image already exists
|
|
15
|
-
try {
|
|
16
|
-
await $`docker manifest inspect ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
|
|
17
|
-
console.log(`Tag sha-${GIT_SHA} already exists in the remote repository. Skipping push.`);
|
|
18
|
-
} catch {
|
|
19
|
-
await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
|
|
20
|
-
await $`docker push ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Tag and push build image
|
|
24
|
-
await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${BUILD_IMAGE_NAME}`;
|
|
25
|
-
await $`docker push ${JF_REGISTRY_FULL_URL}/${BUILD_IMAGE_NAME}`;
|
|
26
|
-
|
|
27
|
-
// Fetch Git tags pointing to the current HEAD
|
|
28
|
-
const gitTagsOutput = (await $`git tag --points-at HEAD`).stdout.trim();
|
|
29
|
-
const gitTags = gitTagsOutput.split('\n').filter((tag) => tag);
|
|
30
|
-
|
|
31
|
-
// Tag and push each Git tag as a Docker tag
|
|
32
|
-
if (gitTags.length > 0) {
|
|
33
|
-
console.log(`Found Git tags pointing to HEAD: ${gitTags.join(', ')}`);
|
|
34
|
-
for (const gitTag of gitTags) {
|
|
35
|
-
const dockerTag = `${JF_REGISTRY_FULL_URL}/${BITBUCKET_REPO_SLUG}:${gitTag}`;
|
|
36
|
-
console.log(`Tagging and pushing Docker image for Git tag: ${gitTag}`);
|
|
37
|
-
await $`docker tag ${IMAGE_NAME} ${dockerTag}`;
|
|
38
|
-
await $`docker push ${dockerTag}`;
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
console.log('No Git tags found pointing to the current HEAD.');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Docker logout
|
|
45
|
-
await $`docker logout ${process.env.JF_REGISTRY_URL}`;
|
|
46
|
-
}
|
package/src/next/pull.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { $ } from 'zx';
|
|
2
|
-
|
|
3
|
-
export async function pull(imageName) {
|
|
4
|
-
const JF_REGISTRY_FULL_URL = `${process.env.JF_REGISTRY_URL}/${process.env.JF_REGISTRY_REPO_NAME}`;
|
|
5
|
-
console.log(`Pulling Docker image: ${JF_REGISTRY_FULL_URL}/${imageName}`);
|
|
6
|
-
await $`docker pull ${JF_REGISTRY_FULL_URL}/${imageName}`;
|
|
7
|
-
}
|
package/src/next/sonar.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { $ } from 'zx';
|
|
2
|
-
|
|
3
|
-
export async function sonar(GIT_SHA) {
|
|
4
|
-
const IMAGE_NAME = `${process.env.BITBUCKET_REPO_SLUG}:sha-${GIT_SHA}`;
|
|
5
|
-
const SONAR_CONTAINER_NAME = `${process.env.BITBUCKET_REPO_SLUG}-${GIT_SHA}`;
|
|
6
|
-
|
|
7
|
-
console.log(`Running Sonar analysis on Docker image: ${IMAGE_NAME}`);
|
|
8
|
-
|
|
9
|
-
// Remove existing container
|
|
10
|
-
const existingContainer = (
|
|
11
|
-
await $`docker ps -a --filter "name=${SONAR_CONTAINER_NAME}" --format "{{.Names}}"`
|
|
12
|
-
).stdout.trim();
|
|
13
|
-
if (existingContainer) {
|
|
14
|
-
await $`docker rm -f ${SONAR_CONTAINER_NAME}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
await $`docker run --rm \
|
|
18
|
-
-e BRANCH=${process.env.BITBUCKET_BRANCH} \
|
|
19
|
-
-e PR_ID=${process.env.BITBUCKET_PR_ID} \
|
|
20
|
-
-e PR_DESTINATION_BRANCH=${process.env.BITBUCKET_PR_DESTINATION_BRANCH} \
|
|
21
|
-
-e SONAR_TOKEN=${process.env.SONAR_TOKEN} \
|
|
22
|
-
--name ${SONAR_CONTAINER_NAME} ${IMAGE_NAME} pnpm sonar`;
|
|
23
|
-
}
|