create-flaghoist 0.2.2 → 0.3.1
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/dist/index.js +93 -44
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { PLATFORM_KINDS as PLATFORM_KINDS2, STORAGE_KINDS as STORAGE_KINDS2 } from "flaghoist";
|
|
5
|
-
import { parseArgs } from "util";
|
|
4
|
+
import { PLATFORM_KINDS as PLATFORM_KINDS2, setupSummary, STORAGE_KINDS as STORAGE_KINDS2, terminalAsker } from "flaghoist";
|
|
6
5
|
import { relative } from "path";
|
|
6
|
+
import { parseArgs } from "util";
|
|
7
7
|
|
|
8
8
|
// src/scaffold.ts
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
collectSetup,
|
|
11
|
+
defaultsAsker,
|
|
12
12
|
PLATFORM_KINDS,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
STORAGE_KINDS,
|
|
14
|
+
writeSetup
|
|
15
15
|
} from "flaghoist";
|
|
16
|
-
import { existsSync, mkdirSync, readdirSync
|
|
17
|
-
import { join, resolve } from "path";
|
|
18
|
-
function scaffold(options = {}) {
|
|
16
|
+
import { existsSync, mkdirSync, readdirSync } from "fs";
|
|
17
|
+
import { basename, join, resolve } from "path";
|
|
18
|
+
async function scaffold(options = {}) {
|
|
19
19
|
const root = options.cwd ?? process.cwd();
|
|
20
20
|
if (options.storage && !STORAGE_KINDS.includes(options.storage)) {
|
|
21
21
|
throw new Error(`Unknown storage "${options.storage}". One of: ${STORAGE_KINDS.join(", ")}.`);
|
|
@@ -23,72 +23,121 @@ function scaffold(options = {}) {
|
|
|
23
23
|
if (options.platform && !PLATFORM_KINDS.includes(options.platform)) {
|
|
24
24
|
throw new Error(`Unknown platform "${options.platform}". One of: ${PLATFORM_KINDS.join(", ")}.`);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
if (options.directory) assertUsable(resolve(root, options.directory), options.directory);
|
|
27
|
+
else if (!options.asker?.interactive) assertUsable(resolve(root), void 0);
|
|
28
|
+
const { directory, cwd: _cwd, asker, storage, platform, ...rest } = options;
|
|
29
|
+
const preset = {
|
|
30
|
+
...rest,
|
|
31
|
+
storage,
|
|
32
|
+
platform,
|
|
33
|
+
// The directory name is the natural project name.
|
|
34
|
+
name: rest.name ?? (directory ? basename(directory) : void 0)
|
|
35
|
+
};
|
|
36
|
+
const setup = await collectSetup(asker ?? defaultsAsker(), preset);
|
|
37
|
+
const target = directory ?? (asker?.interactive === false || !asker ? void 0 : setup.config.name);
|
|
38
|
+
const dir = target ? resolve(root, target) : resolve(root);
|
|
39
|
+
assertUsable(dir, target);
|
|
27
40
|
const existed = existsSync(dir);
|
|
28
|
-
if (existed
|
|
41
|
+
if (!existed) mkdirSync(dir, { recursive: true });
|
|
42
|
+
const { envPath } = writeSetup(dir, setup);
|
|
43
|
+
return {
|
|
44
|
+
dir,
|
|
45
|
+
configPath: join(dir, "flaghoist.toml"),
|
|
46
|
+
...envPath ? { envPath } : {},
|
|
47
|
+
createdDirectory: !existed,
|
|
48
|
+
config: setup.config,
|
|
49
|
+
setup
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function assertUsable(dir, shown) {
|
|
53
|
+
if (existsSync(dir) && readdirSync(dir).length > 0) {
|
|
29
54
|
throw new Error(
|
|
30
|
-
|
|
55
|
+
shown ? `Directory "${shown}" already exists and is not empty.` : "The current directory is not empty. Pass a directory name, e.g. `npm create flaghoist team-flags`."
|
|
31
56
|
);
|
|
32
57
|
}
|
|
33
|
-
if (!existed) mkdirSync(dir, { recursive: true });
|
|
34
|
-
const base = {
|
|
35
|
-
...DEFAULT_CONFIG,
|
|
36
|
-
// The directory name is the natural project name; falling back keeps `.` usable.
|
|
37
|
-
name: options.directory ?? DEFAULT_CONFIG.name,
|
|
38
|
-
storage: options.storage ?? DEFAULT_CONFIG.storage
|
|
39
|
-
};
|
|
40
|
-
const config = options.platform === "container" ? asContainer(base) : base;
|
|
41
|
-
const configPath = join(dir, "flaghoist.toml");
|
|
42
|
-
writeFileSync(configPath, serializeConfig(config));
|
|
43
|
-
return { dir, configPath, createdDirectory: !existed, config };
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
// src/index.ts
|
|
47
61
|
function printHelp() {
|
|
48
|
-
console.log(`create-flaghoist
|
|
62
|
+
console.log(`create-flaghoist: set up a Flaghoist feature-flag service
|
|
49
63
|
|
|
50
64
|
Usage:
|
|
51
|
-
npm create flaghoist@latest
|
|
65
|
+
npm create flaghoist@latest [directory] -- [options]
|
|
66
|
+
|
|
67
|
+
With no options it asks a few questions. Any option below answers its question up front.
|
|
52
68
|
|
|
53
69
|
Options:
|
|
54
|
-
--
|
|
55
|
-
--platform
|
|
56
|
-
|
|
70
|
+
--name <name> Project name (default: the directory, or team-flags)
|
|
71
|
+
--platform <kind> One of: ${PLATFORM_KINDS2.join(", ")}
|
|
72
|
+
--storage <kind> One of: ${STORAGE_KINDS2.join(", ")}
|
|
73
|
+
--no-accounts Keep the single admin token, without accounts and roles
|
|
74
|
+
--sso-issuer <url> Turn on SSO with this OpenID Connect issuer
|
|
75
|
+
--sso-client-id <id> The SSO client id
|
|
76
|
+
--sso-admin-group <name> Members of this group become admins
|
|
77
|
+
--no-dashboard Do not serve the dashboard at /admin
|
|
78
|
+
-y, --yes Take the defaults for everything not given
|
|
79
|
+
-h, --help Show this message
|
|
57
80
|
|
|
58
|
-
Omit
|
|
81
|
+
Omit [directory] to be asked for a project name; it becomes the directory.`);
|
|
59
82
|
}
|
|
60
|
-
function main() {
|
|
83
|
+
async function main() {
|
|
61
84
|
const { values, positionals } = parseArgs({
|
|
62
85
|
args: process.argv.slice(2),
|
|
63
86
|
allowPositionals: true,
|
|
64
87
|
options: {
|
|
88
|
+
name: { type: "string" },
|
|
65
89
|
storage: { type: "string" },
|
|
66
90
|
platform: { type: "string" },
|
|
91
|
+
"no-accounts": { type: "boolean" },
|
|
92
|
+
"sso-issuer": { type: "string" },
|
|
93
|
+
"sso-client-id": { type: "string" },
|
|
94
|
+
"sso-admin-group": { type: "string" },
|
|
95
|
+
"no-dashboard": { type: "boolean" },
|
|
96
|
+
yes: { type: "boolean", short: "y" },
|
|
67
97
|
help: { type: "boolean", short: "h" }
|
|
68
98
|
}
|
|
69
99
|
});
|
|
70
100
|
if (values.help) return printHelp();
|
|
71
|
-
const
|
|
101
|
+
const interactive = process.stdin.isTTY === true && values.yes !== true;
|
|
102
|
+
const asker = interactive ? terminalAsker() : void 0;
|
|
103
|
+
if (interactive) console.log("\nLet us set up your Flaghoist service.\n");
|
|
104
|
+
const options = {
|
|
72
105
|
directory: positionals[0],
|
|
106
|
+
name: values.name,
|
|
73
107
|
storage: values.storage,
|
|
74
|
-
platform: values.platform
|
|
75
|
-
|
|
76
|
-
|
|
108
|
+
platform: values.platform,
|
|
109
|
+
...values["no-accounts"] ? { accounts: false } : {},
|
|
110
|
+
...values["no-dashboard"] ? { dashboard: false } : {},
|
|
111
|
+
...values["sso-issuer"] ? { ssoIssuer: values["sso-issuer"] } : {},
|
|
112
|
+
...values["sso-client-id"] ? { ssoClientId: values["sso-client-id"] } : {},
|
|
113
|
+
...values["sso-admin-group"] ? { ssoAdminGroup: values["sso-admin-group"] } : {},
|
|
114
|
+
asker
|
|
115
|
+
};
|
|
116
|
+
let result;
|
|
117
|
+
try {
|
|
118
|
+
result = await scaffold(options);
|
|
119
|
+
} finally {
|
|
120
|
+
asker?.close();
|
|
121
|
+
}
|
|
122
|
+
const shown = relative(process.cwd(), result.configPath) || "flaghoist.toml";
|
|
77
123
|
console.log(`
|
|
78
124
|
Created ${shown}`);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
125
|
+
const summary = setupSummary(
|
|
126
|
+
interactive ? result.setup : { ...result.setup, pepperGenerated: false },
|
|
127
|
+
result.envPath !== void 0
|
|
128
|
+
);
|
|
129
|
+
for (const line of summary) console.log(line);
|
|
130
|
+
console.log("\nNext:\n");
|
|
131
|
+
const cd = relative(process.cwd(), result.dir);
|
|
85
132
|
if (cd) console.log(` cd ${cd}`);
|
|
86
133
|
console.log(" npx flaghoist deploy\n");
|
|
134
|
+
if (result.config.accounts?.enabled) {
|
|
135
|
+
console.log("After deploying, open /admin and sign in with your ADMIN_TOKEN once to create the");
|
|
136
|
+
console.log("owner account. Everyone after that is invited from the Members page.\n");
|
|
137
|
+
}
|
|
87
138
|
console.log("Prefer to own the code? `npx flaghoist eject` turns it into a project you edit.");
|
|
88
139
|
}
|
|
89
|
-
|
|
90
|
-
main();
|
|
91
|
-
} catch (error) {
|
|
140
|
+
main().catch((error) => {
|
|
92
141
|
console.error(error instanceof Error ? error.message : String(error));
|
|
93
142
|
process.exit(1);
|
|
94
|
-
}
|
|
143
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-flaghoist",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Scaffold a Flaghoist feature-flag service — the package behind `npm create flaghoist`.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"scaffold"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"flaghoist": "0.
|
|
24
|
+
"flaghoist": "0.5.1"
|
|
25
25
|
},
|
|
26
26
|
"publishConfig": {
|
|
27
27
|
"access": "public"
|