@fountainhead/branch-officer
Advanced tools
Comparing version 1.1.0 to 2.0.0
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = require("fs"); | ||
const js_yaml_1 = require("js-yaml"); | ||
const ramda_1 = require("ramda"); | ||
const util_1 = require("util"); | ||
@@ -18,18 +9,5 @@ const readFile = util_1.promisify(fs_1.readFile); | ||
/** | ||
* Parses a YAML string, escaping any Go Template values as regular strings so | ||
* they don't get messed with by the YAML parser. | ||
*/ | ||
exports.parse = ramda_1.pipe(ramda_1.replace(/({{.*}})/g, `'$1'`), js_yaml_1.safeLoad); | ||
/** | ||
* Dumps an object to a YAML string, reverting any escaped Go Templates to their | ||
* original 'bare' form. | ||
*/ | ||
exports.dump = ramda_1.pipe(obj => js_yaml_1.safeDump(obj), ramda_1.replace(/'({{.*}})'/g, '$1')); | ||
/** | ||
* Parses a YAML file from disk using special handling defined in `parse`. | ||
*/ | ||
exports.parseFile = (path) => __awaiter(this, void 0, void 0, function* () { | ||
const content = yield readFile(path, 'utf8'); | ||
return exports.parse(content); | ||
}); | ||
exports.parseFile = (path) => readFile(path, 'utf8').then(js_yaml_1.safeLoad); | ||
/** | ||
@@ -39,2 +17,2 @@ * Writes an Object to disk as a YAML file using any special handling defined in | ||
*/ | ||
exports.dumpFile = (path, obj) => writeFile(path, exports.dump(obj)); | ||
exports.dumpFile = (path, obj) => writeFile(path, js_yaml_1.safeDump(obj)); |
@@ -8,3 +8,3 @@ "use strict"; | ||
const diff_1 = require("diff"); | ||
const helmfile_1 = require("../helmfile"); | ||
const js_yaml_1 = require("js-yaml"); | ||
exports.pullRequest = (task) => { | ||
@@ -43,5 +43,5 @@ if (!task.pullRequest) { | ||
} | ||
const values = helmfile_1.dump(task.release.values); | ||
const values = js_yaml_1.safeDump(task.release.values); | ||
if (task.action === 'update') { | ||
const oldValues = helmfile_1.dump(task.oldRelease.values); | ||
const oldValues = js_yaml_1.safeDump(task.oldRelease.values); | ||
const diff = diff_1.diffLines(oldValues, values); | ||
@@ -48,0 +48,0 @@ return diff |
{ | ||
"name": "@fountainhead/branch-officer", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "Automates the deployment of GitHub Pull Requests as Preview Environments using Helm and Helmfile", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
170
README.md
# branch-officer | ||
Automates the deployment of GitHub Pull Requests as Preview Environments using Helm and Helmfile | ||
Automates the deployment of GitHub Pull Requests as Preview Environments using | ||
Helm and Helmfile. | ||
[![CircleCI](https://circleci.com/gh/FountainheadTechnologies/branch-officer/tree/master.svg?style=svg&circle-token=17c4432ad0719b66131ee5982ad575a6c39f2956)](https://circleci.com/gh/FountainheadTechnologies/branch-officer/tree/master) | ||
## Installation | ||
```bash | ||
npm install -g @fountainhead/branch-officer | ||
``` | ||
## Basic Usage | ||
Branch Officer typically runs as part of your Continuous Integeration/Deployment | ||
workflow (although it can be run through other means), so it expects a | ||
`GITHUB_TOKEN` environment variable. Once this is set, you can invoke it like | ||
so: | ||
```bash | ||
branch-officer \ | ||
--file $(pwd)/helmfile.d/preview-environments.yaml \ | ||
--owner KontosoCorporation \ | ||
--repo WidgetWarehouse | ||
``` | ||
In this example, Branch Officer will enumerate all currently open on the | ||
`KontosoCorporation/WidgetWarehouse` repository, compare the `releases` entry in | ||
the Helmfile `preview-environments.yaml`, and display a table of Release entries | ||
that will be created, modified, deleted or left un-modified. | ||
If you are satisfied with the proposed changes, you may add the `--apply` flag | ||
to modify the supplied Helmfile accordingly: | ||
```bash | ||
branch-officer \ | ||
--file $(pwd)/helmfile.d/preview-environments.yaml \ | ||
--owner KontosoCorporation \ | ||
--repo WidgetWarehouse \ | ||
--apply | ||
``` | ||
The changes to your Helmfile may then be committed to version control and | ||
applied to your cluster using `helmfile sync`. | ||
## Advanced Usage | ||
### Pull Request Metadata | ||
By default, Branch Officer will create a Release entry with the following | ||
structure: | ||
```yaml | ||
name: {{ name of the PR branch }} | ||
chart: charts/{{ owner name }}/{{ repo name }} | ||
values: | ||
image: | ||
tag: {{ SHA of the PR's most recent commit }} | ||
``` | ||
It is possible to modify the `values` of a Release on a per-release basis, by | ||
specifying 'metadata' in the Pull Request. This is encoded as YAML-formatted | ||
front-matter in the body of the Pull Request, which is then deep-merged with the | ||
default structure. | ||
For example, if the body of your Pull Request looks like this: | ||
```yaml | ||
--- | ||
apiReplicas: 2 | ||
uiReplicas: 1 | ||
--- | ||
This patch addresses the race condition caused by multiple API server instances | ||
competing over a shared resource. To demonstrate that this works, I've set the | ||
'apiReplicas' value in the Helm Release to '2'. | ||
``` | ||
Then the Values will be merged into the Helmfile like so: | ||
```yaml | ||
name: fix-race-condition | ||
chart: charts/KontosoCorporation/WidgetWarehouse | ||
values: | ||
apiReplicas: 2 | ||
uiReplicas: 1 | ||
image: | ||
tag: {{ SHA of the PR's most recent commit }} | ||
``` | ||
In order to create more exotic Release entries, including modification of | ||
properties outside of `release.values`, please refer to the next section. | ||
### Custom Pull Request > Release Mapper | ||
It is also possible to create a JavaScript function that allows full control | ||
over the Release entry that will be created in the Helmfile. For example, use | ||
the SHA of the PR's most recent commit to update multiple images, create a | ||
mapper like so: | ||
```javascript | ||
// mapPrToRelease.js | ||
module.exports = ({branch, parsedMetadata, sha}) => ({ | ||
name: branch, | ||
chart: 'charts/kontoso', | ||
values: [{ | ||
api: { | ||
image: { | ||
name: 'quay.io/kontoso/widget-warehouse-api' | ||
tag: `sha-${sha}` | ||
}, | ||
ui: { | ||
image: { | ||
name: 'quay.io/kontoso/widget-warehouse-ui' | ||
tag: `sha-${sha}` | ||
} | ||
}] | ||
}) | ||
``` | ||
Then, use the `--mapper` argument to specify a path to the Mapper file: | ||
```bash | ||
branch-officer \ | ||
--file $(pwd)/helmfile.d/preview-environments.yaml \ | ||
--mapper $(pwd)/mapPrToRelease.js \ | ||
--owner KontosoCorporation \ | ||
--repo WidgetWarehouse \ | ||
--apply | ||
``` | ||
The function exported by your Mapper file will be called with an object | ||
containing the following properties: | ||
- `number (number)`- The Pull Request number. For example, `123`. | ||
- `title (string)` - The Title of the Pull Request. For example, `'Fix Race | ||
Condition'`. | ||
- `body (string)` - The Body of the Pull Request. | ||
- `sha (string)` - The SHA of the most recent commit on the Pull Request. | ||
- `branch (string)` - The name of the branch the Pull Request was made for. | ||
- `parsedMetadata (object)` - Any YAML-formatted front matter from the body of | ||
the Pull Request, parsed as an Object. If no metadata was supplied or parsing | ||
failed, this defaults to an empty object (`{}`). | ||
- `buildSucceeded (boolean)` - Whether all reported 'build statuses' on the PR | ||
have passed. This is always `true`, as the Mapper function will *not* be | ||
called for failing PRs. | ||
### Required Status Checks | ||
By default, Branch Officer requires that *all* applicable Status Checks pass in | ||
order for a Release to be created/updated. If a PR is currently failing to be | ||
built, it will be ignored. | ||
It may be desirable to only require certain status checks to be considered. This | ||
is possible by supplying the `--requiredStatusChecks` argument. This argument | ||
may be passed multiple times to specify multiple required statuses. For example, | ||
to allow a release to be created/updated for a PR provided it passes the status | ||
checks named `ci/circleci: test_ui` *and* `ci/circleci: test_api`, use the | ||
following invocation: | ||
```bash | ||
branch-officer \ | ||
--file $(pwd)/helmfile.d/preview-environments.yaml \ | ||
--owner KontosoCorporation \ | ||
--repo WidgetWarehouse \ | ||
--requiredStatusChecks "ci/circleci: test_ui" \ | ||
--requiredStatusChecks "ci/circleci: test_api" \ | ||
--apply | ||
``` |
28406
171
522