@adobe/helix-cli
Version:
Project Helix CLI
213 lines (190 loc) • 6.24 kB
JavaScript
/*
* Copyright 2018 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
const request = require('request-promise-native');
const fastly = require('@adobe/fastly-native-promises');
const chalk = require('chalk');
const ProgressBar = require('progress');
const AbstractCommand = require('./abstract.cmd.js');
class RemotePublishCommand extends AbstractCommand {
constructor(logger) {
super(logger);
this._wsk_auth = null;
this._wsk_namespace = null;
this._wsk_host = null;
this._fastly_namespace = null;
this._fastly_auth = null;
this._dryRun = false;
}
tick(ticks = 1, message, name) {
if (name === true) {
// eslint-disable-next-line no-param-reassign
name = message;
}
this.progressBar().tick(ticks, {
action: name || '',
});
if (message) {
this.log.log({
progress: true,
level: 'info',
message,
});
}
}
progressBar() {
if (this._bar) {
return this._bar;
}
this._bar = new ProgressBar('Publishing [:bar] :action :etas', {
total: 23,
width: 50,
renderThrottle: 1,
stream: process.stdout,
});
return this._bar;
}
withWskHost(value) {
this._wsk_host = value;
return this;
}
withWskAuth(value) {
this._wsk_auth = value;
return this;
}
withWskNamespace(value) {
this._wsk_namespace = value;
return this;
}
withFastlyNamespace(value) {
this._fastly_namespace = value;
return this;
}
withFastlyAuth(value) {
this._fastly_auth = value;
return this;
}
withDryRun(value) {
this._dryRun = value;
return this;
}
showNextStep(dryrun) {
this.progressBar().terminate();
if (dryrun) {
this.log.info(`✅ A new version has been prepared, but not activated. See version ${this._version} in the Fastly UI at:`);
this.log.info(chalk.grey(`https://manage.fastly.com/configure/services/${this._fastly_namespace}/versions/${this._version}/domains`));
} else {
const urls = this.config.strains.getByFilter(strain => strain.url).map(strain => strain.url);
this.log.info(`✅ The following strains have been published and version ${this._version} is now online:`);
this.config.strains.getByFilter(strain => !!strain.url).forEach((strain) => {
const { url } = strain;
urls.push(url);
this.log.info(`- ${strain.name}: ${url}`);
});
if (urls.length) {
this.log.info('\nYou may now access your site using:');
this.log.info(chalk.grey(`$ curl ${urls[0]}`));
}
}
}
serviceAddLogger() {
return request.post('https://adobeioruntime.net/api/v1/web/helix/default/addlogger', {
json: true,
body: {
service: this._fastly_namespace,
token: this._fastly_auth,
version: this._version,
},
}).then(() => {
this.tick(10, 'set up logging', true);
}).catch((e) => {
this.tick(10, 'failed to set up logging', true);
this.log.error(`Remote addlogger service failed ${e}`);
throw new Error('Unable to set up remote logging');
});
}
purgeFastly() {
if (this._dryRun) {
this.tick(1, 'skipping cache purge');
return false;
}
return this._fastly.purgeAll()
.then(() => {
this.tick(1, 'purged cache', true);
return true;
})
.catch((e) => {
this.tick(1, 'failed to purge cache', true);
this.log.error(`Cache could not get purged ${e}`);
throw new Error('Unable to purge cache: ');
});
}
servicePublish() {
return request.post('https://adobeioruntime.net/api/v1/web/helix/default/publish', {
json: true,
body: {
configuration: this.config.toJSON(),
service: this._fastly_namespace,
token: this._fastly_auth,
version: this._version,
},
}).then(() => {
this.tick(10, 'set service config up for Helix', true);
return true;
}).catch((e) => {
this.tick(10, 'failed to set service config up for Helix', true);
this.log.error(`Remote publish service failed ${e}`);
throw new Error('Unable to setup service config');
});
}
async updateFastlySecrets() {
const jobs = [];
if (this._wsk_auth) {
const auth = this._fastly.writeDictItem(this._version, 'secrets', 'OPENWHISK_AUTH', this._wsk_auth);
jobs.push(auth);
}
if (this._wsk_namespace) {
const namespace = this._fastly.writeDictItem(this._version, 'secrets', 'OPENWHISK_NAMESPACE', this._wsk_namespace);
jobs.push(namespace);
}
return Promise.all(jobs).then(() => {
this.tick(2, 'enabled authentication', true);
return true;
}).catch((e) => {
this.tick(2, 'failed to enable authentication', true);
this.log.error(`failed to enable authentication ${e}`);
throw new Error('Unable to set credentials');
});
}
async init() {
await super.init();
this._fastly = fastly(this._fastly_auth, this._fastly_namespace);
}
async run() {
await this.init();
try {
await this._fastly.transact(async (version) => {
this._version = version;
await this.servicePublish();
await this.serviceAddLogger();
await this.updateFastlySecrets();
}, !this._dryRun);
await this.purgeFastly();
this.showNextStep(this._dryRun);
} catch (e) {
const message = 'Error while running the Publish command';
this.log.error(`${message}: ${e.stack}`, e);
throw new Error(message, e);
}
}
}
module.exports = RemotePublishCommand;