import commandExists from 'command-exists'; import { readFileSync, promises as fs } from 'fs'; import { prompt } from 'inquirer'; import kebabCase from 'lodash/kebabCase'; import path from 'path'; import gitPromise from 'simple-git/promise'; import { useSpinner } from '../../utils/useSpinner'; import { rmdir } from '../../utils/rmdir'; import { promptInput, promptConfirm } from '../../utils/prompt'; import chalk from 'chalk'; const simpleGit = gitPromise(process.cwd()); interface PluginDetails { name: string; org: string; description: string; author: boolean | string; url: string; keywords: string; } type PluginType = 'angular-panel' | 'react-panel' | 'datasource-plugin'; const RepositoriesPaths = { 'angular-panel': 'git@github.com:grafana/simple-angular-panel.git', 'react-panel': 'git@github.com:grafana/simple-react-panel.git', 'datasource-plugin': 'git@github.com:grafana/simple-datasource.git', }; export const getGitUsername = async () => await simpleGit.raw(['config', '--global', 'user.name']); export const getPluginIdFromName = (name: string) => kebabCase(name); export const getPluginId = (pluginDetails: PluginDetails) => `${kebabCase(pluginDetails.org)}-${getPluginIdFromName(pluginDetails.name)}`; export const getPluginKeywords = (pluginDetails: PluginDetails) => pluginDetails.keywords .split(',') .map(k => k.trim()) .filter(k => k !== ''); export const verifyGitExists = async () => { return new Promise((resolve, reject) => { commandExists('git', (err, exists) => { if (exists) { resolve(true); } reject(new Error('git is not installed')); }); }); }; export const promptPluginType = async () => prompt<{ type: PluginType }>([ { type: 'list', message: 'Select plugin type', name: 'type', choices: [ { name: 'Angular panel', value: 'angular-panel' }, { name: 'React panel', value: 'react-panel' }, { name: 'Datasource plugin', value: 'datasource-plugin' }, ], }, ]); export const promptPluginDetails = async (name?: string) => { const username = (await getGitUsername()).trim(); const responses = await prompt([ promptInput('name', 'Plugin name', true, name), promptInput('org', 'Organization (used as part of plugin ID)', true), promptInput('description', 'Description'), promptInput('keywords', 'Keywords (separated by comma)'), // Try using git specified username promptConfirm('author', `Author (${username})`, username, username !== ''), // Prompt for manual author entry if no git user.name specifed promptInput('author', `Author`, true, undefined, answers => !answers.author || username === ''), promptInput('url', 'Your URL (i.e. organisation url)'), ]); return { ...responses, author: responses.author === true ? username : responses.author, }; }; export const fetchTemplate = useSpinner<{ type: PluginType; dest: string }>( 'Fetching plugin template...', async ({ type, dest }) => { const url = RepositoriesPaths[type]; if (!url) { throw new Error('Unknown plugin type'); } await simpleGit.clone(url, dest); } ); export const prepareJsonFiles = useSpinner<{ pluginDetails: PluginDetails; pluginPath: string }>( 'Saving package.json and plugin.json files', async ({ pluginDetails, pluginPath }) => { const packageJsonPath = path.resolve(pluginPath, 'package.json'); const pluginJsonPath = path.resolve(pluginPath, 'src/plugin.json'); const packageJson: any = JSON.parse(readFileSync(packageJsonPath, 'utf8')); const pluginJson: any = JSON.parse(readFileSync(pluginJsonPath, 'utf8')); const pluginId = `${kebabCase(pluginDetails.org)}-${getPluginIdFromName(pluginDetails.name)}`; packageJson.name = pluginId; packageJson.author = pluginDetails.author; packageJson.description = pluginDetails.description; pluginJson.name = pluginDetails.name; pluginJson.id = pluginId; pluginJson.info = { ...pluginJson.info, description: pluginDetails.description, author: { name: pluginDetails.author, url: pluginDetails.url, }, keywords: getPluginKeywords(pluginDetails), }; await Promise.all( [packageJson, pluginJson].map((f, i) => { const filePath = i === 0 ? packageJsonPath : pluginJsonPath; return fs.writeFile(filePath, JSON.stringify(f, null, 2)); }) ); } ); export const removeGitFiles = useSpinner('Cleaning', async pluginPath => rmdir(`${path.resolve(pluginPath, '.git')}`)); export const formatPluginDetails = (details: PluginDetails) => { console.group(); console.log(); console.log(chalk.bold.yellow('Your plugin details')); console.log('---'); console.log(chalk.bold('Name: '), details.name); console.log(chalk.bold('ID: '), getPluginId(details)); console.log(chalk.bold('Description: '), details.description); console.log(chalk.bold('Keywords: '), getPluginKeywords(details)); console.log(chalk.bold('Author: '), details.author); console.log(chalk.bold('Organisation: '), details.org); console.log(chalk.bold('Website: '), details.url); console.log(); console.groupEnd(); };