diff --git a/lib/cli.js b/lib/cli.js index 71d2710..ea23bde 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -2,6 +2,7 @@ const yargs = require('yargs/yargs') const dotenv = require('dotenv') const path = require('path') +const initStatusboard = require('./commands/create') const SHARED_OPTIONS = { db: { @@ -81,8 +82,8 @@ module.exports = (create, builder, argv) => { let cli = yargs() - .command('create', 'Create a StatusBoard', {}, async (argv) => { - console.log('Coming soon!') + .command('create [directory]', 'Create a StatusBoard', {}, async (argv) => { + await initStatusboard(argv) }) .command('build', 'Index and build board', SHARED_OPTIONS, async (argv) => { diff --git a/lib/commands/create.js b/lib/commands/create.js new file mode 100644 index 0000000..3e56683 --- /dev/null +++ b/lib/commands/create.js @@ -0,0 +1,151 @@ +const inquirer = require('inquirer') +const path = require('node:path') +const createPackageJson = require('create-package-json') +const fs = require('fs-extra') +const { gitInit } = require('../git.js') + +async function create (opts) { + const { directory } = opts + + const config = { + path: directory, + name: undefined, + labels: [], + orgs: [], + projects: [], + githubActions: false + } + + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'path', + message: 'Where would you like to create your project?', + default: 'statusboard', + when: () => !config.path + }, + { + type: 'confirm', + name: 'defaultLabels', + message: 'Do you want use default labels?', + default: true + }, + { + type: 'input', + name: 'labels', + message: 'What labels do you want to use (use commas to separate)', + when: (answers) => !answers.defaultLabels + }, + { + type: 'input', + name: 'orgs', + message: + 'What organizations do you want to include (use commas to separate)' + }, + { + type: 'input', + name: 'repositories', + message: + 'What repositories do you want to include (use commas to separate)' + }, + { + type: 'confirm', + name: 'githubActions', + message: 'Do you want deploy with GitHub Actions?', + default: false + } + ]) + + config.path = answers.path.trim() + + config.labels = transformUserInput(answers.labels) + config.orgs = transformUserInput(answers.orgs) + config.projects = transformUserInput(answers.repositories) + config.githubActions = answers.githubActions + + const appPath = path.resolve(config.path) + config.name = path.basename(appPath) + config.path = appPath + + await fs.ensureDir(appPath) + + if (config.githubActions) { + createBuildAction(config) + } + + await createConfigFile(config) + createGitIgnore(config) + + await createPackageJson({ + cwd: appPath, + name: config.name, + description: 'A dashboard for project status', + version: '1.0.0', + dependencies: ['@pkgjs/statusboard'], + author: null, + keywords: ['statusboard', 'projects'], + repository: null, + type: 'commonjs', + private: true, + license: 'MIT', + main: 'config.js', + devDependencies: null, + scripts: { + build: 'statusboard build -C ./config.js', + buildsite: 'npm run clean && statusboard site -C ./config.js', + buildindex: 'statusboard index -C ./config.js', + clean: 'rm -rf build/css build/js' + } + }) + + + gitInit(appPath) +} + +async function createConfigFile (config) { + const configFile = path.join(config.path, 'config.js') + + const configJs = `module.exports = {${ + config.labels.length >= 1 + ? `\n issueLabels: ${JSON.stringify(config.labels)},` + : '' + }${config.orgs.length >= 1 ? `\n orgs: ${JSON.stringify(config.orgs)},` : ''}${ + config.projects.length >= 1 + ? `\n projects: ${JSON.stringify(config.projects)},` + : '' + }${config.githubActions ? `\n baseUrl: "/${config.name}",` : ''} + github: { + token: process.env.GITHUB_TOKEN + } +} +` + + await fs.writeFile(configFile, configJs) +} + +function transformUserInput(input) { + if (input?.length === 0) { + return [] + } + + return input?.split(",").map((l) => l.trim()) || [] +} + +function createBuildAction(config) { + const workflowDir = path.join(config.path, '.github', 'workflows') + const templateFile = path.join(__dirname, 'template', 'build.yml') + const configFile = path.join(workflowDir, 'build.yml') + + fs.ensureDirSync(workflowDir) + fs.copyFileSync(templateFile, configFile) +} + +function createGitIgnore(config) { + const gitIgnore = path.join(config.path, '.gitignore') + const templateFile = path.join(__dirname, 'template', '.gitignore') + + fs.ensureFileSync(gitIgnore) + fs.copyFileSync(templateFile, gitIgnore) +} + +module.exports = create diff --git a/lib/commands/template/.gitignore b/lib/commands/template/.gitignore new file mode 100644 index 0000000..d596a96 --- /dev/null +++ b/lib/commands/template/.gitignore @@ -0,0 +1,11 @@ +# dependencies +node_modules +.pnp +.pnp.js + +# production +build + +# local env files +.env*.local +.env \ No newline at end of file diff --git a/lib/commands/template/build.yml b/lib/commands/template/build.yml new file mode 100644 index 0000000..3691a49 --- /dev/null +++ b/lib/commands/template/build.yml @@ -0,0 +1,54 @@ +name: Generate Statusboard + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + index: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - uses: actions/cache@v4 + id: cache + with: + path: | + ~/.npm + ~/.cache + ./dist + ./node_modules + key: ${{ runner.os }}-build-${{ github.sha }} + - if: steps.cache.outputs.cache-hit != 'true' + run: npm install + shell: bash + - run: npm run build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: './build' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/lib/git.js b/lib/git.js new file mode 100644 index 0000000..e82da88 --- /dev/null +++ b/lib/git.js @@ -0,0 +1,39 @@ +const { execSync } = require("child_process"); +const { rm } = require("fs"); + +function isGitRepo() { + try { + execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" }); + return true; + } catch {} + return false; +} + +module.exports.gitInit = function gitInit(path) { + let didInit = false; + + try { + if(isGitRepo()) { + return false; + } + + execSync("git init", { stdio: "ignore" }); + + didInit = true; + + execSync("git checkout -b main", { stdio: "ignore" }); + execSync("git add -A", { stdio: "ignore" }); + execSync('git commit -m "Initial commit from @pkgjs/statusboard"', { + stdio: "ignore", + }); + + return true; + } catch (e) { + if (didInit) { + try { + rm(join(path, ".git"), { recursive: true, force: true }); + } catch (_) {} + } + return false; + } +} diff --git a/package.json b/package.json index 926baa5..3c601c3 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@wesleytodd/buildjs": "0.0.8", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "cptmpl": "0.0.4", + "create-package-json": "^1.1.0", "dotenv": "^8.0.0", "es5-lit-element": "^2.2.1", "express": "^4.17.1",