Skip to content
This repository was archived by the owner on Apr 20, 2021. It is now read-only.

Commit 67ece20

Browse files
authored
Feat: add cli that uses a list of users to run a preview swarm (#336)
* add cli that uses a list of users to run a preview swarm * add cli visualization
1 parent 45b0641 commit 67ece20

34 files changed

+6812
-55
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules
22
public
33
dist
44
.cache
5+
build

.github/workflows/ci.yml

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ jobs:
1515
- uses: actions/checkout@v2
1616
- uses: bahmutov/npm-install@v1
1717
- run: yarn build && yarn ci-test 'yarn test-plugin'
18+
# @todo revisit this and make it work
19+
# it works locally but has networking issues on CI
20+
# test-preview:
21+
# name: E2E Tests - Preview
22+
# runs-on: ubuntu-16.04
23+
# steps:
24+
# - uses: actions/checkout@v2
25+
# - uses: bahmutov/npm-install@v1
26+
# - run: yarn build && yarn build-cli && yarn ci-test 'yarn test-preview'
1827
test-schema:
1928
name: Integration Tests - Schema
2029
runs-on: ubuntu-16.04

.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
dist
2+
build
23
node_modules
34
public
45
.cache

cli/.gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
node_modules
3+
npm-debug.log
4+
coverage
5+
.nyc_output
6+
dist
7+
build
8+
.vscode
9+
wp-e2e-utils

cli/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

cli/__tests__/cli-integration.test.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// eslint-disable-next-line @typescript-eslint/no-var-requires
2+
const { system, filesystem } = require(`gluegun`)
3+
4+
const src = filesystem.path(__dirname, `..`)
5+
6+
const cli = async (cmd): Promise<void> =>
7+
system.run(`node ` + filesystem.path(src, `bin`, `wpgatsby`) + ` ${cmd}`)
8+
9+
test(`outputs version`, async () => {
10+
const output = await cli(`--version`)
11+
expect(output).toContain(`0.0.1`)
12+
})
13+
14+
test(`outputs help`, async () => {
15+
const output = await cli(`--help`)
16+
expect(output).toContain(`0.0.1`)
17+
})
18+
19+
test(`generates file`, async () => {
20+
const output = await cli(`generate foo`)
21+
22+
expect(output).toContain(`Generated file at models/foo-model.ts`)
23+
const foomodel = filesystem.read(`models/foo-model.ts`)
24+
25+
expect(foomodel).toContain(`module.exports = {`)
26+
expect(foomodel).toContain(`name: 'foo'`)
27+
28+
// cleanup artifact
29+
filesystem.remove(`models`)
30+
})

cli/bin/wpgatsby

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env node
2+
3+
4+
/* tslint:disable */
5+
// check if we're running in dev mode
6+
var devMode = require('fs').existsSync(`${__dirname}/../src`)
7+
// or want to "force" running the compiled version with --compiled-build
8+
var wantsCompiled = process.argv.indexOf('--compiled-build') >= 0
9+
10+
if (wantsCompiled || !devMode) {
11+
// this runs from the compiled javascript source
12+
require(`${__dirname}/../build/cli`).run(process.argv)
13+
} else {
14+
// this runs from the typescript source (for dev only)
15+
// hook into ts-node so we can run typescript on the fly
16+
require('ts-node').register({ project: `${__dirname}/../tsconfig.json` })
17+
// run the CLI with the current process arguments
18+
require(`${__dirname}/../src/cli`).run(process.argv)
19+
}
20+
21+

cli/docs/commands.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Command Reference for wpgatsby
2+
3+
TODO: Add your command reference here

cli/docs/plugins.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Plugin guide for wpgatsby
2+
3+
Plugins allow you to add features to wpgatsby, such as commands and
4+
extensions to the `toolbox` object that provides the majority of the functionality
5+
used by wpgatsby.
6+
7+
Creating a wpgatsby plugin is easy. Just create a repo with two folders:
8+
9+
```
10+
commands/
11+
extensions/
12+
```
13+
14+
A command is a file that looks something like this:
15+
16+
```js
17+
// commands/foo.js
18+
19+
module.exports = {
20+
run: (toolbox) => {
21+
const { print, filesystem } = toolbox
22+
23+
const desktopDirectories = filesystem.subdirectories(`~/Desktop`)
24+
print.info(desktopDirectories)
25+
},
26+
}
27+
```
28+
29+
An extension lets you add additional features to the `toolbox`.
30+
31+
```js
32+
// extensions/bar-extension.js
33+
34+
module.exports = (toolbox) => {
35+
const { print } = toolbox
36+
37+
toolbox.bar = () => {
38+
print.info("Bar!")
39+
}
40+
}
41+
```
42+
43+
This is then accessible in your plugin's commands as `toolbox.bar`.
44+
45+
# Loading a plugin
46+
47+
To load a particular plugin (which has to start with `wpgatsby-*`),
48+
install it to your project using `npm install --save-dev wpgatsby-PLUGINNAME`,
49+
and wpgatsby will pick it up automatically.

cli/package.json

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"name": "wpgatsby",
3+
"version": "0.1.0",
4+
"description": "WPGatsby test CLI",
5+
"private": false,
6+
"types": "build/types/types.d.ts",
7+
"bin": {
8+
"wpgatsby": "bin/wpgatsby"
9+
},
10+
"scripts": {
11+
"clean-build": "rm -rf ./build",
12+
"compile": "tsc -p .",
13+
"copy-templates": "if [ -e ./src/templates ]; then cp -a ./src/templates ./build/; fi",
14+
"build": "yarn clean-build && yarn compile && yarn copy-templates",
15+
"prepublishOnly": "yarn build",
16+
"test": "jest",
17+
"watch": "jest --watch",
18+
"snapupdate": "jest --updateSnapshot",
19+
"coverage": "jest --coverage"
20+
},
21+
"files": [
22+
"tsconfig.json",
23+
"build",
24+
"LICENSE",
25+
"readme.md",
26+
"docs",
27+
"bin"
28+
],
29+
"license": "MIT",
30+
"dependencies": {
31+
"@wordpress/e2e-test-utils": "^4.15.0",
32+
"@wordpress/keycodes": "^2.16.0",
33+
"draftlog": "^1.0.12",
34+
"fs-extra": "^9.0.1",
35+
"gluegun": "latest",
36+
"lodash": "^4.17.20",
37+
"puppeteer": "^5.5.0"
38+
},
39+
"devDependencies": {
40+
"@types/jest": "^24.0.18",
41+
"@types/node": "^12.7.11",
42+
"@types/puppeteer": "^5.4.0",
43+
"jest": "^24.1.0",
44+
"ts-jest": "^24.1.0",
45+
"ts-node": "^8.4.1",
46+
"tslint": "^5.12.0",
47+
"tslint-config-prettier": "^1.17.0",
48+
"tslint-config-standard": "^8.0.1",
49+
"typescript": "^4.1.2"
50+
},
51+
"jest": {
52+
"preset": "ts-jest",
53+
"testEnvironment": "node"
54+
}
55+
}

cli/readme.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# wpgatsby CLI
2+
3+
A CLI for wpgatsby.
4+
5+
## Customizing your CLI
6+
7+
Check out the documentation at https://github.com/infinitered/gluegun/tree/master/docs.
8+
9+
## Publishing to NPM
10+
11+
To package your CLI up for NPM, do this:
12+
13+
```shell
14+
$ npm login
15+
$ npm whoami
16+
$ npm lint
17+
$ npm test
18+
(if typescript, run `npm run build` here)
19+
$ npm publish
20+
```
21+
22+
# License
23+
24+
MIT - see LICENSE

cli/src/cli.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// eslint-disable-next-line @typescript-eslint/no-var-requires
2+
const { build } = require(`gluegun`)
3+
4+
/**
5+
* Create the cli and kick it off
6+
*/
7+
async function run(argv): Promise<void> {
8+
// create a CLI runtime
9+
const cli = build()
10+
.brand(`wpgatsby`)
11+
.src(__dirname)
12+
.plugins(`./node_modules`, { matching: `wpgatsby-*`, hidden: true })
13+
.help() // provides default for help, h, --help, -h
14+
.version() // provides default for version, v, --version, -v
15+
.defaultCommand()
16+
.create()
17+
// enable the following method if you'd like to skip loading one of these core extensions
18+
// this can improve performance if they're not necessary for your project:
19+
// .exclude(['meta', 'strings', 'print', 'filesystem', 'semver', 'system', 'prompt', 'http', 'template', 'patching', 'package-manager'])
20+
// and run it
21+
const toolbox = await cli.run(argv)
22+
23+
// send it back (for testing, mostly)
24+
return toolbox
25+
}
26+
27+
module.exports = { run }

cli/src/commands/generate.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { GluegunToolbox } from "gluegun"
2+
3+
module.exports = {
4+
name: `generate`,
5+
alias: [`g`],
6+
run: async (toolbox: GluegunToolbox): Promise<void> => {
7+
const {
8+
parameters,
9+
template: { generate },
10+
print: { info },
11+
} = toolbox
12+
13+
const name = parameters.first
14+
15+
await generate({
16+
template: `model.ts.ejs`,
17+
target: `models/${name}-model.ts`,
18+
props: { name },
19+
})
20+
21+
info(`Generated file at models/${name}-model.ts`)
22+
},
23+
}

cli/src/commands/preview/swarm.ts

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { GluegunCommand, GluegunToolbox } from "gluegun"
2+
3+
import * as fs from "fs-extra"
4+
5+
import { runPreviewSwarm } from "../../utils/wordpress-puppeteer/run-preview-swarm"
6+
7+
const command: GluegunCommand = {
8+
name: `swarm`,
9+
commandPath: [`preview`, `swarm`],
10+
dashed: true,
11+
description: `Swarm a Gatsby Preview instance with bot WP users`,
12+
run: async (toolbox: GluegunToolbox) => {
13+
const { print, prompt, parameters } = toolbox
14+
15+
const {
16+
wpUrl: optionWpUrl,
17+
users: optionUsersJsonPath,
18+
previewRefreshUrl,
19+
previewFrontendUrl,
20+
timeout,
21+
previewsEach,
22+
debugMode,
23+
} = parameters.options
24+
25+
print.info(
26+
`We're going to toast your WP and Gatsby and then smatter them with delicious jam`
27+
)
28+
29+
let { wpUrl, wpUsersJsonPath } = await prompt.ask([
30+
!optionWpUrl && {
31+
type: `input`,
32+
name: `wpUrl`,
33+
message: `What's the full URL for your WordPress instance?`,
34+
},
35+
!optionUsersJsonPath && {
36+
type: `input`,
37+
name: `wpUsersJsonPath`,
38+
message: `What's the path to your users.json file?`,
39+
},
40+
])
41+
42+
if (optionWpUrl) {
43+
wpUrl = optionWpUrl
44+
}
45+
46+
if (optionUsersJsonPath) {
47+
wpUsersJsonPath = optionUsersJsonPath
48+
}
49+
50+
if (!wpUsersJsonPath) {
51+
print.error(`You must provide a path to your users.json file.`)
52+
}
53+
54+
if (!wpUrl) {
55+
print.error(`You must provide the home url for your WordPress instance.`)
56+
}
57+
58+
if (!wpUsersJsonPath || !wpUrl) {
59+
return
60+
}
61+
62+
const users = await fs.readJson(wpUsersJsonPath)
63+
64+
await runPreviewSwarm({
65+
headless: false,
66+
maxPreviewsEach: previewsEach || 10,
67+
previewTimeout: timeout,
68+
users,
69+
wpUrl,
70+
gatsbyPreviewFrontendUrl: previewFrontendUrl,
71+
gatsbyPreviewRefreshEndpoint: previewRefreshUrl,
72+
debugMode,
73+
})
74+
},
75+
}
76+
77+
module.exports = command

cli/src/extensions/cli-extension.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { GluegunToolbox } from "gluegun"
2+
3+
// add your CLI-specific functionality here, which will then be accessible
4+
// to your commands
5+
module.exports = (toolbox: GluegunToolbox): void => {
6+
toolbox.foo = (): void => {
7+
toolbox.print.info(`called foo extension`)
8+
}
9+
10+
// enable this if you want to read configuration in from
11+
// the current folder's package.json (in a "wpgatsby" property),
12+
// wpgatsby.config.json, etc.
13+
// toolbox.config = {
14+
// ...toolbox.config,
15+
// ...toolbox.config.loadConfig("wpgatsby", process.cwd())
16+
// }
17+
}

0 commit comments

Comments
 (0)