Skip to content
This repository has been archived by the owner on Mar 22, 2024. It is now read-only.

Commit

Permalink
bootstrap 2, closes #131 (#132)
Browse files Browse the repository at this point in the history
* new bootstrap
 🐿 v2.10.3

* refactor docs
 🐿 v2.10.3

* tpyo
 🐿 v2.10.3

* refactor commands to use yargs more
 🐿 v2.10.3

* add update-bootstrap command
 🐿 v2.10.3

* wait wait wait it has 𝒕𝒆𝒔𝒕𝒔
 🐿 v2.10.3

* add update-bootstrap target, document command
 🐿 v2.10.3

* add link
  • Loading branch information
apaleslimghost authored Oct 4, 2018
1 parent be27062 commit 02ad5d4
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 81 deletions.
63 changes: 31 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ then create a new `Makefile` file with the following:

```make
# n-gage bootstrapping logic
node_modules/@financial-times/n-gage/index.mk:
npm install --no-save --no-package-lock @financial-times/n-gage
touch $@

-include node_modules/@financial-times/n-gage/index.mk
include $(shell npx -p @financial-times/n-gage ngage bootstrap)
```

See [here](#bootstrapping) for more explanation of the bootstrapping logic. You will want to add `unit-test`, `test`, `provision`, `smoke` and `deploy` tasks to the `Makefile`. See other, similar Next projects for ideas.
See [the bootstrap command documentation](#bootstrap) for more explanation of this logic. You will want to add `unit-test`, `test`, `provision`, `smoke` and `deploy` tasks to the `Makefile`. See other, similar Next projects for ideas.

If your Makefile is using the [old bootstrap code](https://github.com/Financial-Times/n-gage/blob/v2.0.4/README.md#getting-started), you should update to the new bootstrap by running `make update-bootstrap` (or [`ngage update-bootstrap Makefile`](#update-bootstrap)). The new bootstrapping code is backwards compatible, and old-bootstrap makefiles will continue to work, but future improvements to the bootstrap are far easier to distribute with the new method.

## Make tasks

Expand All @@ -38,14 +36,25 @@ See in [index.mk](index.mk) for all the different tasks you can use in your `Mak

This includes a CLI for you to use to do some things.

### get-config
```sh
$ ngage --help
ngage <command>

This tool helps you to obtain configuration for your project.
Commands:
ngage bootstrap called by makefiles to include n-gage
ngage get-config get environment variables from Vault
ngage update-bootstrap <makefile> migrate a makefile from bootstrap v1 to v2

```sh
$ ngage
ngage get-config --help
Options:
--version Show version number [boolean]
--help Show help [boolean]
```

### `get-config`

This command helps you to obtain configuration for your project.

```sh
$ ngage get-config --help
Options:
--help Show help [boolean]
Expand All @@ -66,13 +75,13 @@ $ cat .env-ci
}
```
The `--team` option lets you specify a team if not `next` (must match Vault path).
```sh
$ ngage get-config --team myteam
```
The `--team` option lets you specify a team if not `next` (must match Vault path).

### FT User Sessions
#### FT User Sessions
To get `FTSession` and `FTSession_s` environment variables to be populated with up-to-date session tokens from test users, add the following environment variables to your `development` and/or `continuous-integration` configs in the Vault:
Expand All @@ -86,27 +95,17 @@ As a result of this, `{USER_TYPE}_FTSession` and `{USER_TYPE}_FTSession_s` envir
Multiple user types can be specified in the TEST_USER_TYPES variable.
*Example*
##### Example
If you set `TEST_USER_TYPES` environment variable to `premium,standard`, these variables will be populated in the `.env` file:
`PREMIUM_FTSession`, `PREMIUM_FTSession_s`, `STANDARD_FTSession`, `STANDARD_FTSession_s`
## Bootstrapping
### `bootstrap`
Curious how the bootstrapping bit at top of the `Makefile` works? Here's the annotated code:
The `bootstrap` command is the main entry point to `n-gage` for makefiles. On its own, it outputs the path to `index.mk`. It's intended to be run using `make`'s `$(shell)` function, passing the result to `include`.
```make
# This task tells make how to 'build' n-gage. It npm installs n-gage, and
# Once that's done it overwrites the file with its own contents - this
# ensures the timestamp on the file is recent, so make won't think the file
# is out of date and try to rebuild it every time
node_modules/@financial-times/n-gage/index.mk:
npm install --no-save @financial-times/n-gage
touch $@

# If, by the end of parsing your `Makefile`, `make` finds that any files
# referenced with `-include` don't exist or are out of date, it will run any
# tasks it finds that match the missing file. So if n-gage *is* installed
# it will just be included; if not, it will look for a task to run
-include node_modules/@financial-times/n-gage/index.mk
```
Running this command using [`npx`](https://www.npmjs.com/package/npx) (which is included in `npm` v5 and above) will use the `n-gage` installed in `node_modules`, if it's there; if not, it'll install it. This lets you run `make` without first running `npm install`, and subsequent runs of `make install` won't be interfered with because the automatically-installed `n-gage` is stored in `npm`'s cache, not `node_modules`.
### `update-bootstrap`
Updates the makefile passed in from v1 bootstrap to v2. See [this Pull Request](https://github.com/Financial-Times/n-gage/pull/132#issue-219628923) for context. If the original bootstrap has been modified in your makefile, this command won't do anything, but print out what it expected to see and what to replace it with.
4 changes: 4 additions & 0 deletions index.mk
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ DONE = echo ✓ $@ done
IS_USER_FACING = `find . -type d \( -path ./bower_components -o -path ./node_modules -o -path ./coverage \) -prune -o -name '*.html' -print`
MAKEFILE_HAS_A11Y = `grep -rli "a11y" Makefile`
REPLACE_IN_GITIGNORE = sed -i -e 's/$1/$2/g' .gitignore && rm -f .gitignore-e ||:
ENTRY_MAKEFILE = $(firstword $(MAKEFILE_LIST))

# Show help when run without any target
.DEFAULT_GOAL := help
Expand Down Expand Up @@ -283,6 +284,9 @@ else
fi;
endif

update-bootstrap: ## update-bootstrap: update makefile bootstrap v1 to v2
ngage update-bootstrap $(ENTRY_MAKEFILE)

# some aliases
css:
nui build --sass-only
Expand Down
5 changes: 5 additions & 0 deletions scripts/commands/bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.command = 'bootstrap';
exports.describe = 'called by makefiles to include n-gage';
exports.handler = () => {
console.log(require.resolve('../index.mk'));
};
53 changes: 29 additions & 24 deletions scripts/get-config.js → scripts/commands/get-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ const fetch = require('@financial-times/n-fetch');
const fs = require('fs');
const path = require('path');
const os = require('os');
const appendSessionTokens = require('./append-session-tokens');
const appendSessionTokens = require('../append-session-tokens');

const opts = require('yargs')
.option('app', (() => {
exports.command = 'get-config';
exports.describe = 'get environment variables from Vault';

exports.builder = yargs => (yargs
.option('app', (() => {
// try get app name from the package.json
try {
return {
Expand All @@ -19,24 +22,24 @@ const opts = require('yargs')
}
}
})())
.option('env', {
.option('env', {
choices: ['dev', 'prod', 'ci', 'test'],
default: 'dev'
})
.option('filename', {
.option('filename', {
coerce: value => typeof value === 'string' ? value : '.env',
default: '.env'
})
.option('format', {
.option('format', {

choices: ['simple', 'json'],
default: 'simple'
})
.option('team', {
.option('team', {
coerce: value => typeof value === 'string' ? value : 'next',
default: 'next'
})
.help()
.argv;
})
);

const getToken = () => {
if (process.env.CIRCLECI) {
Expand Down Expand Up @@ -64,15 +67,16 @@ const getVaultPaths = (ftApp, env, team) => {
const app = ftApp.replace(/^ft-/, '');
const vaultEnvs = { dev: 'development', prod: 'production', ci: 'continuous-integration', test: 'test' };
const vaultEnv = vaultEnvs[env];

return [
`secret/teams/${team}/${app}/${vaultEnv}`,
`secret/teams/${team}/${app}/shared`,
`secret/teams/${team}/shared/${vaultEnv}`
];
};

const parseKeys = (app, appShared, envShared) => {
if (opts.env === 'ci') {
const parseKeys = (env, app, appShared, envShared) => {
if (env === 'ci') {
return Object.assign({}, app.env, envShared);
} else {
const shared = appShared.env.reduce((keys, key) => {
Expand All @@ -97,34 +101,35 @@ const format = (keys, mode) => {

// LET'S GO!

module.exports = () => {
exports.handler = argv => {
getToken()
.then(token => {
return Promise.all(getVaultPaths(opts.app, opts.env, opts.team).map(path => {
return Promise.all(getVaultPaths(argv.app, argv.env, argv.team).map(path => {
const url = 'https://vault.in.ft.com/v1/' + path;
console.log(url);

const vaultFetch = fetch(url, { headers: { 'X-Vault-Token': token } })
.then(json => json.data || {});
.then(json => json.data || {});

if (opts.env === 'dev') {
if (argv.env === 'dev') {
return vaultFetch.catch(err => {
console.warn(`Couldn't get config at ${url}.`);
});
} else {
return vaultFetch;
}
}))
.then(([app, appShared, envShared]) => parseKeys(app, appShared, envShared))
.then(([app, appShared, envShared]) => parseKeys(argv.env, app, appShared, envShared))
.then((keys) => appendSessionTokens(keys))
.then((keys) => {
const content = format(keys, opts.format);
const file = path.join(process.cwd(), opts.filename || '.env');
const content = format(keys, argv.format);
const file = path.join(process.cwd(), argv.filename || '.env');
fs.writeFileSync(file, content);
console.log(`Written ${opts.app}'s ${opts.env} config to ${file}`);
console.log(`Written ${argv.app}'s ${argv.env} config to ${file}`);
});
})
.catch(error => {
console.error(error);
process.exit(14);
});
.catch(error => {
console.error(error);
process.exit(14);
});
};
55 changes: 55 additions & 0 deletions scripts/commands/update-bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const fs = require('fs');

exports.command = 'update-bootstrap <makefile>';
exports.describe = 'migrate a makefile from bootstrap v1 to v2';

const oldBootstrap = `node_modules/@financial-times/n-gage/index.mk:
npm install --no-save --no-package-lock @financial-times/n-gage
touch $@
-include node_modules/@financial-times/n-gage/index.mk`;

const newBootstrap = 'include $(shell npx -p @financial-times/n-gage ngage bootstrap)';

const twee = 'have a nice day! xoxoxox';

exports.handler = argv => {
let content;

try {
content = fs.readFileSync(argv.makefile, 'utf8');
} catch(e) {
// probably the file doesn't exist. this shouldn't happen unless someone runs `ngage update-bootstrap nonexistent/Makefile`
console.log(`yeah we couldn't read from ${argv.makefile}, make sure that's a real thing`);
throw e;
}

const replaced = content.replace(oldBootstrap, newBootstrap);

if(replaced === content) {
console.log(
`looks like your makefile isn't using the standard n-gage v1 bootstrap, or it's already been migrated to v2. have a look at ${argv.makefile}, and if there's something that looks like:
${oldBootstrap}
please replace it with:
${newBootstrap}
${twee}`);

return;
}

try {
fs.writeFileSync(argv.makefile, replaced, 'utf8');
} catch(e) {
console.log(`yeah we couldn't write to ${argv.makefile}, dunno what's up with that, sorry,`);
throw e;
}

console.log(
`bootstrap updated to v2! check that ${argv.makefile} looks good and commit it plz
${twee}`);
};
10 changes: 5 additions & 5 deletions scripts/ngage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

if (process.argv.length > 1 && process.argv[2] === 'get-config') {
require('./get-config')();
} else {
console.log('ngage get-config --help');
}
require('yargs')
.commandDir('commands')
.demandCommand()
.help()
.argv;
Loading

0 comments on commit 02ad5d4

Please sign in to comment.