contensis-cli 1.0.0-beta.95 → 1.0.0-beta.97

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.
@@ -2,6 +2,8 @@ export type EnvContentsToAdd = {
2
2
  ALIAS: string;
3
3
  PROJECT: string;
4
4
  ACCESS_TOKEN?: string;
5
+ CONTENSIS_CLIENT_ID?: string;
6
+ CONTENSIS_CLIENT_SECRET?: string;
5
7
  };
6
8
 
7
9
  export type GitHubActionPushBlockJobStep = {
@@ -24,3 +26,15 @@ export type GitHubActionPushBlockJob = {
24
26
  needs?: string;
25
27
  steps: GitHubActionPushBlockJobStep[];
26
28
  };
29
+
30
+ export type GitLabPushBlockJobStage = {
31
+ stage: string;
32
+ variables: {
33
+ alias: string;
34
+ project_id: string;
35
+ block_id: string;
36
+ image_uri?: string;
37
+ client_id: string;
38
+ shared_secret: string;
39
+ };
40
+ };
@@ -71,6 +71,10 @@ class ContensisCli {
71
71
  contensisOpts: Partial<MigrateRequest>;
72
72
  currentProject: string;
73
73
 
74
+ clientDetailsLocation?: 'env' | 'git';
75
+ clientId?: string;
76
+ clientSecret?: string;
77
+
74
78
  sourceAlias?: string;
75
79
  targetEnv?: string;
76
80
  urls:
@@ -290,6 +294,7 @@ class ContensisCli {
290
294
  | 'contentTypes'
291
295
  | 'components'
292
296
  | 'models'
297
+ | 'nodes'
293
298
  | 'user-input';
294
299
  }) => {
295
300
  const source: 'contensis' | 'file' = fromFile ? 'file' : 'contensis';
@@ -1736,6 +1741,85 @@ class ContensisCli {
1736
1741
  }
1737
1742
  };
1738
1743
 
1744
+ ImportNodes = async ({
1745
+ commit,
1746
+ fromFile,
1747
+ logOutput,
1748
+ }: {
1749
+ commit: boolean;
1750
+ fromFile: string;
1751
+ logOutput: string;
1752
+ }) => {
1753
+ const { currentEnv, currentProject, log, messages } = this;
1754
+
1755
+ const contensis = await this.ConnectContensisImport({
1756
+ commit,
1757
+ fromFile,
1758
+ importDataType: 'nodes',
1759
+ });
1760
+
1761
+ if (contensis) {
1762
+ log.line();
1763
+ if (contensis.isPreview) {
1764
+ console.log(log.successText(` -- IMPORT PREVIEW -- `));
1765
+ } else {
1766
+ console.log(log.warningText(` *** COMMITTING IMPORT *** `));
1767
+ }
1768
+
1769
+ const [err, result] = await contensis.MigrateNodes();
1770
+
1771
+ if (err) logError(err);
1772
+ else
1773
+ this.HandleFormattingAndOutput(result, () => {
1774
+ // print the migrateResult to console
1775
+ // TODO: fix
1776
+ printMigrateResult(this, result, {
1777
+ showAllEntries: logOutput === 'all',
1778
+ showChangedEntries: logOutput === 'changes',
1779
+ });
1780
+ });
1781
+
1782
+ const nodesTotalCount = result?.nodesToMigrate[currentProject].totalCount;
1783
+ const nodesCreated = result?.nodesResult?.['created'] || 0;
1784
+ const nodesUpdated = result?.nodesResult?.['updated'] || 0;
1785
+ const noChange = result.nodesToMigrate[currentProject]['no change'] !== 0;
1786
+
1787
+ if (
1788
+ !err &&
1789
+ !result.errors?.length &&
1790
+ ((!commit && nodesTotalCount) ||
1791
+ (commit && (nodesCreated || nodesUpdated)))
1792
+ ) {
1793
+ let totalCount: number;
1794
+ if (commit) {
1795
+ let created = typeof nodesCreated === 'number' ? nodesCreated : 0;
1796
+ let updated = typeof nodesUpdated === 'number' ? nodesUpdated : 0;
1797
+
1798
+ totalCount = created + updated;
1799
+ } else {
1800
+ totalCount =
1801
+ typeof nodesTotalCount === 'number' ? nodesTotalCount : 0;
1802
+ }
1803
+
1804
+ log.success(messages.nodes.imported(currentEnv, commit, totalCount));
1805
+ if (!commit) {
1806
+ log.raw(``);
1807
+ log.help(messages.nodes.commitTip());
1808
+ }
1809
+ } else {
1810
+ if (noChange) {
1811
+ log.help(messages.nodes.noChange(currentEnv), err);
1812
+ } else {
1813
+ log.error(messages.nodes.failedImport(currentEnv), err);
1814
+ if (!nodesTotalCount) log.help(messages.nodes.notFound(currentEnv));
1815
+ }
1816
+ }
1817
+ } else {
1818
+ log.warning(messages.models.noList(currentProject));
1819
+ log.help(messages.connect.tip());
1820
+ }
1821
+ };
1822
+
1739
1823
  PrintWebhookSubscriptions = async (subscriptionIdsOrNames?: string[]) => {
1740
1824
  const { currentEnv, log, messages } = this;
1741
1825
  const contensis = await this.ConnectContensis();
@@ -1,5 +1,5 @@
1
1
  import to from 'await-to-js';
2
- import { execFile, spawn } from 'child_process';
2
+ import { spawn } from 'child_process';
3
3
  import inquirer from 'inquirer';
4
4
  import path from 'path';
5
5
 
@@ -21,10 +21,13 @@ import { mergeDotEnvFileContents } from '~/util/dotenv';
21
21
  import { findByIdOrName } from '~/util/find';
22
22
  import { GitHelper } from '~/util/git';
23
23
  import { jsonFormatter } from '~/util/json.formatter';
24
- import { normaliseLineEndings, winSlash } from '~/util/os';
24
+ import { winSlash } from '~/util/os';
25
25
  import { stringifyYaml } from '~/util/yaml';
26
+ import { createSpinner } from 'nanospinner';
26
27
 
27
28
  class ContensisDev extends ContensisRole {
29
+ git!: GitHelper;
30
+
28
31
  constructor(
29
32
  args: string[],
30
33
  outputOpts?: OutputOptionsConstructorArg,
@@ -52,7 +55,7 @@ class ContensisDev extends ContensisRole {
52
55
  );
53
56
 
54
57
  // Retrieve git info
55
- const git = new GitHelper(projectHome);
58
+ const git = (this.git = new GitHelper(projectHome));
56
59
 
57
60
  // Retrieve ci workflow info
58
61
  const workflowFiles = git.workflows;
@@ -116,10 +119,39 @@ class ContensisDev extends ContensisRole {
116
119
 
117
120
  log.raw(log.infoText(messages.devinit.ciDetails(ciFileName)));
118
121
 
119
- // Look at the workflow file content and make updates
120
- const mappedWorkflow = await mapCIWorkflowContent(this, git);
122
+ let mappedWorkflow;
123
+ // Location for Client ID / Secret.
124
+ const { clientDetailsOption } = await inquirer.prompt({
125
+ name: 'clientDetailsOption',
126
+ type: 'list',
127
+ prefix: '🔑',
128
+ // Where would you like to store your Client ID/Secret?
129
+ message: messages.devinit.clientDetailsLocation(),
130
+ choices: [
131
+ messages.devinit.clientDetailsInGit(git),
132
+ messages.devinit.clientDetailsInEnv(),
133
+ ],
134
+ });
135
+
136
+ // global 'clientDetailsLocation' variable stores users input on where client id / secert are stored
137
+ if (clientDetailsOption === messages.devinit.clientDetailsInEnv()) {
138
+ this.clientDetailsLocation = 'env';
139
+ } else {
140
+ this.clientDetailsLocation = 'git';
141
+ }
121
142
 
122
- log.help(messages.devinit.ciIntro(git));
143
+ if (this.clientDetailsLocation === 'env') {
144
+ // Update CI Workflow to pull from ENV variables
145
+ mappedWorkflow = await mapCIWorkflowContent(this);
146
+ // Add client id and secret to global 'this'
147
+ this.clientId = existingDeployKey?.id;
148
+ this.clientSecret = existingDeployKey?.sharedSecret;
149
+ log.help(messages.devinit.ciIntro(git, this.clientDetailsLocation));
150
+ } else {
151
+ // Look at the workflow file content and make updates
152
+ mappedWorkflow = await mapCIWorkflowContent(this);
153
+ log.help(messages.devinit.ciIntro(git, this.clientDetailsLocation));
154
+ }
123
155
 
124
156
  if (!dryRun) {
125
157
  // Confirm prompt
@@ -136,16 +168,37 @@ class ContensisDev extends ContensisRole {
136
168
  }
137
169
 
138
170
  // Access token prompt
139
- const { accessToken }: { accessToken: string } = await inquirer.prompt([
171
+ let accessToken: string | undefined = undefined;
172
+ const { canContinue } = await inquirer.prompt([
140
173
  {
141
- type: 'input',
174
+ type: 'confirm',
142
175
  prefix: '🛡️',
176
+ // We're all set to grab your access token. Can we proceed? (⏎ continue)
143
177
  message: messages.devinit.accessTokenPrompt(),
144
- name: 'accessToken',
178
+ name: 'canContinue',
145
179
  },
146
180
  ]);
147
181
  log.raw('');
148
182
 
183
+ if (!canContinue) return;
184
+ if (canContinue) {
185
+ const spinner = createSpinner(messages.devinit.accessTokenFetch());
186
+ spinner.start();
187
+
188
+ // Fetching access token
189
+ const token = await this.GetDeliveryApiKey();
190
+
191
+ if (token) {
192
+ spinner.success();
193
+ this.log.success(messages.devinit.accessTokenSuccess(token));
194
+ accessToken = token;
195
+ } else {
196
+ spinner.error();
197
+ this.log.error(messages.devinit.accessTokenFailed());
198
+ return;
199
+ }
200
+ }
201
+
149
202
  // Magic happens...
150
203
  const checkpoint = (op: string) => {
151
204
  if (errors.length) throw errors[0];
@@ -207,6 +260,12 @@ class ContensisDev extends ContensisRole {
207
260
  PROJECT: currentProject,
208
261
  };
209
262
  if (accessToken) envContentsToAdd['ACCESS_TOKEN'] = accessToken;
263
+ if (this.clientDetailsLocation === 'env') {
264
+ if (git.type === 'github') {
265
+ envContentsToAdd['CONTENSIS_CLIENT_ID'] = this.clientId;
266
+ envContentsToAdd['CONTENSIS_CLIENT_SECRET'] = this.clientSecret;
267
+ }
268
+ }
210
269
 
211
270
  const envFilePath = `${projectHome}/.env`;
212
271
  const existingEnvFile = readFile(envFilePath);
@@ -214,9 +273,7 @@ class ContensisDev extends ContensisRole {
214
273
  (existingEnvFile || '').split('\n').filter(l => !!l),
215
274
  envContentsToAdd
216
275
  );
217
- const newEnvFileContent = normaliseLineEndings(
218
- `${envFileLines.join('\n')}\n`
219
- );
276
+ const newEnvFileContent = envFileLines.join('\n');
220
277
  const envDiff = diffFileContent(existingEnvFile || '', newEnvFileContent);
221
278
 
222
279
  if (dryRun) {
@@ -258,15 +315,17 @@ class ContensisDev extends ContensisRole {
258
315
  }
259
316
  }
260
317
 
261
- // Echo Deployment API key to console, ask user to add secrets to repo
262
- log.warning(messages.devinit.addGitSecretsIntro());
263
- log.help(
264
- messages.devinit.addGitSecretsHelp(
265
- git,
266
- existingDeployKey?.id,
267
- existingDeployKey?.sharedSecret
268
- )
269
- );
318
+ if (this.clientDetailsLocation === 'git') {
319
+ // Echo Deployment API key to console, ask user to add secrets to repo
320
+ log.warning(messages.devinit.addGitSecretsIntro());
321
+ log.help(
322
+ messages.devinit.addGitSecretsHelp(
323
+ git,
324
+ existingDeployKey?.id,
325
+ existingDeployKey?.sharedSecret
326
+ )
327
+ );
328
+ }
270
329
 
271
330
  if (dryRun) {
272
331
  log.success(messages.devinit.dryRun());
@@ -1,8 +1,9 @@
1
1
  import { Role } from 'contensis-management-api/lib/models';
2
2
  import { ApiKey, MigrateRequest } from 'migratortron';
3
-
3
+ import to from 'await-to-js';
4
4
  import ContensisCli from './ContensisCliService';
5
5
  import { OutputOptionsConstructorArg } from '~/models/CliService';
6
+ import { Logger } from '~/util/logger';
6
7
 
7
8
  class ContensisRole extends ContensisCli {
8
9
  constructor(
@@ -13,6 +14,37 @@ class ContensisRole extends ContensisCli {
13
14
  super(args, outputOpts, contensisOpts);
14
15
  }
15
16
 
17
+ GetDeliveryApiKey = async () => {
18
+ const { contensis, currentEnv } = this;
19
+
20
+ const CMS = `https://cms-${currentEnv}.cloud.contensis.com`;
21
+ const API = 'api/contensis-cli/settings/defaultDeliveryApiAccessToken';
22
+
23
+ if (contensis) {
24
+ const [error, bearerToken] = await to(
25
+ contensis.content.sourceRepo.repo.BearerToken()
26
+ );
27
+ if (error) Logger.error(error.message);
28
+
29
+ const token = fetch(`${CMS}/${API}`, {
30
+ method: 'GET',
31
+ headers: {
32
+ 'Content-Type': 'application/json',
33
+ Authorization: `Bearer ${bearerToken}`,
34
+ },
35
+ })
36
+ .then(repsonse => repsonse.json())
37
+ .then(({ value }) => {
38
+ if (value) return value;
39
+ })
40
+ .catch(error => {
41
+ throw new Error(error);
42
+ });
43
+
44
+ return token;
45
+ }
46
+ };
47
+
16
48
  CreateOrUpdateApiKey = async (
17
49
  existingKey: ApiKey | undefined,
18
50
  name: string,
package/src/util/diff.ts CHANGED
@@ -47,7 +47,10 @@ export const diffFileContent = (
47
47
  const colour = part.added ? 'green' : part.removed ? 'red' : 'grey';
48
48
 
49
49
  if (part.value !== '\n') {
50
- if (needsNewLine) output.push('\n### --');
50
+ if (needsNewLine) {
51
+ output.push('\n### --');
52
+ needsNewLine = false;
53
+ }
51
54
  output.push(
52
55
  `\n${part.value
53
56
  .split('\n')
package/src/util/git.ts CHANGED
@@ -111,13 +111,14 @@ export class GitHelper {
111
111
  githubWorkflows = () => {
112
112
  const workflowPath = path.join(this.gitcwd(), '.github/workflows');
113
113
  const workflowFiles = readFiles(workflowPath, false);
114
- // console.log('gh workflows: ', workflowFiles);
115
114
  const addFolderSuffix = (files: string[]) =>
116
115
  files.map(f => `.github/workflows/${f}`);
117
116
 
118
- if (workflowFiles.some(f => f.includes('build')))
117
+ if (workflowFiles.some(f => f.includes('build'))) {
119
118
  return addFolderSuffix(workflowFiles.filter(f => f.includes('build')));
120
- return addFolderSuffix(workflowFiles);
119
+ } else {
120
+ return addFolderSuffix(workflowFiles);
121
+ }
121
122
  };
122
123
  gitlabWorkflow = (ciFileName = GITLAB_CI_FILENAME) => {
123
124
  const workflowPath = this.gitcwd();
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const LIB_VERSION = "1.0.0-beta.95";
1
+ export const LIB_VERSION = "1.0.0-beta.97";