@contentstack/cli-cm-clone 1.1.6 → 1.2.0

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/README.md CHANGED
@@ -14,8 +14,8 @@ It is Contentstack’s CLI plugin to clone a stack. Using this command, you can
14
14
  $ npm install -g @contentstack/cli-cm-clone
15
15
  $ csdx COMMAND
16
16
  running command...
17
- $ csdx (-v|--version|version)
18
- @contentstack/cli-cm-clone/1.1.6 linux-x64 node-v16.18.1
17
+ $ csdx (--version)
18
+ @contentstack/cli-cm-clone/1.2.0 linux-x64 node-v16.19.0
19
19
  $ csdx --help [COMMAND]
20
20
  USAGE
21
21
  $ csdx COMMAND
@@ -34,6 +34,7 @@ USAGE
34
34
  # Commands
35
35
  <!-- commands -->
36
36
  * [`csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]`](#csdx-cmstacksclone---source-branch-value---target-branch-value---source-management-token-alias-value---destination-management-token-alias-value--n-value---type-ab---source-stack-api-key-value---destination-stack-api-key-value---import-webhook-status-disablecurrent)
37
+ * [`csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]`](#csdx-cmstacksclone---source-branch-value---target-branch-value---source-management-token-alias-value---destination-management-token-alias-value--n-value---type-ab---source-stack-api-key-value---destination-stack-api-key-value---import-webhook-status-disablecurrent-1)
37
38
 
38
39
  ## `csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]`
39
40
 
@@ -41,54 +42,96 @@ Clone data (structure/content or both) of a stack into another stack
41
42
 
42
43
  ```
43
44
  USAGE
44
- $ csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>]
45
- [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>]
46
- [--destination-stack-api-key <value>] [--import-webhook-status disable|current]
45
+ $ csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>]
46
+ [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>]
47
+ [--destination-stack-api-key <value>] [--import-webhook-status disable|current]
48
+
49
+ FLAGS
50
+ -n, --stack-name=<value> Name for the new stack to store the cloned content.
51
+ -y, --yes [Optional] Override marketplace prompts
52
+ --destination-management-token-alias=<value> Source API key of the target stack token alias.
53
+ --destination-stack-api-key=<value> Destination stack API Key
54
+ --import-webhook-status=<option> [default: disable] [Optional] Webhook state
55
+ <options: disable|current>
56
+ --source-branch=<value> Branch of the source stack.
57
+ --source-management-token-alias=<value> Source API key of the target stack token alias.
58
+ --source-stack-api-key=<value> Source stack API Key
59
+ --target-branch=<value> Branch of the target stack.
60
+ --type=<option> Type of data to clone
61
+ a) Structure (all modules except entries & assets)
62
+ b) Structure with content (all modules including entries & assets)
63
+
64
+ <options: a|b>
47
65
 
48
- OPTIONS
49
- -n, --stack-name=stack-name Name for the new stack to store the cloned
50
- content.
66
+ DESCRIPTION
67
+ Clone data (structure/content or both) of a stack into another stack
68
+ Use this plugin to automate the process of cloning a stack in few steps.
51
69
 
52
- -y, --yes [Optional] Override marketplace prompts
53
70
 
54
- --destination-management-token-alias=destination-management-token-alias Source API key of the target stack token
55
- alias.
71
+ ALIASES
72
+ $ csdx cm:stack-clone
56
73
 
57
- --destination-stack-api-key=destination-stack-api-key Destination stack API Key
74
+ EXAMPLES
75
+ $ csdx cm:stacks:clone
58
76
 
59
- --import-webhook-status=disable|current [default: disable] [Optional] Webhook state
77
+ $ csdx cm:stacks:clone --source-branch <source-branch-name> --target-branch <target-branch-name> --yes
60
78
 
61
- --source-branch=source-branch Branch of the source stack.
79
+ $ csdx cm:stacks:clone --source-stack-api-key <apiKey> --destination-stack-api-key <apiKey>
62
80
 
63
- --source-management-token-alias=source-management-token-alias Source API key of the target stack token
64
- alias.
81
+ $ csdx cm:stacks:clone --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>
65
82
 
66
- --source-stack-api-key=source-stack-api-key Source stack API Key
83
+ $ csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>
84
+
85
+ $ csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias> --type <value a or b>
86
+ ```
87
+
88
+ ## `csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]`
67
89
 
68
- --target-branch=target-branch Branch of the target stack.
90
+ Clone data (structure/content or both) of a stack into another stack
69
91
 
70
- --type=a|b Type of data to clone
71
- a) Structure (all modules except entries &
72
- assets)
73
- b) Structure with content (all modules
74
- including entries & assets)
92
+ ```
93
+ USAGE
94
+ $ csdx cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>]
95
+ [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>]
96
+ [--destination-stack-api-key <value>] [--import-webhook-status disable|current]
97
+
98
+ FLAGS
99
+ -n, --stack-name=<value> Name for the new stack to store the cloned content.
100
+ -y, --yes [Optional] Override marketplace prompts
101
+ --destination-management-token-alias=<value> Source API key of the target stack token alias.
102
+ --destination-stack-api-key=<value> Destination stack API Key
103
+ --import-webhook-status=<option> [default: disable] [Optional] Webhook state
104
+ <options: disable|current>
105
+ --source-branch=<value> Branch of the source stack.
106
+ --source-management-token-alias=<value> Source API key of the target stack token alias.
107
+ --source-stack-api-key=<value> Source stack API Key
108
+ --target-branch=<value> Branch of the target stack.
109
+ --type=<option> Type of data to clone
110
+ a) Structure (all modules except entries & assets)
111
+ b) Structure with content (all modules including entries & assets)
112
+
113
+ <options: a|b>
75
114
 
76
115
  DESCRIPTION
116
+ Clone data (structure/content or both) of a stack into another stack
77
117
  Use this plugin to automate the process of cloning a stack in few steps.
78
118
 
119
+
79
120
  ALIASES
80
121
  $ csdx cm:stack-clone
81
122
 
82
123
  EXAMPLES
83
- csdx cm:stacks:clone
84
- csdx cm:stacks:clone --source-branch <source-branch-name> --target-branch <target-branch-name> --yes
85
- csdx cm:stacks:clone --source-stack-api-key <apiKey> --destination-stack-api-key <apiKey>
86
- csdx cm:stacks:clone --source-management-token-alias <management token alias> --destination-management-token-alias
87
- <management token alias>
88
- csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias>
89
- --destination-management-token-alias <management token alias>
90
- csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias>
91
- --destination-management-token-alias <management token alias> --type <value a or b>
124
+ $ csdx cm:stacks:clone
125
+
126
+ $ csdx cm:stacks:clone --source-branch <source-branch-name> --target-branch <target-branch-name> --yes
127
+
128
+ $ csdx cm:stacks:clone --source-stack-api-key <apiKey> --destination-stack-api-key <apiKey>
129
+
130
+ $ csdx cm:stacks:clone --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>
131
+
132
+ $ csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>
133
+
134
+ $ csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias> --type <value a or b>
92
135
  ```
93
136
 
94
137
  _See code: [src/commands/cm/stacks/clone.js](https://github.com/contentstack/cli/blob/main/packages/contentstack-clone/src/commands/cm/stacks/clone.js)_
@@ -1 +1,107 @@
1
- {"version":"1.1.6","commands":{"cm:stacks:clone":{"id":"cm:stacks:clone","description":"Clone data (structure/content or both) of a stack into another stack\nUse this plugin to automate the process of cloning a stack in few steps.\n","usage":"cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]","pluginName":"@contentstack/cli-cm-clone","pluginType":"core","aliases":["cm:stack-clone"],"examples":["csdx cm:stacks:clone","csdx cm:stacks:clone --source-branch <source-branch-name> --target-branch <target-branch-name> --yes","csdx cm:stacks:clone --source-stack-api-key <apiKey> --destination-stack-api-key <apiKey>","csdx cm:stacks:clone --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>","csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>","csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias> --type <value a or b>"],"flags":{"source-branch":{"name":"source-branch","type":"option","description":"Branch of the source stack.","required":false},"target-branch":{"name":"target-branch","type":"option","description":"Branch of the target stack.","required":false},"source-management-token-alias":{"name":"source-management-token-alias","type":"option","description":"Source API key of the target stack token alias.","required":false},"destination-management-token-alias":{"name":"destination-management-token-alias","type":"option","description":"Source API key of the target stack token alias.","required":false},"stack-name":{"name":"stack-name","type":"option","char":"n","description":"Name for the new stack to store the cloned content.","required":false},"type":{"name":"type","type":"option","description":"Type of data to clone\na) Structure (all modules except entries & assets)\nb) Structure with content (all modules including entries & assets)\n ","required":false,"options":["a","b"]},"source-stack-api-key":{"name":"source-stack-api-key","type":"option","description":"Source stack API Key"},"destination-stack-api-key":{"name":"destination-stack-api-key","type":"option","description":"Destination stack API Key"},"import-webhook-status":{"name":"import-webhook-status","type":"option","description":"[Optional] Webhook state","required":false,"options":["disable","current"],"default":"disable"},"yes":{"name":"yes","type":"boolean","char":"y","description":"[Optional] Override marketplace prompts","required":false,"allowNo":false}},"args":[]}}}
1
+ {
2
+ "version": "1.2.0",
3
+ "commands": {
4
+ "cm:stacks:clone": {
5
+ "id": "cm:stacks:clone",
6
+ "description": "Clone data (structure/content or both) of a stack into another stack\nUse this plugin to automate the process of cloning a stack in few steps.\n",
7
+ "strict": true,
8
+ "usage": "cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]",
9
+ "pluginName": "@contentstack/cli-cm-clone",
10
+ "pluginAlias": "@contentstack/cli-cm-clone",
11
+ "pluginType": "core",
12
+ "aliases": [
13
+ "cm:stack-clone"
14
+ ],
15
+ "examples": [
16
+ "csdx cm:stacks:clone",
17
+ "csdx cm:stacks:clone --source-branch <source-branch-name> --target-branch <target-branch-name> --yes",
18
+ "csdx cm:stacks:clone --source-stack-api-key <apiKey> --destination-stack-api-key <apiKey>",
19
+ "csdx cm:stacks:clone --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>",
20
+ "csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>",
21
+ "csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias> --type <value a or b>"
22
+ ],
23
+ "flags": {
24
+ "source-branch": {
25
+ "name": "source-branch",
26
+ "type": "option",
27
+ "description": "Branch of the source stack.",
28
+ "required": false,
29
+ "multiple": false
30
+ },
31
+ "target-branch": {
32
+ "name": "target-branch",
33
+ "type": "option",
34
+ "description": "Branch of the target stack.",
35
+ "required": false,
36
+ "multiple": false
37
+ },
38
+ "source-management-token-alias": {
39
+ "name": "source-management-token-alias",
40
+ "type": "option",
41
+ "description": "Source API key of the target stack token alias.",
42
+ "required": false,
43
+ "multiple": false
44
+ },
45
+ "destination-management-token-alias": {
46
+ "name": "destination-management-token-alias",
47
+ "type": "option",
48
+ "description": "Source API key of the target stack token alias.",
49
+ "required": false,
50
+ "multiple": false
51
+ },
52
+ "stack-name": {
53
+ "name": "stack-name",
54
+ "type": "option",
55
+ "char": "n",
56
+ "description": "Name for the new stack to store the cloned content.",
57
+ "required": false,
58
+ "multiple": false
59
+ },
60
+ "type": {
61
+ "name": "type",
62
+ "type": "option",
63
+ "description": "Type of data to clone\na) Structure (all modules except entries & assets)\nb) Structure with content (all modules including entries & assets)\n ",
64
+ "required": false,
65
+ "multiple": false,
66
+ "options": [
67
+ "a",
68
+ "b"
69
+ ]
70
+ },
71
+ "source-stack-api-key": {
72
+ "name": "source-stack-api-key",
73
+ "type": "option",
74
+ "description": "Source stack API Key",
75
+ "multiple": false
76
+ },
77
+ "destination-stack-api-key": {
78
+ "name": "destination-stack-api-key",
79
+ "type": "option",
80
+ "description": "Destination stack API Key",
81
+ "multiple": false
82
+ },
83
+ "import-webhook-status": {
84
+ "name": "import-webhook-status",
85
+ "type": "option",
86
+ "description": "[Optional] Webhook state",
87
+ "required": false,
88
+ "multiple": false,
89
+ "options": [
90
+ "disable",
91
+ "current"
92
+ ],
93
+ "default": "disable"
94
+ },
95
+ "yes": {
96
+ "name": "yes",
97
+ "type": "boolean",
98
+ "char": "y",
99
+ "description": "[Optional] Override marketplace prompts",
100
+ "required": false,
101
+ "allowNo": false
102
+ }
103
+ },
104
+ "args": {}
105
+ }
106
+ }
107
+ }
package/package.json CHANGED
@@ -1,19 +1,17 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-clone",
3
3
  "description": "Contentstack stack clone plugin",
4
- "version": "1.1.6",
4
+ "version": "1.2.0",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/rohitmishra209/cli-cm-clone/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-cm-export": "^1.2.3",
9
- "@contentstack/cli-cm-import": "^1.2.4",
10
- "@contentstack/cli-command": "^1.0.4",
11
- "@contentstack/cli-utilities": "^1.0.5",
12
- "@contentstack/management": "^1.6.0",
13
- "@oclif/command": "^1.8.16",
14
- "@oclif/config": "^1.18.3",
15
- "chalk": "^4.1.0",
8
+ "@contentstack/cli-cm-export": "^1.3.0",
9
+ "@contentstack/cli-cm-import": "^1.3.0",
10
+ "@contentstack/cli-command": "^1.1.0",
11
+ "@contentstack/cli-utilities": "^1.1.0",
12
+ "@contentstack/management": "^1.6.1",
16
13
  "async": "^3.2.4",
14
+ "chalk": "^4.1.0",
17
15
  "child_process": "^1.0.2",
18
16
  "fancy-test": "^1.4.10",
19
17
  "inquirer": "8.2.4",
@@ -22,7 +20,7 @@
22
20
  "winston": "^3.7.2"
23
21
  },
24
22
  "devDependencies": {
25
- "@oclif/dev-cli": "^1.22.2",
23
+ "oclif": "^3.1.2",
26
24
  "@oclif/test": "^1.2.7",
27
25
  "chai": "^4.2.0",
28
26
  "eslint": "^8.18.0",
@@ -31,7 +29,7 @@
31
29
  "jest": "^26.6.3",
32
30
  "mocha": "^10.0.0",
33
31
  "nyc": "^15.1.0",
34
- "sinon": "^9.2.4"
32
+ "sinon": "^15.0.1"
35
33
  },
36
34
  "engines": {
37
35
  "node": ">=8.0.0"
@@ -56,10 +54,10 @@
56
54
  "repository": "https://github.com/contentstack/cli",
57
55
  "scripts": {
58
56
  "postpack": "rm -f oclif.manifest.json",
59
- "prepack": "oclif-dev manifest && oclif-dev readme",
57
+ "prepack": "oclif manifest && oclif readme",
60
58
  "test": "nyc --reporter=html mocha --forbid-only \"test/**/*.test.js\"",
61
59
  "posttest": "eslint .",
62
- "version": "oclif-dev readme && git add README.md"
60
+ "version": "oclif readme && git add README.md"
63
61
  },
64
62
  "csdxConfig": {
65
63
  "expiredCommands": {
@@ -12,7 +12,7 @@ class StackCloneCommand extends Command {
12
12
  try {
13
13
  let self = this;
14
14
  let _authToken = configHandler.get('authtoken');
15
- const cloneCommandFlags = self.parse(StackCloneCommand).flags;
15
+ const { flags: cloneCommandFlags } = await self.parse(StackCloneCommand);
16
16
  const {
17
17
  yes,
18
18
  type: cloneType,
@@ -6,9 +6,7 @@ const chalk = require('chalk');
6
6
 
7
7
  let exportCmd = require('@contentstack/cli-cm-export');
8
8
  let importCmd = require('@contentstack/cli-cm-import');
9
- const { HttpClient } = require('@contentstack/cli-utilities');
10
9
  let sdkInstance = require('../../lib/util/contentstack-management-sdk');
11
- const defaultConfig = require('@contentstack/cli-cm-export/src/config/default');
12
10
  const { CustomAbortController } = require('./abort-controller');
13
11
 
14
12
  const {
@@ -138,35 +136,32 @@ class CloneHandler {
138
136
 
139
137
  handleBranchSelection = async (options) => {
140
138
  const { api_key, isSource = true, returnBranch = false } = options;
141
- const baseUrl = defaultConfig.host.startsWith('http') ? defaultConfig.host : `https://${defaultConfig.host}/v3`;
142
-
143
139
  return new Promise(async (resolve, reject) => {
140
+ let spinner;
144
141
  try {
145
- const headers = { api_key };
146
-
147
- if (config.auth_token) {
148
- headers['authtoken'] = config.auth_token;
149
- } else if (config.management_token) {
150
- headers['authorization'] = config.management_token;
151
- }
142
+ const stackAPIClient = client.stack({
143
+ api_key: config.source_stack,
144
+ management_token: config.management_token,
145
+ });
152
146
 
153
147
  // NOTE validate if source branch is exist
154
148
  if (isSource && config.sourceStackBranch) {
155
- await this.validateIfBranchExist(headers, true);
149
+ await this.validateIfBranchExist(stackAPIClient, true);
156
150
  return resolve();
157
151
  }
158
152
 
159
153
  // NOTE Validate target branch is exist
160
154
  if (!isSource && config.targetStackBranch) {
161
- await this.validateIfBranchExist(headers, false);
155
+ await this.validateIfBranchExist(stackAPIClient, false);
162
156
  return resolve();
163
157
  }
164
-
165
- const spinner = ora('Fetching Branches').start();
166
- const result = await new HttpClient()
167
- .headers(headers)
168
- .get(`${baseUrl}/stacks/branches`)
169
- .then(({ data: { branches } }) => branches);
158
+ spinner = ora('Fetching Branches').start();
159
+ const result = await stackAPIClient
160
+ .branch()
161
+ .query()
162
+ .find()
163
+ .then(({ items }) => items)
164
+ .catch((_err) => {});
170
165
 
171
166
  const condition = result && Array.isArray(result) && result.length > 0;
172
167
 
@@ -196,31 +191,36 @@ class CloneHandler {
196
191
  resolve();
197
192
  }
198
193
  } catch (e) {
199
- spinner.fail();
200
- console.log(e && e.message);
201
- resolve();
194
+ if (spinner) spinner.fail();
195
+ console.error(e && e.message);
196
+ return reject(e);
202
197
  }
203
198
  });
204
199
  };
205
200
 
206
- async validateIfBranchExist(headers, isSource) {
207
- const branch = isSource ? config.sourceStackBranch : config.targetStackBranch;
208
- const spinner = ora(`Validation if ${isSource ? 'source' : 'target'} branch exist.!`).start();
209
- const isBranchExist = await HttpClient.create()
210
- .headers(headers)
211
- .get(`https://${config.host}/v3/stacks/branches/${branch}`)
212
- .then(({ data }) => data);
213
-
201
+ async validateIfBranchExist(stackAPIClient, isSource) {
202
+ let spinner;
214
203
  const completeSpinner = (msg, method = 'succeed') => {
215
204
  spinner[method](msg);
216
205
  spinner.stop();
217
206
  };
218
-
219
- if (isBranchExist && typeof isBranchExist === 'object' && typeof isBranchExist.branch === 'object') {
220
- completeSpinner(`${isSource ? 'Source' : 'Target'} branch verified.!`);
221
- } else {
207
+ try {
208
+ const branch = isSource ? config.sourceStackBranch : config.targetStackBranch;
209
+ spinner = ora(`Validation if ${isSource ? 'source' : 'target'} branch exist.!`).start();
210
+ const isBranchExist = await stackAPIClient
211
+ .branch(branch)
212
+ .fetch()
213
+ .then((data) => data);
214
+
215
+ if (isBranchExist && typeof isBranchExist === 'object') {
216
+ completeSpinner(`${isSource ? 'Source' : 'Target'} branch verified.!`);
217
+ } else {
218
+ completeSpinner(`${isSource ? 'Source' : 'Target'} branch not found.!`, 'fail');
219
+ process.exit();
220
+ }
221
+ } catch (e) {
222
222
  completeSpinner(`${isSource ? 'Source' : 'Target'} branch not found.!`, 'fail');
223
- process.exit();
223
+ throw e;
224
224
  }
225
225
  }
226
226
 
@@ -329,7 +329,12 @@ class CloneHandler {
329
329
  async setBranch() {
330
330
  if (!config.sourceStackBranch) {
331
331
  try {
332
- const branches = await client.stack({ api_key: config.source_stack }).branch().query().find();
332
+ const branches = await client
333
+ .stack({ api_key: config.source_stack })
334
+ .branch()
335
+ .query()
336
+ .find()
337
+ .catch((_err) => {});
333
338
 
334
339
  if (branches && branches.items && branches.items.length) {
335
340
  config.sourceStackBranch = 'main';