@atomist/sdm-pack-node
Version:
Extension pack for an Atomist SDM to work with Node.js projects
250 lines • 10.6 kB
JavaScript
;
/*
* Copyright © 2019 Atomist, Inc.
*
* Licensed 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 CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 automation_client_1 = require("@atomist/automation-client");
const sdm_1 = require("@atomist/sdm");
const sdm_core_1 = require("@atomist/sdm-core");
const sdm_pack_build_1 = require("@atomist/sdm-pack-build");
const base64url_1 = require("base64url");
const fs = require("fs-extra");
const hash = require("hasha");
const _ = require("lodash");
const nodePushTests_1 = require("../pushtest/nodePushTests");
const npmLogInterpreter_1 = require("./npmLogInterpreter");
/**
* Options to use when running node commands like npm run compile that require dev dependencies to be installed
*/
exports.DevelopmentEnvOptions = {
env: Object.assign({}, process.env, { NODE_ENV: "development" }),
};
exports.Install = { command: "npm", args: ["ci"], options: exports.DevelopmentEnvOptions };
function nodeBuilder(...commands) {
return sdm_pack_build_1.spawnBuilder(npmBuilderOptions(commands.map(cmd => ({
command: cmd.command, args: cmd.args, options: Object.assign({}, exports.DevelopmentEnvOptions, cmd.options),
}))));
}
exports.nodeBuilder = nodeBuilder;
function npmBuilderOptions(commands) {
return {
name: "NpmBuilder",
commands,
errorFinder: sdm_1.SuccessIsReturn0ErrorFinder,
logInterpreter: npmLogInterpreter_1.NpmLogInterpreter,
projectToAppInfo(p) {
return __awaiter(this, void 0, void 0, function* () {
const packageJson = yield p.findFile("package.json");
const content = yield packageJson.getContent();
const pkg = JSON.parse(content);
return { id: p.id, name: pkg.name, version: pkg.version };
});
},
};
}
function npmBuilderOptionsFromFile(commandFile) {
return {
name: "NpmBuilder",
commandFile,
errorFinder: (code, signal, l) => {
return l.log.startsWith("[error]") || l.log.includes("ERR!");
},
logInterpreter: npmLogInterpreter_1.NpmLogInterpreter,
projectToAppInfo(p) {
return __awaiter(this, void 0, void 0, function* () {
const packageJson = yield p.findFile("package.json");
const content = yield packageJson.getContent();
const pkg = JSON.parse(content);
return { id: p.id, name: pkg.name, version: pkg.version };
});
},
};
}
exports.npmBuilderOptionsFromFile = npmBuilderOptionsFromFile;
exports.NpmPreparations = [npmInstallPreparation, npmVersionPreparation, npmCompilePreparation];
function npmInstallPreparation(p, goalInvocation) {
return __awaiter(this, void 0, void 0, function* () {
const hasPackageLock = p.fileExistsSync("package-lock.json");
return sdm_1.spawnLog("npm", [hasPackageLock ? "ci" : "install"], Object.assign({ cwd: p.baseDir }, exports.DevelopmentEnvOptions, { log: goalInvocation.progressLog }));
});
}
exports.npmInstallPreparation = npmInstallPreparation;
function npmVersionPreparation(p, goalInvocation) {
return __awaiter(this, void 0, void 0, function* () {
const sdmGoal = goalInvocation.goalEvent;
const version = yield sdm_core_1.readSdmVersion(sdmGoal.repo.owner, sdmGoal.repo.name, sdmGoal.repo.providerId, sdmGoal.sha, sdmGoal.branch, goalInvocation.context);
return sdm_1.spawnLog("npm", ["--no-git-tag-version", "version", version], {
cwd: p.baseDir,
log: goalInvocation.progressLog,
});
});
}
exports.npmVersionPreparation = npmVersionPreparation;
exports.NpmVersionProjectListener = {
name: "npm version",
pushTest: nodePushTests_1.IsNode,
listener: (p, r, event) => __awaiter(this, void 0, void 0, function* () {
if (sdm_1.GoalProjectListenerEvent.before === event) {
return npmVersionPreparation(p, r);
}
}),
};
function npmCompilePreparation(p, goalInvocation) {
return __awaiter(this, void 0, void 0, function* () {
if (yield hasCompileScriptInPackageJson(p)) {
return sdm_1.spawnLog("npm", ["run", "compile"], Object.assign({ cwd: p.baseDir }, exports.DevelopmentEnvOptions, { log: goalInvocation.progressLog }));
}
else {
return { code: 0 };
}
});
}
exports.npmCompilePreparation = npmCompilePreparation;
function hasCompileScriptInPackageJson(p) {
return __awaiter(this, void 0, void 0, function* () {
const rawPj = yield p.getFile("package.json");
const pj = JSON.parse(yield rawPj.getContent());
return !!pj.scripts && !!pj.scripts.compile;
});
}
exports.NpmCompileProjectListener = {
name: "npm compile",
pushTest: nodePushTests_1.IsNode,
listener: (p, r) => __awaiter(this, void 0, void 0, function* () {
return npmCompilePreparation(p, r);
}),
events: [sdm_1.GoalProjectListenerEvent.before],
};
exports.NodeModulesProjectListener = {
name: "npm install",
listener: (p, gi) => __awaiter(this, void 0, void 0, function* () {
// Check if project has a package.json
if (!(yield p.hasFile("package.json"))) {
return;
}
return cacheNodeModules(p, gi, { scope: CacheScope.GoalSet });
}),
events: [sdm_1.GoalProjectListenerEvent.before],
pushTest: nodePushTests_1.IsNode,
};
exports.NpmInstallProjectListener = exports.NodeModulesProjectListener;
function npmInstallProjectListener(options = { scope: CacheScope.GoalSet }) {
return {
name: "npm install",
listener: (p, gi) => __awaiter(this, void 0, void 0, function* () {
// Check if project has a package.json
if (!(yield p.hasFile("package.json"))) {
return;
}
return cacheNodeModules(p, gi, options);
}),
events: [sdm_1.GoalProjectListenerEvent.before],
pushTest: nodePushTests_1.IsNode,
};
}
exports.npmInstallProjectListener = npmInstallProjectListener;
var CacheScope;
(function (CacheScope) {
CacheScope[CacheScope["GoalSet"] = 0] = "GoalSet";
CacheScope[CacheScope["Repository"] = 1] = "Repository";
})(CacheScope = exports.CacheScope || (exports.CacheScope = {}));
function cacheNodeModules(p, gi, options) {
return __awaiter(this, void 0, void 0, function* () {
// If project already has a node_modules dir; there is nothing left to do
if (yield p.hasDirectory("node_modules")) {
return;
}
const hasPackageLock = yield p.hasFile("package-lock.json");
let requiresInstall = true;
let installed = false;
const { goalEvent } = gi;
// Check cache for a previously cached node_modules cache archive
let name;
if (options.scope === CacheScope.GoalSet) {
name = goalEvent.goalSetId;
}
else if (options.scope === CacheScope.Repository) {
if (hasPackageLock) {
name = base64url_1.default.fromBase64(hash(yield (yield p.getFile("package-lock.json")).getContent(), {
algorithm: "md5",
encoding: "base64",
}));
}
else {
name = base64url_1.default.fromBase64(hash(yield (yield p.getFile("package.json")).getContent(), {
algorithm: "md5",
encoding: "base64",
}));
}
}
const cacheFileName = `${_.get(gi, "configuration.sdm.cache.path", "/opt/data")}/${name}-node_modules.tar.gz`;
if (_.get(gi, "configuration.sdm.cache.enabled") === true && (yield fs.pathExists(cacheFileName))) {
const result = yield extract(cacheFileName, p, gi);
requiresInstall = result.code !== 0;
}
if (requiresInstall) {
let result;
if (hasPackageLock) {
result = yield runInstall("ci", p, gi);
}
else {
result = yield runInstall("i", p, gi);
}
installed = result.code === 0;
}
// Cache the node_modules folder
if (installed && _.get(gi, "configuration.sdm.cache.enabled") === true) {
const tempCacheFileName = `${cacheFileName}.${automation_client_1.guid().slice(0, 7)}`;
const result = yield compress(tempCacheFileName, p, gi);
if (result.code === 0) {
yield fs.move(tempCacheFileName, cacheFileName, { overwrite: true });
}
}
});
}
function runInstall(cmd, p, gi) {
return __awaiter(this, void 0, void 0, function* () {
return sdm_1.spawnLog("npm", [cmd], {
cwd: p.baseDir,
env: Object.assign({}, process.env, { NODE_ENV: "development" }),
log: gi.progressLog,
});
});
}
function compress(name, p, gi) {
return __awaiter(this, void 0, void 0, function* () {
return sdm_1.spawnLog("tar", ["-zcf", name, "node_modules"], {
cwd: p.baseDir,
log: gi.progressLog,
});
});
}
function extract(name, p, gi) {
return __awaiter(this, void 0, void 0, function* () {
return sdm_1.spawnLog("tar", ["-xf", name], {
cwd: p.baseDir,
log: gi.progressLog,
});
});
}
//# sourceMappingURL=npmBuilder.js.map