Skip to content

Commit

Permalink
fix: GraphQL create command
Browse files Browse the repository at this point in the history
Fixes #387
  • Loading branch information
maticzav committed Jan 21, 2019
1 parent d716df5 commit 39d5ba4
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 122 deletions.
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
"@types/node": "10.12.18",
"@types/node-fetch": "2.1.3",
"@types/ora": "1.3.5",
"@types/request": "2.48.1",
"@types/rimraf": "2.0.2",
"@types/yargs": "12.0.1",
"ava": "0.25.0",
Expand All @@ -73,10 +72,10 @@
"typescript": "3.2.4"
},
"dependencies": {
"adm-zip": "0.4.13",
"apollo-codegen": "^0.20.2",
"chalk": "^2.4.1",
"command-exists": "^1.2.8",
"creato": "^1.0.3",
"cross-spawn": "^6.0.5",
"disparity": "^2.0.0",
"dotenv": "^6.1.0",
Expand All @@ -99,8 +98,6 @@
"npm-run": "4.1.2",
"opn": "^5.4.0",
"ora": "^3.0.0",
"parse-github-url": "^1.0.2",
"request": "^2.88.0",
"rimraf": "2.6.3",
"source-map-support": "^0.5.9",
"tmp-graphql-config-extension-openapi": "^1.0.7",
Expand Down
81 changes: 58 additions & 23 deletions src/cmds/create/boilerplates.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Template } from 'creato'

export interface Boilerplate {
name: string
description: string
Expand All @@ -6,71 +8,104 @@ export interface Boilerplate {

// a list of available boilerplate projects from:
// https://github.com/graphql-boilerplates/
export const defaultBoilerplates: Boilerplate[] = [
export const defaultBoilerplates: Template[] = [
{
name: 'node-minimal',
description: '"Hello World" GraphQL server',
repo:
'https://github.com/graphql-boilerplates/node-graphql-server/tree/master/minimal',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/node-graphql-server',
path: '/minimal',
},
},
{
name: 'node-basic',
description: 'Basic GraphQL server (incl. database)',
repo:
'https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/node-graphql-server',
path: '/basic',
},
},
{
name: 'node-advanced',
description: 'GraphQL server (incl. database & authentication)',
repo:
'https://github.com/graphql-boilerplates/node-graphql-server/tree/master/advanced',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/node-graphql-server',
path: '/advanced',
},
},
{
name: 'typescript-minimal',
description: '"Hello World" GraphQL server',
repo:
'https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/minimal',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/typescript-graphql-server',
path: '/minimal',
},
},
{
name: 'typescript-basic',
description: 'Basic GraphQL server (incl. database)',
repo:
'https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/typescript-graphql-server',
path: '/basic',
},
},
{
name: 'typescript-advanced',
description: 'GraphQL server (incl. database & authentication)',
repo:
'https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/advanced',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/typescript-graphql-server',
path: '/advanced',
},
},
{
name: 'react-fullstack-minimal',
description: '"Hello World" fullstack app with React & GraphQL',
repo:
'https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/minimal',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/react-fullstack-graphql',
path: '/minimal',
},
},
{
name: 'react-fullstack-basic',
description: 'React app + GraphQL server (incl. database)',
repo:
'https://github.com/graphql-boilerplates/react-fullstack-graphql/tree/master/basic',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/react-fullstack-graphql',
path: '/basic',
},
},
{
name: 'vue-fullstack-minimal',
description: '"Hello World" fullstack app with Vue & GraphQL',
repo:
'https://github.com/graphql-boilerplates/vue-fullstack-graphql/tree/master/minimal',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/vue-fullstack-graphql',
path: '/minimal',
},
},
{
name: 'vue-fullstack-basic',
description: 'Vue app + GraphQL server (incl. database)',
repo:
'https://github.com/graphql-boilerplates/vue-fullstack-graphql/tree/master/basic',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/vue-fullstack-graphql',
path: '/basic',
},
},
{
name: 'vue-fullstack-advanced',
description: 'Vue app + GraphQL server (incl. database & authentication)',
repo:
'https://github.com/graphql-boilerplates/vue-fullstack-graphql/tree/master/advanced',
repo: {
branch: 'master',
uri: 'https://github.com/graphql-boilerplates/vue-fullstack-graphql',
path: '/advanced',
},
},
]
104 changes: 45 additions & 59 deletions src/cmds/create/index.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,48 @@
import * as Zip from 'adm-zip'
// import * as Zip from 'adm-zip'
import chalk from 'chalk'
import commandExists = require('command-exists')
import * as gh from 'parse-github-url'
import * as creato from 'creato'
// import * as gh from 'parse-github-url'
import { spawn } from 'cross-spawn'
import * as fs from 'fs'
import { padEnd } from 'lodash'
import * as path from 'path'
import * as request from 'request'
import * as tmp from 'tmp'
// import * as request from 'request'
// import * as tmp from 'tmp'
import * as rimraf from 'rimraf'

import { Context } from '../..'
import { defaultBoilerplates } from './boilerplates'
import { getZipInfo } from './utils'
// import { getZipInfo } from './utils'

export const command = 'create [directory]'
export const describe = 'Bootstrap a new GraphQL project'

export const builder = {
boilerplate: {
alias: 'b',
describe:
'Full URL or repo shorthand (e.g. `owner/repo`) to boilerplate GitHub repository',
type: 'string',
},
'no-install': {
describe: `Don't install project dependencies`,
type: 'boolean',
default: false,
},
}

function getGitHubUrl(boilerplate: string): string | undefined {
const details = gh(boilerplate)
// function getGitHubUrl(boilerplate: string): string | undefined {
// const details = gh(boilerplate)

if (details.host && details.owner && details.repo) {
const branch = details.branch ? `/tree/${details.branch}` : ''
return `https://${details.host}/${details.repo}${branch}`
}
}
// if (details.host && details.owner && details.repo) {
// const branch = details.branch ? `/tree/${details.branch}` : ''
// return `https://${details.host}/${details.repo}${branch}`
// }
// }

export async function handler(
context: Context,
argv: {
boilerplate?: string
directory?: string
noInstall: boolean
},
) {
let { boilerplate, directory, noInstall } = argv
let { directory, noInstall } = argv

if (directory && directory.match(/[A-Z]/)) {
console.log(
Expand Down Expand Up @@ -91,53 +85,45 @@ export async function handler(
fs.mkdirSync(projectPath)
}

// allow short handle boilerplate (e.g. `node-basic`)
if (boilerplate && !boilerplate.startsWith('http')) {
const matchedBoilerplate = defaultBoilerplates.find(
b => b.name === boilerplate,
)
if (matchedBoilerplate) {
boilerplate = matchedBoilerplate.repo
} else {
// allow shorthand GitHub URLs (e.g. `graphcool/graphcool-server-example`)
boilerplate = getGitHubUrl(boilerplate)
// interactive selection
const maxNameLength = defaultBoilerplates
.map(bp => bp.name.length)
.reduce((max, x) => Math.max(max, x), 0)
const choices = defaultBoilerplates.map(bp => {
return {
name: `${padEnd(bp.name, maxNameLength + 2)} ${bp.description}`,
value: bp,
}
}
})
const { choice } = await context.prompt<{ choice: creato.Template }>({
type: 'list',
name: 'choice',
message: `Choose GraphQL boilerplate project:`,
choices,
})

// interactive selection
if (!boilerplate) {
const maxNameLength = defaultBoilerplates
.map(bp => bp.name.length)
.reduce((max, x) => Math.max(max, x), 0)
const choices = defaultBoilerplates.map(
bp => `${padEnd(bp.name, maxNameLength + 2)} ${bp.description}`,
)
const { choice } = await context.prompt<{ choice: string }>({
type: 'list',
name: 'choice',
message: `Choose GraphQL boilerplate project:`,
choices,
})
const template = await creato.loadTemplate(choice, projectPath)

boilerplate = defaultBoilerplates[choices.indexOf(choice)].repo
if (template.status !== 'ok') {
throw new Error(template.message)
}

// download repo contents
const zipInfo = getZipInfo(boilerplate!)
const downloadUrl = zipInfo.url
const tmpFile = tmp.fileSync()
// // download repo contents

console.log(`[graphql create] Downloading boilerplate from ${downloadUrl}...`)
// const downloadUrl = zipInfo.url
// const tmpFile = tmp.fileSync()

await new Promise(resolve => {
request(downloadUrl)
.pipe(fs.createWriteStream(tmpFile.name))
.on('close', resolve)
})
// console.log(`[graphql create] Downloading boilerplate from ${downloadUrl}...`)

// await new Promise(resolve => {
// request(downloadUrl)
// .pipe(fs.createWriteStream(tmpFile.name))
// .on('close', resolve)
// })

const zip = new Zip(tmpFile.name)
zip.extractEntryTo(zipInfo.path, projectPath, false)
tmpFile.removeCallback()
// const zip = new Zip(tmpFile.name)
// zip.extractEntryTo(zipInfo.path, projectPath, false)
// tmpFile.removeCallback()

// run npm/yarn install
if (!noInstall) {
Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import {
ConfigNotFoundError,
resolveEnvsInValues,
} from 'graphql-config'
import * as updateNotifier from 'update-notifier'
const pkg = require('../package.json')
// import * as updateNotifier from 'update-notifier'
// const pkg = require('../package.json')
import 'source-map-support/register'

export * from './types'
export * from './utils'

updateNotifier({ pkg }).notify()
// updateNotifier({ pkg }).notify()

function listPluggings(dir: string): string[] {
return readdirSync(dir)
Expand Down
Loading

0 comments on commit 39d5ba4

Please sign in to comment.