@slicemachine/init 1.1.9 → 1.1.10-alpha.11
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/build/index.js +431 -141
- package/build/index.js.map +1 -1
- package/jest.config.js +1 -0
- package/package.json +7 -4
- package/src/index.ts +41 -27
- package/src/steps/choose-or-create-a-repository.ts +43 -42
- package/src/steps/configure-project.ts +17 -8
- package/src/steps/display-final-message.ts +23 -4
- package/src/steps/index.ts +1 -0
- package/src/steps/install-required-dependencies.ts +29 -10
- package/src/steps/loginOrBypass.ts +18 -14
- package/src/steps/sendStarterData.ts +31 -0
- package/src/steps/starters/custom-types.ts +81 -0
- package/src/steps/starters/documents.ts +89 -0
- package/src/steps/starters/prompts.ts +29 -0
- package/src/steps/starters/s3.ts +70 -0
- package/src/steps/starters/slices.ts +75 -0
- package/src/utils/auth/helpers.ts +5 -1
- package/src/utils/auth/index.ts +30 -30
- package/src/utils/client.ts +67 -0
- package/src/utils/create-repo.ts +9 -15
- package/src/utils/fs.ts +18 -0
- package/src/utils/index.ts +21 -0
- package/src/utils/validateRepositoryName.ts +44 -0
- package/.caches/eslint +0 -1
- package/src/utils/communication.ts +0 -72
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import * as inquirer from "inquirer";
|
|
2
2
|
import Separator from "inquirer/lib/objects/separator";
|
|
3
|
-
import {
|
|
4
|
-
import * as Prismic from "@slicemachine/core/build/prismic";
|
|
3
|
+
import { Models } from "@slicemachine/core";
|
|
5
4
|
import * as NodeUtils from "@slicemachine/core/build/node-utils";
|
|
6
5
|
import { createRepository } from "../utils/create-repo";
|
|
7
|
-
import {
|
|
6
|
+
import { validateRepositoryName } from "../utils/validateRepositoryName";
|
|
7
|
+
import { InitClient, logs } from "../utils";
|
|
8
8
|
|
|
9
9
|
export const CREATE_REPO = "$_CREATE_REPO"; // not a valid domain name
|
|
10
|
-
const DEFAULT_BASE = CONSTS.DEFAULT_BASE;
|
|
11
10
|
|
|
12
|
-
export function prettyRepoName(address: URL,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
)}`;
|
|
11
|
+
export function prettyRepoName(address: URL, domain: string): string {
|
|
12
|
+
return `${logs.cyan.dim(`${address.protocol}//`)}${logs.cyan(
|
|
13
|
+
domain
|
|
14
|
+
)}${logs.cyan.dim(`.${address.hostname}`)}`;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
export async function promptForRepoDomain(
|
|
20
|
-
|
|
18
|
+
client: InitClient,
|
|
21
19
|
defaultValue?: string
|
|
22
20
|
): Promise<string> {
|
|
23
|
-
const address = new URL(
|
|
21
|
+
const address = new URL(client.apisEndpoints.Wroom);
|
|
24
22
|
|
|
25
23
|
logs.writeInfo(
|
|
26
24
|
"The name acts as a domain/endpoint for your content repo and should be completely unique."
|
|
@@ -34,16 +32,9 @@ export async function promptForRepoDomain(
|
|
|
34
32
|
type: "input",
|
|
35
33
|
required: true,
|
|
36
34
|
default: defaultValue,
|
|
37
|
-
transformer: (value: string) =>
|
|
38
|
-
prettyRepoName(address, value || defaultValue),
|
|
39
|
-
|
|
40
|
-
const result = await Prismic.Communication.validateRepositoryName(
|
|
41
|
-
name,
|
|
42
|
-
base,
|
|
43
|
-
false
|
|
44
|
-
);
|
|
45
|
-
return result === name || result;
|
|
46
|
-
},
|
|
35
|
+
transformer: (value: string | undefined) =>
|
|
36
|
+
prettyRepoName(address, value || defaultValue || "repository"),
|
|
37
|
+
validate: (name: string) => validateRepositoryName(client, name),
|
|
47
38
|
},
|
|
48
39
|
])
|
|
49
40
|
.then((res) => res.repoDomain);
|
|
@@ -122,47 +113,57 @@ export function sortReposForPrompt(
|
|
|
122
113
|
}
|
|
123
114
|
|
|
124
115
|
export async function chooseOrCreateARepository(
|
|
116
|
+
client: InitClient,
|
|
125
117
|
cwd: string,
|
|
126
118
|
framework: Models.Frameworks,
|
|
127
|
-
|
|
128
|
-
base = DEFAULT_BASE,
|
|
129
|
-
domain?: string
|
|
119
|
+
preSelectedRepository?: string
|
|
130
120
|
): Promise<string> {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
121
|
+
const repositories: Models.Repository[] = await client.listRepositories();
|
|
122
|
+
|
|
123
|
+
const isPreSelectedValid =
|
|
124
|
+
preSelectedRepository &&
|
|
125
|
+
repositories.find(
|
|
126
|
+
(repository) => repository.domain === preSelectedRepository
|
|
127
|
+
);
|
|
128
|
+
if (isPreSelectedValid) return preSelectedRepository;
|
|
129
|
+
|
|
130
|
+
// No repository to display, ask for a new repository name to create it.
|
|
131
|
+
if (repositories.length === 0) {
|
|
132
|
+
const domainName = await promptForRepoDomain(client, preSelectedRepository);
|
|
133
|
+
await createRepository(client, domainName, framework);
|
|
134
|
+
return domainName;
|
|
140
135
|
}
|
|
141
136
|
|
|
142
|
-
|
|
143
|
-
|
|
137
|
+
// prepare the list of repositories to display
|
|
138
|
+
const choices = sortReposForPrompt(
|
|
139
|
+
repositories,
|
|
140
|
+
client.apisEndpoints.Wroom,
|
|
141
|
+
cwd
|
|
142
|
+
);
|
|
144
143
|
const numberOfDisabledRepos = choices.filter((repo) => {
|
|
145
144
|
if (repo instanceof Separator) return false;
|
|
146
145
|
return repo.disabled;
|
|
147
146
|
}).length;
|
|
148
147
|
|
|
149
|
-
|
|
148
|
+
// display the list of repositories and wait for the user to choose one.
|
|
149
|
+
const promptResult = await inquirer.prompt<{ chosenRepository: string }>([
|
|
150
150
|
{
|
|
151
151
|
type: "list",
|
|
152
|
-
name: "
|
|
152
|
+
name: "chosenRepository",
|
|
153
153
|
default: 0,
|
|
154
154
|
required: true,
|
|
155
155
|
message: "Connect a Prismic Repository or create a new one",
|
|
156
156
|
choices,
|
|
157
157
|
pageSize: numberOfDisabledRepos + 2 <= 7 ? 7 : numberOfDisabledRepos + 2,
|
|
158
|
-
// loop: false
|
|
159
158
|
},
|
|
160
159
|
]);
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
// If the user has chosen to create a new repository.
|
|
162
|
+
if (promptResult.chosenRepository === CREATE_REPO) {
|
|
163
|
+
const domainName = await promptForRepoDomain(client, preSelectedRepository);
|
|
164
|
+
await createRepository(client, domainName, framework);
|
|
165
|
+
return domainName;
|
|
165
166
|
}
|
|
166
167
|
|
|
167
|
-
return
|
|
168
|
+
return promptResult.chosenRepository;
|
|
168
169
|
}
|
|
@@ -3,23 +3,22 @@ import type { Models } from "@slicemachine/core";
|
|
|
3
3
|
import * as Prismic from "@slicemachine/core/build/prismic";
|
|
4
4
|
import * as NodeUtils from "@slicemachine/core/build/node-utils";
|
|
5
5
|
import { FrameworkResult } from "./detect-framework";
|
|
6
|
-
import { logs } from "../utils";
|
|
6
|
+
import { InitClient, logs } from "../utils";
|
|
7
7
|
import Tracker from "../utils/tracker";
|
|
8
8
|
|
|
9
|
-
type Base = Prismic.Endpoints.Base;
|
|
10
|
-
|
|
11
9
|
const defaultSliceMachineVersion = "0.0.41";
|
|
12
10
|
|
|
13
11
|
export async function configureProject(
|
|
12
|
+
client: InitClient,
|
|
14
13
|
cwd: string,
|
|
15
|
-
base: Base,
|
|
16
14
|
repositoryDomainName: string,
|
|
17
15
|
framework: FrameworkResult,
|
|
18
16
|
sliceLibPath: string[] = [],
|
|
19
17
|
tracking = true
|
|
20
18
|
): Promise<void> {
|
|
19
|
+
const frameworkName = NodeUtils.Framework.fancyName(framework.value);
|
|
21
20
|
const spinner = logs.spinner(
|
|
22
|
-
`Configuring your ${
|
|
21
|
+
`Configuring your ${frameworkName} and Prismic project...`
|
|
23
22
|
);
|
|
24
23
|
spinner.start();
|
|
25
24
|
|
|
@@ -32,15 +31,22 @@ export async function configureProject(
|
|
|
32
31
|
|
|
33
32
|
const manifestAlreadyExistWithContent = manifest.exists && manifest.content;
|
|
34
33
|
|
|
34
|
+
const libs =
|
|
35
|
+
manifest.content &&
|
|
36
|
+
manifest.content.libraries &&
|
|
37
|
+
manifest.content.libraries.length > 0
|
|
38
|
+
? manifest.content.libraries
|
|
39
|
+
: ["@/slices"];
|
|
40
|
+
|
|
35
41
|
const manifestUpdated: Models.Manifest = {
|
|
36
42
|
...(manifestAlreadyExistWithContent
|
|
37
43
|
? manifest.content
|
|
38
44
|
: { _latest: sliceMachineVersionInstalled }),
|
|
39
45
|
apiEndpoint: Prismic.Endpoints.buildRepositoryEndpoint(
|
|
40
|
-
|
|
46
|
+
client.apisEndpoints.Wroom,
|
|
41
47
|
repositoryDomainName
|
|
42
48
|
),
|
|
43
|
-
libraries: [
|
|
49
|
+
libraries: [...libs, ...sliceLibPath], // odd case here for staters
|
|
44
50
|
...(framework.manuallyAdded ? { framework: framework.value } : {}),
|
|
45
51
|
...(!tracking ? { tracking } : {}),
|
|
46
52
|
};
|
|
@@ -52,7 +58,10 @@ export async function configureProject(
|
|
|
52
58
|
const pathToSlicesFolder = NodeUtils.CustomPaths(cwd)
|
|
53
59
|
.library("slices")
|
|
54
60
|
.value();
|
|
55
|
-
if (
|
|
61
|
+
if (
|
|
62
|
+
!NodeUtils.Files.exists(pathToSlicesFolder) &&
|
|
63
|
+
libs.includes("@/slices")
|
|
64
|
+
) {
|
|
56
65
|
NodeUtils.Files.mkdir(pathToSlicesFolder, { recursive: true });
|
|
57
66
|
}
|
|
58
67
|
|
|
@@ -2,11 +2,30 @@ import { CONSTS } from "@slicemachine/core";
|
|
|
2
2
|
import * as NodeUtils from "@slicemachine/core/build/node-utils";
|
|
3
3
|
import { logs } from "../utils";
|
|
4
4
|
|
|
5
|
-
export function displayFinalMessage(
|
|
5
|
+
export function displayFinalMessage(
|
|
6
|
+
cwd: string,
|
|
7
|
+
wasStarter: boolean,
|
|
8
|
+
reponame: string,
|
|
9
|
+
base: string
|
|
10
|
+
): void {
|
|
6
11
|
const yarnLock = NodeUtils.Files.exists(NodeUtils.YarnLockPath(cwd));
|
|
7
12
|
const command = `${yarnLock ? "yarn" : "npm"} run ${CONSTS.SCRIPT_NAME}`;
|
|
13
|
+
console.log();
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
if (wasStarter) {
|
|
16
|
+
const repoUrl = new URL(base);
|
|
17
|
+
repoUrl.hostname = `${reponame}.${repoUrl.hostname}`;
|
|
18
|
+
const urlAsString = repoUrl.toString();
|
|
19
|
+
|
|
20
|
+
const message = `${logs.white(
|
|
21
|
+
"■"
|
|
22
|
+
)} Start editing your content in Prismic ${logs.purple(urlAsString)}`;
|
|
23
|
+
console.log(message);
|
|
24
|
+
} else {
|
|
25
|
+
console.log(
|
|
26
|
+
`${logs.white("■")} Run ${logs.purple(
|
|
27
|
+
command
|
|
28
|
+
)} to launch Slice Machine and create your first Custom Type`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
12
31
|
}
|
package/src/steps/index.ts
CHANGED
|
@@ -32,18 +32,14 @@ function depsForFramework(framework: Models.Frameworks): string {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
): Promise<
|
|
39
|
-
const
|
|
40
|
-
const installDevDependencyCommand = yarnLock
|
|
35
|
+
async function addAndInstallDeps(
|
|
36
|
+
framework: Models.Frameworks,
|
|
37
|
+
useYarn = false
|
|
38
|
+
): Promise<string> {
|
|
39
|
+
const installDevDependencyCommand = useYarn
|
|
41
40
|
? "yarn add -D"
|
|
42
41
|
: "npm install --save-dev";
|
|
43
|
-
const installDependencyCommand =
|
|
44
|
-
|
|
45
|
-
const spinner = logs.spinner("Downloading Slice Machine");
|
|
46
|
-
spinner.start();
|
|
42
|
+
const installDependencyCommand = useYarn ? "yarn add" : "npm install --save";
|
|
47
43
|
|
|
48
44
|
const { stderr } = await execCommand(
|
|
49
45
|
`${installDevDependencyCommand} ${SM_PACKAGE_NAME}`
|
|
@@ -52,6 +48,29 @@ export async function installRequiredDependencies(
|
|
|
52
48
|
const deps = depsForFramework(framework);
|
|
53
49
|
if (deps) await execCommand(`${installDependencyCommand} ${deps}`);
|
|
54
50
|
|
|
51
|
+
return stderr;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function installDeps(useYarn = false): Promise<string> {
|
|
55
|
+
const installCommand = useYarn ? "yarn" : "npm install";
|
|
56
|
+
const { stderr } = await execCommand(installCommand);
|
|
57
|
+
return stderr;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function installRequiredDependencies(
|
|
61
|
+
cwd: string,
|
|
62
|
+
framework: Models.Frameworks,
|
|
63
|
+
skipDependencies: boolean
|
|
64
|
+
): Promise<void> {
|
|
65
|
+
const yarnLock = NodeUtils.Files.exists(NodeUtils.YarnLockPath(cwd));
|
|
66
|
+
|
|
67
|
+
const spinner = logs.spinner("Installing Slice Machine");
|
|
68
|
+
spinner.start();
|
|
69
|
+
|
|
70
|
+
const stderr = await (skipDependencies
|
|
71
|
+
? installDeps(yarnLock)
|
|
72
|
+
: addAndInstallDeps(framework, yarnLock));
|
|
73
|
+
|
|
55
74
|
const pathToPkg = path.join(
|
|
56
75
|
NodeUtils.PackagePaths(cwd).value(),
|
|
57
76
|
SM_PACKAGE_NAME
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import { Models } from "@slicemachine/core";
|
|
2
|
-
import {
|
|
3
|
-
import { logs, Auth } from "../utils";
|
|
2
|
+
import { PrismicSharedConfigManager } from "@slicemachine/core/build/prismic";
|
|
3
|
+
import { logs, Auth, InitClient } from "../utils";
|
|
4
|
+
|
|
5
|
+
export async function loginOrBypass(
|
|
6
|
+
client: InitClient
|
|
7
|
+
): Promise<Models.UserProfile> {
|
|
8
|
+
const user: Models.UserProfile | null = await client
|
|
9
|
+
.profile()
|
|
10
|
+
.catch(() => null);
|
|
4
11
|
|
|
5
|
-
export async function loginOrBypass(base: string): Promise<{
|
|
6
|
-
info: Models.UserInfo;
|
|
7
|
-
profile: Models.UserProfile | null;
|
|
8
|
-
} | null> {
|
|
9
|
-
const user = await validateSessionAndGetProfile(base).catch((err) =>
|
|
10
|
-
console.log(err)
|
|
11
|
-
);
|
|
12
12
|
if (user) {
|
|
13
|
-
const email = user.
|
|
13
|
+
const email = user.email;
|
|
14
14
|
logs.writeCheck(`Logged in as ${logs.bold(email)}`);
|
|
15
15
|
return user;
|
|
16
|
-
} else {
|
|
17
|
-
await Auth.login(base);
|
|
18
|
-
const user = await validateSessionAndGetProfile(base);
|
|
19
|
-
return user;
|
|
20
16
|
}
|
|
17
|
+
|
|
18
|
+
await Auth.login(client);
|
|
19
|
+
|
|
20
|
+
// update token used to make calls.
|
|
21
|
+
client.updateAuthenticationToken(PrismicSharedConfigManager.getAuth());
|
|
22
|
+
|
|
23
|
+
const userAfterLogin: Models.UserProfile = await client.profile();
|
|
24
|
+
return userAfterLogin;
|
|
21
25
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { retrieveManifest, Files } from "@slicemachine/core/build/node-utils";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import { sendSlices } from "./starters/slices";
|
|
5
|
+
import { sendCustomTypes } from "./starters/custom-types";
|
|
6
|
+
import { sendDocuments } from "./starters/documents";
|
|
7
|
+
import { InitClient } from "../utils";
|
|
8
|
+
|
|
9
|
+
export async function sendStarterData(
|
|
10
|
+
client: InitClient,
|
|
11
|
+
cwd: string,
|
|
12
|
+
pushDocuments = true
|
|
13
|
+
) {
|
|
14
|
+
const manifest = retrieveManifest(cwd);
|
|
15
|
+
const documentsPath = path.join(cwd, "documents");
|
|
16
|
+
const hasDocuments = Files.exists(documentsPath);
|
|
17
|
+
|
|
18
|
+
if (manifest.exists === false || hasDocuments === false)
|
|
19
|
+
return Promise.resolve(false);
|
|
20
|
+
|
|
21
|
+
if (manifest.content) await sendSlices(client, cwd, manifest.content);
|
|
22
|
+
await sendCustomTypes(client, cwd);
|
|
23
|
+
|
|
24
|
+
// If the user choose not to push documents, we still delete the documents folder.
|
|
25
|
+
if (!pushDocuments) {
|
|
26
|
+
fs.rmSync(documentsPath, { recursive: true, force: true });
|
|
27
|
+
return Promise.resolve(true);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return sendDocuments(client, cwd);
|
|
31
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { CustomType } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
import { Files, CustomTypesPaths } from "@slicemachine/core/build/node-utils";
|
|
3
|
+
import { isLeft } from "fp-ts/lib/Either";
|
|
4
|
+
import { promptToPushCustomTypes } from "./prompts";
|
|
5
|
+
import { InitClient, logs } from "../../utils";
|
|
6
|
+
import { ClientError } from "@slicemachine/client";
|
|
7
|
+
|
|
8
|
+
export function readLocalCustomTypes(cwd: string): Array<CustomType> {
|
|
9
|
+
const customTypePaths = CustomTypesPaths(cwd);
|
|
10
|
+
const dir = customTypePaths.value();
|
|
11
|
+
|
|
12
|
+
if (Files.isDirectory(dir) === false) return [];
|
|
13
|
+
|
|
14
|
+
const fileNames = Files.readDirectory(dir);
|
|
15
|
+
|
|
16
|
+
const files = fileNames.reduce<Array<CustomType>>((acc, fileName) => {
|
|
17
|
+
const filePath = customTypePaths.customType(fileName).model();
|
|
18
|
+
const json = Files.safeReadJson(filePath);
|
|
19
|
+
|
|
20
|
+
if (!json) return acc;
|
|
21
|
+
|
|
22
|
+
const file = CustomType.decode(json);
|
|
23
|
+
|
|
24
|
+
if (file instanceof Error) {
|
|
25
|
+
logs.writeError(`reading ${filePath}: ${file.message}`);
|
|
26
|
+
return acc;
|
|
27
|
+
}
|
|
28
|
+
if (isLeft(file)) {
|
|
29
|
+
logs.writeError(`validating ${filePath}: ${JSON.stringify(file.left)}`);
|
|
30
|
+
return acc;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return [...acc, file.right];
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return files;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function sendCustomTypes(client: InitClient, cwd: string) {
|
|
40
|
+
const localCustomTypes = readLocalCustomTypes(cwd);
|
|
41
|
+
|
|
42
|
+
// nothing to push
|
|
43
|
+
if (localCustomTypes.length === 0) return Promise.resolve(false);
|
|
44
|
+
|
|
45
|
+
const remoteCustomTypeIds = await client
|
|
46
|
+
.getCustomTypes()
|
|
47
|
+
.then((customTypes) => customTypes.map((customType) => customType.id));
|
|
48
|
+
|
|
49
|
+
if (remoteCustomTypeIds.length) {
|
|
50
|
+
const shouldPush = await promptToPushCustomTypes();
|
|
51
|
+
if (shouldPush === false) return Promise.resolve(false);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const spinner = logs.spinner(
|
|
55
|
+
"Pushing existing custom types to your repository"
|
|
56
|
+
);
|
|
57
|
+
spinner.start();
|
|
58
|
+
|
|
59
|
+
await Promise.all(
|
|
60
|
+
localCustomTypes.map(async (customType) => {
|
|
61
|
+
const promise = remoteCustomTypeIds.includes(customType.id)
|
|
62
|
+
? client.updateCustomType(customType)
|
|
63
|
+
: client.insertCustomType(customType);
|
|
64
|
+
|
|
65
|
+
return promise.catch((error: ClientError) => {
|
|
66
|
+
logs.writeError(
|
|
67
|
+
`Sending custom type ${customType.id} - ${error.message}`
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// throwing the error again to stop the Promise.all
|
|
71
|
+
throw error;
|
|
72
|
+
});
|
|
73
|
+
})
|
|
74
|
+
).catch(() => {
|
|
75
|
+
// the error about the custom type that failed to be pushed should be in the terminal already.
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
spinner.succeed();
|
|
80
|
+
return Promise.resolve(true);
|
|
81
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import type { AxiosError } from "axios";
|
|
4
|
+
|
|
5
|
+
import * as t from "io-ts";
|
|
6
|
+
import { getOrElseW } from "fp-ts/Either";
|
|
7
|
+
import { InitClient, logs, lsdir, lsfiles } from "../../utils";
|
|
8
|
+
import { PrismicSharedConfigManager } from "@slicemachine/core/build/prismic/SharedConfig";
|
|
9
|
+
|
|
10
|
+
const SignatureFileReader = t.type({
|
|
11
|
+
signature: t.string,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type SignatureFile = t.TypeOf<typeof SignatureFileReader>;
|
|
15
|
+
|
|
16
|
+
export async function readSignatureFile(cwd: string): Promise<SignatureFile> {
|
|
17
|
+
const pathToFile = path.join(cwd, "documents", "index.json");
|
|
18
|
+
return fs.promises.readFile(pathToFile, "utf-8").then((res) => {
|
|
19
|
+
const data = JSON.parse(res) as unknown;
|
|
20
|
+
return getOrElseW(() => {
|
|
21
|
+
throw new Error("Unable to read document signature file");
|
|
22
|
+
})(SignatureFileReader.decode(data));
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function readDocuments(
|
|
27
|
+
cwd: string
|
|
28
|
+
): Promise<Record<string, unknown>> {
|
|
29
|
+
const documentDir = path.join(cwd, "documents");
|
|
30
|
+
const dirs = await lsdir(documentDir);
|
|
31
|
+
|
|
32
|
+
const files = (await Promise.all(dirs.map((dir) => lsfiles(dir)))).flat();
|
|
33
|
+
|
|
34
|
+
const documentObj = files.reduce<Record<string, unknown>>((acc, file) => {
|
|
35
|
+
const filename: string = path.parse(file).name;
|
|
36
|
+
const fileContent: string = fs.readFileSync(file, "utf-8");
|
|
37
|
+
const json = JSON.parse(fileContent) as Record<string, unknown>;
|
|
38
|
+
|
|
39
|
+
return { ...acc, [filename]: json };
|
|
40
|
+
}, {});
|
|
41
|
+
|
|
42
|
+
return documentObj;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function sendDocuments(
|
|
46
|
+
client: InitClient,
|
|
47
|
+
cwd: string
|
|
48
|
+
): Promise<boolean> {
|
|
49
|
+
const pathToDocuments = path.join(cwd, "documents");
|
|
50
|
+
const pathToSignatureFile = path.join(pathToDocuments, "index.json");
|
|
51
|
+
|
|
52
|
+
// Without the signature, we can't push documents to Prismic.
|
|
53
|
+
if (!fs.existsSync(pathToSignatureFile)) return Promise.resolve(false);
|
|
54
|
+
|
|
55
|
+
const signatureObj = await readSignatureFile(cwd);
|
|
56
|
+
const documents: Record<string, unknown> = await readDocuments(cwd);
|
|
57
|
+
|
|
58
|
+
// No documents to push
|
|
59
|
+
if (Object.keys(documents).length === 0) return Promise.resolve(false);
|
|
60
|
+
|
|
61
|
+
const spinner = logs.spinner("Pushing existing documents to your repository");
|
|
62
|
+
spinner.start();
|
|
63
|
+
|
|
64
|
+
return client
|
|
65
|
+
.pushDocuments(
|
|
66
|
+
signatureObj.signature,
|
|
67
|
+
documents,
|
|
68
|
+
PrismicSharedConfigManager.get().cookies
|
|
69
|
+
)
|
|
70
|
+
.then(() => {
|
|
71
|
+
spinner.succeed();
|
|
72
|
+
fs.rmSync(pathToDocuments, { recursive: true, force: true });
|
|
73
|
+
return true;
|
|
74
|
+
})
|
|
75
|
+
.catch((e: AxiosError) => {
|
|
76
|
+
spinner.fail();
|
|
77
|
+
if (e.response?.data === "Repository should not contain documents") {
|
|
78
|
+
logs.writeError(
|
|
79
|
+
"The selected repository is not empty, documents cannot be uploaded. Please choose an empty repository or delete the documents contained in your repository."
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
logs.writeError(
|
|
83
|
+
"Sending documents failed, please try again. If the problem persists, contact us."
|
|
84
|
+
);
|
|
85
|
+
logs.writeError(`Full error: ${e.code || 500} - ${e.message}`);
|
|
86
|
+
}
|
|
87
|
+
process.exit(1);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
|
|
3
|
+
export async function promptToPushSlices(): Promise<boolean> {
|
|
4
|
+
return inquirer
|
|
5
|
+
.prompt<{ pushSlices: boolean }>([
|
|
6
|
+
{
|
|
7
|
+
type: "confirm",
|
|
8
|
+
name: "pushSlices",
|
|
9
|
+
default: false,
|
|
10
|
+
message:
|
|
11
|
+
"Your repository already contains Slices. Do you want to continue pushing your local Slices?",
|
|
12
|
+
},
|
|
13
|
+
])
|
|
14
|
+
.then((res) => res.pushSlices);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function promptToPushCustomTypes(): Promise<boolean> {
|
|
18
|
+
return inquirer
|
|
19
|
+
.prompt<{ pushCustomTypes: boolean }>([
|
|
20
|
+
{
|
|
21
|
+
type: "confirm",
|
|
22
|
+
name: "pushCustomTypes",
|
|
23
|
+
default: false,
|
|
24
|
+
message:
|
|
25
|
+
"Your repository already contains Custom Types. Do you want to continue pushing your local Custom Types?",
|
|
26
|
+
},
|
|
27
|
+
])
|
|
28
|
+
.then((res) => res.pushCustomTypes);
|
|
29
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { InitClient } from "../../utils";
|
|
2
|
+
import {
|
|
3
|
+
Component,
|
|
4
|
+
ComponentInfo,
|
|
5
|
+
VariationSM,
|
|
6
|
+
SliceSM,
|
|
7
|
+
} from "@slicemachine/core/build/models";
|
|
8
|
+
import { Acl, ClientError } from "@slicemachine/client";
|
|
9
|
+
import { writeError } from "../../utils/logs";
|
|
10
|
+
|
|
11
|
+
async function updateVariationWithScreenshot(
|
|
12
|
+
client: InitClient,
|
|
13
|
+
acl: Acl,
|
|
14
|
+
screenshotPaths: ComponentInfo["screenshotPaths"],
|
|
15
|
+
sliceName: SliceSM["id"],
|
|
16
|
+
variation: VariationSM
|
|
17
|
+
): Promise<VariationSM> {
|
|
18
|
+
const screenshot = screenshotPaths[variation.id];
|
|
19
|
+
if (!screenshot || !screenshot.path) return Promise.resolve(variation);
|
|
20
|
+
|
|
21
|
+
return client
|
|
22
|
+
.uploadScreenshot({
|
|
23
|
+
acl,
|
|
24
|
+
sliceName,
|
|
25
|
+
variationId: variation.id,
|
|
26
|
+
filePath: screenshot.path,
|
|
27
|
+
})
|
|
28
|
+
.then((screenshotUrl) => {
|
|
29
|
+
return {
|
|
30
|
+
...variation,
|
|
31
|
+
imageUrl: screenshotUrl,
|
|
32
|
+
};
|
|
33
|
+
})
|
|
34
|
+
.catch((error: ClientError) => {
|
|
35
|
+
writeError(
|
|
36
|
+
`Couldn't upload screenshot slice: ${sliceName} - variation: ${variation.id}`
|
|
37
|
+
);
|
|
38
|
+
writeError(error.message, "Full error:");
|
|
39
|
+
return variation;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function updateSlicesWithScreenshots(
|
|
44
|
+
client: InitClient,
|
|
45
|
+
acl: Acl,
|
|
46
|
+
components: Array<Component>
|
|
47
|
+
): Promise<Array<SliceSM>> {
|
|
48
|
+
return Promise.all(
|
|
49
|
+
components.map(async (component) => {
|
|
50
|
+
const { screenshotPaths, model } = component;
|
|
51
|
+
|
|
52
|
+
const variationsUpdated: VariationSM[] = await Promise.all(
|
|
53
|
+
model.variations.map(async (variation) =>
|
|
54
|
+
updateVariationWithScreenshot(
|
|
55
|
+
client,
|
|
56
|
+
acl,
|
|
57
|
+
screenshotPaths,
|
|
58
|
+
model.id,
|
|
59
|
+
variation
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...model,
|
|
66
|
+
variations: variationsUpdated,
|
|
67
|
+
};
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
}
|