|
1 | | -const inquirer = require('inquirer') |
| 1 | +'use strict' |
| 2 | +const inquirer = require('inquirer').default |
2 | 3 | const path = require('node:path') |
3 | | -const createPackageJson = require('create-package-json') |
4 | | -const fs = require('fs-extra') |
5 | | -const { gitInit } = require('../git.js') |
6 | | - |
7 | | -async function create (opts) { |
8 | | - const { directory } = opts |
9 | | - |
10 | | - const config = { |
11 | | - path: directory, |
12 | | - name: undefined, |
13 | | - labels: [], |
14 | | - orgs: [], |
15 | | - projects: [], |
16 | | - githubActions: false |
17 | | - } |
| 4 | +const fs = require('node:fs/promises') |
| 5 | +const { gitInit } = require('../git') |
| 6 | +const packageJson = require('../../package.json') |
18 | 7 |
|
| 8 | +async function create (opts = {}) { |
19 | 9 | const answers = await inquirer.prompt([ |
20 | 10 | { |
21 | 11 | type: 'input', |
22 | 12 | name: 'path', |
23 | 13 | message: 'Where would you like to create your project?', |
24 | 14 | default: 'statusboard', |
25 | | - when: () => !config.path |
| 15 | + when: () => !opts.directory, |
| 16 | + validate: value => value.trim().length > 0 || 'Enter a project directory.' |
26 | 17 | }, |
27 | 18 | { |
28 | 19 | type: 'confirm', |
29 | 20 | name: 'defaultLabels', |
30 | | - message: 'Do you want use default labels?', |
| 21 | + message: 'Do you want to use the default labels?', |
31 | 22 | default: true |
32 | 23 | }, |
33 | 24 | { |
34 | 25 | type: 'input', |
35 | 26 | name: 'labels', |
36 | | - message: 'What labels do you want to use (use commas to separate)', |
37 | | - when: (answers) => !answers.defaultLabels |
| 27 | + message: 'What labels do you want to use (use commas to separate)?', |
| 28 | + when: answers => !answers.defaultLabels |
38 | 29 | }, |
39 | 30 | { |
40 | 31 | type: 'input', |
41 | 32 | name: 'orgs', |
42 | | - message: |
43 | | - 'What organizations do you want to include (use commas to separate)' |
| 33 | + message: 'What organizations do you want to include (use commas to separate)?' |
44 | 34 | }, |
45 | 35 | { |
46 | 36 | type: 'input', |
47 | 37 | name: 'repositories', |
48 | | - message: |
49 | | - 'What repositories do you want to include (use commas to separate)' |
| 38 | + message: 'What repositories do you want to include (owner/repo, separated by commas)?', |
| 39 | + validate: value => transformUserInput(value).every(repo => /^[\w.-]+\/[\w.-]+$/.test(repo)) || 'Use owner/repo for each repository.' |
50 | 40 | }, |
51 | 41 | { |
52 | 42 | type: 'confirm', |
53 | 43 | name: 'githubActions', |
54 | | - message: 'Do you want deploy with GitHub Actions?', |
| 44 | + message: 'Do you want to deploy with GitHub Actions?', |
55 | 45 | default: false |
56 | 46 | } |
57 | 47 | ]) |
58 | 48 |
|
59 | | - config.path = answers.path.trim() |
60 | | - |
61 | | - config.labels = transformUserInput(answers.labels) |
62 | | - config.orgs = transformUserInput(answers.orgs) |
63 | | - config.projects = transformUserInput(answers.repositories) |
64 | | - config.githubActions = answers.githubActions |
65 | | - |
66 | | - const appPath = path.resolve(config.path) |
67 | | - config.name = path.basename(appPath) |
68 | | - config.path = appPath |
69 | | - |
70 | | - await fs.ensureDir(appPath) |
| 49 | + const directory = (opts.directory || answers.path || '').trim() |
| 50 | + if (!directory) throw new Error('Enter a project directory.') |
| 51 | + const appPath = path.resolve(directory) |
| 52 | + await fs.mkdir(appPath, { recursive: true }) |
| 53 | + if ((await fs.readdir(appPath)).length) { |
| 54 | + throw new Error(`Directory is not empty: ${appPath}`) |
| 55 | + } |
71 | 56 |
|
72 | | - if (config.githubActions) { |
73 | | - createBuildAction(config) |
| 57 | + const config = { |
| 58 | + path: appPath, |
| 59 | + name: path.basename(appPath), |
| 60 | + labels: answers.defaultLabels ? undefined : transformUserInput(answers.labels), |
| 61 | + orgs: transformUserInput(answers.orgs), |
| 62 | + projects: transformUserInput(answers.repositories), |
| 63 | + githubActions: answers.githubActions |
74 | 64 | } |
75 | 65 |
|
| 66 | + if (config.githubActions) await createBuildAction(config) |
76 | 67 | await createConfigFile(config) |
77 | | - createGitIgnore(config) |
| 68 | + await fs.copyFile(path.join(__dirname, 'template', 'gitignore'), path.join(appPath, '.gitignore')) |
78 | 69 |
|
79 | | - await createPackageJson({ |
80 | | - cwd: appPath, |
81 | | - name: config.name, |
| 70 | + // The generated manifest is fixed apart from the project name and our version. |
| 71 | + const manifest = { |
| 72 | + name: config.name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/^-+/, '') || 'statusboard', |
82 | 73 | description: 'A dashboard for project status', |
83 | 74 | version: '1.0.0', |
84 | | - dependencies: ['@pkgjs/statusboard'], |
85 | | - author: null, |
86 | | - keywords: ['statusboard', 'projects'], |
87 | | - repository: null, |
88 | | - type: 'commonjs', |
89 | 75 | private: true, |
| 76 | + type: 'commonjs', |
90 | 77 | license: 'MIT', |
91 | | - main: 'config.js', |
92 | | - devDependencies: null, |
| 78 | + engines: packageJson.engines, |
| 79 | + dependencies: { '@pkgjs/statusboard': `^${packageJson.version}` }, |
93 | 80 | scripts: { |
94 | 81 | build: 'statusboard build -C ./config.js', |
95 | 82 | buildsite: 'npm run clean && statusboard site -C ./config.js', |
96 | 83 | buildindex: 'statusboard index -C ./config.js', |
97 | | - clean: 'rm -rf build/css build/js' |
| 84 | + clean: 'node -e "const fs = require(\'node:fs\'); for (const dir of [\'build/css\', \'build/js\']) fs.rmSync(dir, { recursive: true, force: true })"' |
98 | 85 | } |
99 | | - }) |
| 86 | + } |
| 87 | + await fs.writeFile(path.join(appPath, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`, { flag: 'wx' }) |
100 | 88 |
|
101 | | - gitInit(appPath) |
| 89 | + if (!gitInit(appPath)) { |
| 90 | + console.warn('Could not create the initial Git commit. Project files are ready; check Git installation and user configuration.') |
| 91 | + } |
| 92 | + console.log(`Created Statusboard in ${appPath}. Run npm install there, set GITHUB_TOKEN, then run npm run build.`) |
| 93 | + if (config.githubActions) { |
| 94 | + console.log('Enable GitHub Pages with GitHub Actions as the source in your repository settings.') |
| 95 | + } |
102 | 96 | } |
103 | 97 |
|
104 | 98 | async function createConfigFile (config) { |
105 | | - const configFile = path.join(config.path, 'config.js') |
106 | | - |
107 | | - const configJs = `module.exports = {${ |
108 | | - config.labels.length >= 1 |
109 | | - ? `\n issueLabels: ${JSON.stringify(config.labels)},` |
110 | | - : '' |
111 | | - }${config.orgs.length >= 1 ? `\n orgs: ${JSON.stringify(config.orgs)},` : ''}${ |
112 | | - config.projects.length >= 1 |
113 | | - ? `\n projects: ${JSON.stringify(config.projects)},` |
114 | | - : '' |
115 | | - }${config.githubActions ? `\n baseUrl: "/${config.name}",` : ''} |
| 99 | + const fields = { |
| 100 | + ...(config.labels === undefined ? {} : { issueLabels: config.labels }), |
| 101 | + orgs: config.orgs, |
| 102 | + projects: config.projects |
| 103 | + } |
| 104 | + const content = JSON.stringify(fields, null, 2).slice(0, -2) |
| 105 | + const baseUrl = config.githubActions |
| 106 | + ? `\n baseUrl: process.env.STATUSBOARD_BASE_URL ?? ${JSON.stringify(`/${config.name}`)},` |
| 107 | + : '' |
| 108 | + await fs.writeFile(path.join(config.path, 'config.js'), `'use strict'\nmodule.exports = ${content},${baseUrl} |
116 | 109 | github: { |
117 | 110 | token: process.env.GITHUB_TOKEN |
118 | 111 | } |
119 | 112 | } |
120 | | -` |
121 | | - |
122 | | - await fs.writeFile(configFile, configJs) |
| 113 | +`, { flag: 'wx' }) |
123 | 114 | } |
124 | 115 |
|
125 | | -function transformUserInput (input) { |
126 | | - if (input?.length === 0) { |
127 | | - return [] |
128 | | - } |
129 | | - |
130 | | - return input?.split(',').map((l) => l.trim()) || [] |
| 116 | +function transformUserInput (input = '') { |
| 117 | + return input.split(',').map(value => value.trim()).filter(Boolean) |
131 | 118 | } |
132 | 119 |
|
133 | | -function createBuildAction (config) { |
| 120 | +async function createBuildAction (config) { |
134 | 121 | const workflowDir = path.join(config.path, '.github', 'workflows') |
135 | | - const templateFile = path.join(__dirname, 'template', 'build.yml') |
136 | | - const configFile = path.join(workflowDir, 'build.yml') |
137 | | - |
138 | | - fs.ensureDirSync(workflowDir) |
139 | | - fs.copyFileSync(templateFile, configFile) |
140 | | -} |
141 | | - |
142 | | -function createGitIgnore (config) { |
143 | | - const gitIgnore = path.join(config.path, '.gitignore') |
144 | | - const templateFile = path.join(__dirname, 'template', '.gitignore') |
145 | | - |
146 | | - fs.ensureFileSync(gitIgnore) |
147 | | - fs.copyFileSync(templateFile, gitIgnore) |
| 122 | + await fs.mkdir(workflowDir, { recursive: true }) |
| 123 | + await fs.copyFile(path.join(__dirname, 'template', 'build.yml'), path.join(workflowDir, 'build.yml')) |
148 | 124 | } |
149 | 125 |
|
150 | 126 | module.exports = create |
0 commit comments