@scrymore/scry-deployer 0.3.2 → 0.4.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/bin/cli.js +6 -2
- package/lib/init.js +40 -43
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -409,9 +409,13 @@ async function main() {
|
|
|
409
409
|
alias: 'skipGhSetup'
|
|
410
410
|
})
|
|
411
411
|
.option('commit-api-key', {
|
|
412
|
-
describe: '
|
|
412
|
+
describe: 'Write the API key into the committed config file (not recommended)',
|
|
413
413
|
type: 'boolean',
|
|
414
|
-
default
|
|
414
|
+
// False by default. The description has always said "not
|
|
415
|
+
// recommended" while the default said otherwise, and the
|
|
416
|
+
// default won: every `init` wrote a customer's key into a
|
|
417
|
+
// file it then committed.
|
|
418
|
+
default: false,
|
|
415
419
|
alias: 'commitApiKey'
|
|
416
420
|
})
|
|
417
421
|
.option('verbose', {
|
package/lib/init.js
CHANGED
|
@@ -47,19 +47,27 @@ async function runInit(argv) {
|
|
|
47
47
|
// Step 3: Create config file
|
|
48
48
|
const step3Start = Date.now();
|
|
49
49
|
logger.info('3/8: Creating configuration file...');
|
|
50
|
-
createConfigFile(argv.project, argv.apiKey, argv.apiUrl, envInfo);
|
|
50
|
+
createConfigFile(argv.project, argv.apiKey, argv.apiUrl, envInfo, argv.commitApiKey);
|
|
51
51
|
const step3Duration = Date.now() - step3Start;
|
|
52
52
|
logger.success(`✅ Created .storybook-deployer.json [${step3Duration}ms]\n`);
|
|
53
53
|
|
|
54
|
-
// Step 4:
|
|
54
|
+
// Step 4: Report what the committed config does and does not contain.
|
|
55
|
+
//
|
|
56
|
+
// This step used to add `.storybook-deployer.json` to .gitignore, which was
|
|
57
|
+
// wrong in both directions. The config now holds no credential, so ignoring
|
|
58
|
+
// it would only stop a team sharing its project id — and the entry it wrote,
|
|
59
|
+
// `.storybook-deployer.json # Contains API key`, never matched anything:
|
|
60
|
+
// in .gitignore a `#` is only a comment at the start of a line, so the
|
|
61
|
+
// pattern included the trailing text and git ignored no file.
|
|
55
62
|
const step4Start = Date.now();
|
|
56
|
-
if (
|
|
57
|
-
logger.info('4/8:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
if (argv.commitApiKey) {
|
|
64
|
+
logger.info('4/8: Checking credentials...');
|
|
65
|
+
logger.error(`⚠️ --commit-api-key: your API key will be written to .storybook-deployer.json and committed.
|
|
66
|
+
Git history keeps it after rotation, and CI does not need it — the key is
|
|
67
|
+
already stored as the SCRY_API_KEY repository secret. [${Date.now() - step4Start}ms]\n`);
|
|
61
68
|
} else {
|
|
62
|
-
logger.info('4/8:
|
|
69
|
+
logger.info('4/8: Checking credentials...');
|
|
70
|
+
logger.success(`✅ .storybook-deployer.json holds no credentials — safe to commit [${Date.now() - step4Start}ms]\n`);
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
// Step 5: Generate workflow files
|
|
@@ -94,7 +102,7 @@ async function runInit(argv) {
|
|
|
94
102
|
// Step 7: Git commit
|
|
95
103
|
const step7Start = Date.now();
|
|
96
104
|
logger.info('7/8: Committing changes...');
|
|
97
|
-
const commitResult = gitCommit(
|
|
105
|
+
const commitResult = gitCommit(logger);
|
|
98
106
|
const step7Duration = Date.now() - step7Start;
|
|
99
107
|
if (commitResult.success) {
|
|
100
108
|
logger.success(`✅ Changes committed: ${commitResult.sha} [${step7Duration}ms]\n`);
|
|
@@ -236,7 +244,7 @@ function parseGitHubRemote(remote) {
|
|
|
236
244
|
/**
|
|
237
245
|
* Create the configuration file
|
|
238
246
|
*/
|
|
239
|
-
function createConfigFile(projectId, apiKey, apiUrl, envInfo) {
|
|
247
|
+
function createConfigFile(projectId, apiKey, apiUrl, envInfo, commitApiKey) {
|
|
240
248
|
const config = {
|
|
241
249
|
apiUrl: apiUrl,
|
|
242
250
|
project: projectId,
|
|
@@ -245,10 +253,19 @@ function createConfigFile(projectId, apiKey, apiUrl, envInfo) {
|
|
|
245
253
|
verbose: false
|
|
246
254
|
};
|
|
247
255
|
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
|
|
256
|
+
// The key is deliberately absent unless explicitly asked for.
|
|
257
|
+
//
|
|
258
|
+
// This file gets committed, and CI never reads the key from it — `init` sets
|
|
259
|
+
// SCRY_API_KEY as a GitHub *secret* and the generated workflow reads
|
|
260
|
+
// ${{ secrets.SCRY_API_KEY }}. So a copy here buys nothing and lands
|
|
261
|
+
// somewhere git history makes permanent: rotating the key afterwards does
|
|
262
|
+
// not remove it, and on a public repository it is simply disclosed.
|
|
263
|
+
//
|
|
264
|
+
// Local runs read SCRY_API_KEY from the environment, which lib/config.js
|
|
265
|
+
// already resolves.
|
|
266
|
+
if (commitApiKey) {
|
|
267
|
+
config.apiKey = apiKey;
|
|
268
|
+
}
|
|
252
269
|
|
|
253
270
|
const configPath = '.storybook-deployer.json';
|
|
254
271
|
fs.writeFileSync(
|
|
@@ -258,28 +275,6 @@ function createConfigFile(projectId, apiKey, apiUrl, envInfo) {
|
|
|
258
275
|
);
|
|
259
276
|
}
|
|
260
277
|
|
|
261
|
-
/**
|
|
262
|
-
* Update .gitignore to exclude sensitive files (optional)
|
|
263
|
-
*/
|
|
264
|
-
function updateGitignore() {
|
|
265
|
-
const gitignorePath = '.gitignore';
|
|
266
|
-
const entries = [
|
|
267
|
-
'# Scry Storybook Deployer',
|
|
268
|
-
'.storybook-deployer.json # Contains API key'
|
|
269
|
-
];
|
|
270
|
-
|
|
271
|
-
let gitignoreContent = '';
|
|
272
|
-
if (fs.existsSync(gitignorePath)) {
|
|
273
|
-
gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Check if already added
|
|
277
|
-
if (!gitignoreContent.includes('.storybook-deployer.json')) {
|
|
278
|
-
gitignoreContent += '\n' + entries.join('\n') + '\n';
|
|
279
|
-
fs.writeFileSync(gitignorePath, gitignoreContent, 'utf8');
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
278
|
/**
|
|
284
279
|
* Generate workflow files
|
|
285
280
|
*/
|
|
@@ -367,7 +362,7 @@ Or install GitHub CLI and run:
|
|
|
367
362
|
/**
|
|
368
363
|
* Commit the changes to git
|
|
369
364
|
*/
|
|
370
|
-
function gitCommit(
|
|
365
|
+
function gitCommit(logger) {
|
|
371
366
|
try {
|
|
372
367
|
// Check if there are changes to commit
|
|
373
368
|
const status = execSync('git status --porcelain', { encoding: 'utf8' });
|
|
@@ -382,10 +377,6 @@ function gitCommit(commitApiKey, logger) {
|
|
|
382
377
|
'.storybook-deployer.json'
|
|
383
378
|
];
|
|
384
379
|
|
|
385
|
-
if (!commitApiKey) {
|
|
386
|
-
filesToAdd.push('.gitignore');
|
|
387
|
-
}
|
|
388
|
-
|
|
389
380
|
for (const file of filesToAdd) {
|
|
390
381
|
if (fs.existsSync(file)) {
|
|
391
382
|
execSync(`git add "${file}"`, { stdio: 'pipe' });
|
|
@@ -449,7 +440,7 @@ function showSuccessMessage(projectId, envInfo, apiUrl, pushed) {
|
|
|
449
440
|
Your Storybook deployment is configured and ready to go.
|
|
450
441
|
|
|
451
442
|
📦 What was set up:
|
|
452
|
-
✅ Configuration file (.storybook-deployer.json)
|
|
443
|
+
✅ Configuration file (.storybook-deployer.json — no credentials, safe to commit)
|
|
453
444
|
✅ GitHub Actions workflows (.github/workflows/)
|
|
454
445
|
✅ Repository variables (SCRY_PROJECT_ID, SCRY_API_URL)
|
|
455
446
|
✅ Repository secret (SCRY_API_KEY)
|
|
@@ -461,6 +452,12 @@ ${!pushed ? `
|
|
|
461
452
|
git push
|
|
462
453
|
` : ''}
|
|
463
454
|
|
|
455
|
+
🔑 Running a deploy locally:
|
|
456
|
+
CI reads the key from the SCRY_API_KEY secret. On your own machine, export it
|
|
457
|
+
rather than writing it into the config file, which is committed:
|
|
458
|
+
|
|
459
|
+
export SCRY_API_KEY=<your key>
|
|
460
|
+
|
|
464
461
|
🚀 Deployment:
|
|
465
462
|
Your Storybook will deploy automatically on:
|
|
466
463
|
• Every push to ${envInfo.currentBranch || 'main'} branch
|
|
@@ -477,4 +474,4 @@ Happy deploying! ✨
|
|
|
477
474
|
`);
|
|
478
475
|
}
|
|
479
476
|
|
|
480
|
-
module.exports = { runInit };
|
|
477
|
+
module.exports = { runInit, createConfigFile };
|