UNPKG

@atomist/atomist-sdm

Version:

Atomist SDM to deliver our own projects

215 lines 8.72 kB
"use strict"; /* * 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