@atomist/atomist-sdm
Version:
Atomist SDM to deliver our own projects
215 lines • 8.72 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_pack_build_1 = require("@atomist/sdm-pack-build");
const fs = require("fs-extra");
const path = require("path");
exports.IsJekyllProject = sdm_1.pushTest("IsJekyllProject", inv => inv.project.hasFile("_config.yml"));
const webNpmCommands = [
{ command: "npm", args: ["ci"], options: { env: Object.assign({}, process.env, { NODE_ENV: "development" }), log: undefined } },
{ command: "npm", args: ["run", "compile"] },
];
function spawnCommandString(cmd) {
return cmd.command + " " + cmd.args.join(" ");
}
function webNpmBuild(project, goalInvocation) {
return __awaiter(this, void 0, void 0, function* () {
const siteRoot = yield project.getFile("public/index.html");
if (siteRoot) {
return { code: 0, message: `Site directory already exists in '${project.baseDir}'` };
}
const log = goalInvocation.progressLog;
const opts = {
cwd: project.baseDir,
env: Object.assign({}, process.env, { NODE_ENV: "development" }),
log,
};
for (const spawnCmd of webNpmCommands) {
const res = yield sdm_1.spawnLog(spawnCmd.command, spawnCmd.args, opts);
if (res.code) {
log.write(`Command failed '${spawnCommandString(spawnCmd)}': ${res.error.message}`);
return res;
}
}
return { code: 0, message: "Site NPM build successful" };
});
}
exports.webNpmBuild = webNpmBuild;
exports.WebNpmBuildAfterCheckout = {
name: "npm web build",
events: [sdm_1.GoalProjectListenerEvent.before],
listener: webNpmBuild,
};
const jekyllCommands = [
{ command: "bundle", args: ["install"] },
{ command: "bundle", args: ["exec", "jekyll", "build"] },
];
function jekyllBuild(project, goalInvocation) {
return __awaiter(this, void 0, void 0, function* () {
const siteRoot = yield project.getFile("_site/index.html");
if (siteRoot) {
return { code: 0, message: `Site directory already exists in '${project.baseDir}'` };
}
const log = goalInvocation.progressLog;
const opts = {
cwd: project.baseDir,
log,
};
for (const spawnCmd of jekyllCommands) {
const res = yield sdm_1.spawnLog(spawnCmd.command, spawnCmd.args, opts);
if (res.code) {
log.write(`Command failed '${spawnCommandString(spawnCmd)}': ${res.error.message}`);
return res;
}
}
return { code: 0, message: "Site Jekyll build successful" };
});
}
exports.jekyllBuild = jekyllBuild;
exports.JekyllBuildAfterCheckout = {
name: "jekyll build",
events: [sdm_1.GoalProjectListenerEvent.before],
listener: jekyllBuild,
};
function webBuilder(sitePath) {
const commands = (sitePath === "_site") ? jekyllCommands : webNpmCommands;
return sdm_pack_build_1.spawnBuilder({
name: "WebBuilder",
commands,
logInterpreter: sdm_1.LogSuppressor,
projectToAppInfo: (p) => __awaiter(this, void 0, void 0, function* () {
let version;
const versionFile = yield p.getFile("VERSION");
if (versionFile) {
version = (yield versionFile.getContent()).trim();
}
else {
const pkgFile = yield p.getFile("package.json");
if (pkgFile) {
const pkg = JSON.parse(yield pkgFile.getContent());
version = pkg.version;
}
else {
version = "0.0.0";
}
}
return {
id: p.id,
name: p.name,
version,
};
}),
});
}
exports.webBuilder = webBuilder;
/**
* Run htmltest on `sitePath` and convert results to ReviewComments.
*
* @param sitePath path to web site relative to root of project
* @return function that takes a project and returns ReviewComments
*/
function runHtmltest(sitePath) {
return (p) => __awaiter(this, void 0, void 0, function* () {
const review = { repoId: p.id, comments: [] };
if (!automation_client_1.isLocalProject(p)) {
automation_client_1.logger.error(`Project ${p.name} is not a local project`);
return review;
}
if (!(yield p.hasDirectory(sitePath))) {
automation_client_1.logger.error(`Project ${p.name} does not have site directory '${sitePath}'`);
return review;
}
const absPath = path.join(p.baseDir, sitePath);
automation_client_1.logger.debug(`Running htmltest on ${absPath}`);
try {
const result = yield sdm_1.execPromise("htmltest", [absPath]);
if (result.stderr) {
automation_client_1.logger.debug(`htmltest standard error from ${p.name}: ${result.stderr}`);
}
automation_client_1.logger.debug(`htmltest standard output from ${p.name}: ${result.stdout}`);
const comments = yield mapHtmltestResultsToReviewComments(p.baseDir);
review.comments.push(...comments);
}
catch (e) {
automation_client_1.logger.error(`Failed to run htmltest: ${e.message}`);
}
return review;
});
}
function htmltestInspection(sitePath) {
return {
name: "RunHtmltest",
description: "Run htmltest on website",
inspection: runHtmltest(sitePath),
intent: "htmltest",
};
}
exports.htmltestInspection = htmltestInspection;
/**
* Convert the output of htmltest to proper ReviewComments. If any
* part of the process fails, an empty array is returned.
*
* @param output string output from running `htmltest` that will be parsed and converted.
* @return htmltest errors and warnings as ReviewComments
*/
function mapHtmltestResultsToReviewComments(baseDir) {
return __awaiter(this, void 0, void 0, function* () {
const logFile = path.join(baseDir, "tmp", ".htmltest", "htmltest.log");
const logContent = yield fs.readFile(logFile, "utf8");
return htmltestLogToReviewComments(logContent);
});
}
exports.mapHtmltestResultsToReviewComments = mapHtmltestResultsToReviewComments;
/**
* Testable unit of mapHtmltestResultsToReviewComments.
*/
function htmltestLogToReviewComments(logContent) {
const resultRegExp = /^(.*?)\s+---\s+(.*?)\s+-->\s+(.*?)$/;
const comments = logContent.split("\n").map(r => r.trim()).filter(r => r).map(r => {
const matches = resultRegExp.exec(r);
if (!matches) {
automation_client_1.logger.warn(`Failed to match htmltest output line '${r}': ${JSON.stringify(matches)}`);
return undefined;
}
const [description, sourcePath, detail] = matches.slice(1);
const sourceLocation = {
path: sourcePath,
offset: 0,
};
const severity = (description === "target does not exist") ? "error" : "warn";
return {
category: "htmltest",
detail,
severity,
sourceLocation,
subcategory: description,
};
}).filter(r => r);
return comments;
}
exports.htmltestLogToReviewComments = htmltestLogToReviewComments;
//# sourceMappingURL=webSupport.js.map