UNPKG

@atomist/atomist-sdm

Version:

Atomist SDM to deliver our own projects

382 lines (381 loc) 20.8 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 }); /* tslint:disable:max-file-line-count */ 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_docker_1 = require("@atomist/sdm-pack-docker"); const sdm_pack_issue_1 = require("@atomist/sdm-pack-issue"); const sdm_pack_node_1 = require("@atomist/sdm-pack-node"); const npmBuilder_1 = require("@atomist/sdm-pack-node/lib/build/npmBuilder"); const sdm_pack_spring_1 = require("@atomist/sdm-pack-spring"); const fs = require("fs-extra"); const path = require("path"); const addAtomistHeader_1 = require("../autofix/addAtomistHeader"); const CodeSnippetInline_1 = require("../autofix/CodeSnippetInline"); const importsFix_1 = require("../autofix/imports/importsFix"); const ReadmeSampleListingAutofix_1 = require("../autofix/ReadmeSampleListingAutofix"); const testNamingFix_1 = require("../autofix/test/testNamingFix"); const updateSupportFiles_1 = require("../autofix/updateSupportFiles"); const deleteDistTagOnBranchDeletion_1 = require("../event/deleteDistTagOnBranchDeletion"); const executeLogger_1 = require("../support/executeLogger"); const identityPushTests_1 = require("../support/identityPushTests"); const transformToProjectListener_1 = require("../support/transformToProjectListener"); const dependenciesToPeerDependencies_1 = require("../transform/dependenciesToPeerDependencies"); const rewriteImports_1 = require("../transform/rewriteImports"); const tryToUpdateAtomistDependencies_1 = require("../transform/tryToUpdateAtomistDependencies"); const tryToUpdateAtomistPeerDependencies_1 = require("../transform/tryToUpdateAtomistPeerDependencies"); const tryToUpdateDependency_1 = require("../transform/tryToUpdateDependency"); const updatePackageAuthor_1 = require("../transform/updatePackageAuthor"); const updatePackageVersion_1 = require("../transform/updatePackageVersion"); const goals_1 = require("./goals"); const release_1 = require("./release"); const NodeDefaultOptions = { pushTest: sdm_1.allSatisfied(sdm_pack_node_1.IsNode, sdm_1.not(sdm_pack_spring_1.IsMaven)), logInterpreter: sdm_1.LogSuppressor, progressReporter: sdm_pack_node_1.NpmProgressReporter, }; /** * Add Node.js implementations of goals to SDM. * * @param sdm Software Delivery machine to modify * @return modified software delivery machine */ function addNodeSupport(sdm) { goals_1.version.with(Object.assign({}, NodeDefaultOptions, { name: "npm-versioner-global-sdm", versioner: (sdmGoal, p, log) => __awaiter(this, void 0, void 0, function* () { const branch = sdmGoal.branch; if (branch === sdmGoal.push.repo.defaultBranch) { sdmGoal.branch = "global"; } let v; try { v = yield sdm_pack_node_1.NodeProjectVersioner(sdmGoal, p, log); } finally { sdmGoal.branch = branch; } return v; }), pushTest: sdm_1.allSatisfied(sdm_pack_node_1.IsNode, identityPushTests_1.isOrgNamed("atomisthq"), identityPushTests_1.isNamed("global-sdm")) })).with(Object.assign({}, NodeDefaultOptions, { name: "npm-versioner", versioner: sdm_pack_node_1.NodeProjectVersioner, pushTest: sdm_1.allSatisfied(sdm_pack_node_1.IsNode, sdm_1.not(sdm_1.allSatisfied(identityPushTests_1.isOrgNamed("atomisthq"), identityPushTests_1.isNamed("global-sdm")))) })); goals_1.autofix.with(addAtomistHeader_1.AddAtomistTypeScriptHeader) .with(sdm_pack_node_1.TslintAutofix) .with(importsFix_1.TypeScriptImports) .with(sdm_pack_node_1.PackageLockUrlRewriteAutofix) .with(testNamingFix_1.RenameTestFix) .with(sdm_pack_node_1.AddThirdPartyLicenseAutofix) .with(updateSupportFiles_1.UpdateSupportFilesAutofix) .with(ReadmeSampleListingAutofix_1.ReadmeSampleListingAutofix) .with(CodeSnippetInline_1.CodeSnippetInlineAutofix) .withProjectListener(npmBuilder_1.npmInstallProjectListener({ scope: npmBuilder_1.CacheScope.Repository })); goals_1.build.with(Object.assign({}, NodeDefaultOptions, { name: "npm-run-build", builder: sdm_pack_node_1.nodeBuilder({ command: "npm", args: ["run", "compile"] }, { command: "npm", args: ["test"] }), pushTest: NodeDefaultOptions.pushTest })) .withProjectListener(npmBuilder_1.npmInstallProjectListener({ scope: npmBuilder_1.CacheScope.Repository })); goals_1.autoCodeInspection.with(sdm_pack_node_1.TslintInspection) .with(sdm_pack_node_1.npmAuditInspection()) .withProjectListener(npmBuilder_1.npmInstallProjectListener({ scope: npmBuilder_1.CacheScope.Repository })) .withListener(sdm_pack_issue_1.singleIssuePerCategoryManaging(sdm.configuration.name, false, () => true)) .withListener(sdm_1.ApproveGoalIfErrorComments); goals_1.publish.with(Object.assign({}, NodeDefaultOptions, { name: "npm-publish", goalExecutor: sdm_pack_node_1.executePublish(sdm_pack_node_1.NodeProjectIdentifier, sdm.configuration.sdm.npm) })) .withProjectListener(transformToProjectListener_1.transformToProjectListener(dependenciesToPeerDependencies_1.dependenciesToPeerDependenciesTransform(/@atomist\/sdm.*/, /@atomist\/automation-client.*/), "package.json rewrite", sdm_1.allSatisfied(sdm_pack_node_1.IsNode, identityPushTests_1.isOrgNamed("atomist"), identityPushTests_1.isNamed("uhura")))) .withProjectListener(npmBuilder_1.npmInstallProjectListener({ scope: npmBuilder_1.CacheScope.Repository })) .withProjectListener(sdm_pack_node_1.NpmVersionProjectListener) .withProjectListener(sdm_pack_node_1.NpmCompileProjectListener); goals_1.publishWithApproval.with(Object.assign({}, NodeDefaultOptions, { name: "npm-publish", goalExecutor: sdm_pack_node_1.executePublish(sdm_pack_node_1.NodeProjectIdentifier, sdm.configuration.sdm.npm) })) .withProjectListener(transformToProjectListener_1.transformToProjectListener(dependenciesToPeerDependencies_1.dependenciesToPeerDependenciesTransform(/@atomist\/sdm.*/, /@atomist\/automation-client.*/), "package.json rewrite", sdm_1.allSatisfied(sdm_pack_node_1.IsNode, identityPushTests_1.isOrgNamed("atomist"), identityPushTests_1.isNamed("uhura")))) .withProjectListener(npmBuilder_1.npmInstallProjectListener({ scope: npmBuilder_1.CacheScope.Repository })) .withProjectListener(sdm_pack_node_1.NpmVersionProjectListener) .withProjectListener(sdm_pack_node_1.NpmCompileProjectListener); goals_1.dockerBuild.with(Object.assign({}, NodeDefaultOptions, { name: "npm-docker-build-global-sdm", options: Object.assign({}, sdm.configuration.sdm.docker.t095sffbk, { push: true, builder: "docker" }), pushTest: sdm_1.allSatisfied(sdm_pack_node_1.IsNode, sdm_pack_docker_1.HasDockerfile, identityPushTests_1.isOrgNamed("atomisthq"), identityPushTests_1.isNamed("global-sdm")) })).with(Object.assign({}, NodeDefaultOptions, { name: "npm-docker-build", options: Object.assign({}, sdm.configuration.sdm.docker.hub, { push: true, builder: "docker" }), pushTest: sdm_1.allSatisfied(sdm_pack_node_1.IsNode, sdm_pack_docker_1.HasDockerfile, sdm_1.not(sdm_1.allSatisfied(identityPushTests_1.isOrgNamed("atomisthq"), identityPushTests_1.isNamed("global-sdm")))) })) .withProjectListener(npmBuilder_1.npmInstallProjectListener({ scope: npmBuilder_1.CacheScope.Repository })) .withProjectListener(sdm_pack_node_1.NpmVersionProjectListener) .withProjectListener(sdm_pack_node_1.NpmCompileProjectListener); goals_1.release.with(Object.assign({}, NodeDefaultOptions, { name: "npm-release", goalExecutor: executeReleaseNpm(sdm_pack_node_1.NodeProjectIdentifier, exports.NpmReleasePreparations, sdm.configuration.sdm.npm) })); goals_1.releaseDocs.with(Object.assign({}, NodeDefaultOptions, { name: "npm-docs-release", goalExecutor: executeReleaseTypeDocs(exports.DocsReleasePreparations) })); goals_1.releaseVersion.with(Object.assign({}, NodeDefaultOptions, { name: "npm-release-version", goalExecutor: release_1.executeReleaseVersion(sdm_pack_node_1.NodeProjectIdentifier, npmIncrementPatch) })); sdm.addEvent(deleteDistTagOnBranchDeletion_1.deleteDistTagOnBranchDeletion(sdm.configuration.sdm.projectLoader, sdm.configuration.sdm.npm)); sdm.addCodeTransformCommand(tryToUpdateAtomistDependencies_1.TryToUpdateAtomistDependencies) .addCodeTransformCommand(tryToUpdateDependency_1.TryToUpdateDependency) .addCodeTransformCommand(updatePackageVersion_1.UpdatePackageVersion) .addCodeTransformCommand(tryToUpdateAtomistPeerDependencies_1.TryToUpdateAtomistPeerDependencies) .addCodeTransformCommand(updatePackageAuthor_1.UpdatePackageAuthor) .addCodeTransformCommand(updateSupportFiles_1.UpdateSupportFilesTransform) .addCodeTransformCommand(rewriteImports_1.RewriteImports) .addCodeTransformCommand(testNamingFix_1.RenameTest); return sdm; } exports.addNodeSupport = addNodeSupport; /** * Increment the patch version of a Node project managed by NPM. */ function npmIncrementPatch(p, log) { return __awaiter(this, void 0, void 0, function* () { return sdm_1.spawnLog("npm", ["version", "--no-git-tag-version", "patch"], { cwd: p.baseDir, log }); }); } function npmPackageUrl(p) { return `${p.registry}/${p.name}/-/${p.name}-${p.version}.tgz`; } /** * Download the pre-release NPM package related to this project and * goal invocation and provide information back about it. The caller * is responsible for cleaning up the downloaded files and its parent * directory. * * @param p Project to download NPM package for * @param gi Download package generated by this goal invocation * @return information about the NPM package */ function downloadNpmPackage(p, gi, v) { return __awaiter(this, void 0, void 0, function* () { const pjFile = yield p.getFile("package.json"); if (!pjFile) { const msg = `NPM project does not have a package.json`; automation_client_1.logger.error(msg); throw new Error(msg); } const pjContents = yield pjFile.getContent(); let pj; try { pj = JSON.parse(pjContents); } catch (e) { e.message = `Unable to parse package.json '${pjContents}': ${e.message}`; automation_client_1.logger.error(e.message); throw e; } if (!pj.name) { const msg = `Unable to get NPM package name from package.json '${pjContents}'`; automation_client_1.logger.error(msg); throw new Error(msg); } const pkgVersion = (v) ? v : yield release_1.rwlcVersion(gi); const npmOptions = automation_client_1.configurationValue("sdm.npm"); if (!npmOptions.registry) { throw new Error(`No NPM registry defined in NPM options`); } const pkgUrl = npmPackageUrl({ registry: npmOptions.registry, name: pj.name, version: pkgVersion, }); const tmpDir = path.join((process.env.TMPDIR || "/tmp"), `${p.name}-${automation_client_1.guid()}`); const tgz = path.join(tmpDir, "package.tgz"); const cmds = [ { cmd: { command: "curl", args: ["--output", tgz, "--silent", "--fail", "--create-dirs", pkgUrl] }, }, ]; const els = cmds.map(executeLogger_1.spawnExecuteLogger); const result = yield executeLogger_1.executeLoggers(els, gi.progressLog); if (result.code !== 0) { throw new Error(`Failed to download NPM package ${pkgUrl}: ${result.message}`); } return { path: tgz, url: pkgUrl, version: pkgVersion, }; }); } exports.downloadNpmPackage = downloadNpmPackage; /** * Download published pre-release NPM package, replace the contents of * project with the contents of the package, and set the version to * the release version. */ function npmReleasePreparation(p, gi) { return __awaiter(this, void 0, void 0, function* () { const pkgInfo = yield downloadNpmPackage(p, gi); const versionRelease = release_1.releaseOrPreRelease(pkgInfo.version, gi); const tmpDir = path.dirname(pkgInfo.path); const cmds = [ { cmd: { command: "tar", args: ["-x", "-z", "-f", pkgInfo.path] }, cwd: tmpDir, }, { cmd: { command: "bash", args: ["-c", "rm -r *"] }, cwd: p.baseDir, }, { cmd: { command: "cp", args: ["-r", "package/.", p.baseDir] }, cwd: tmpDir, }, { cmd: { command: "npm", args: ["--no-git-tag-version", "version", versionRelease] }, cwd: p.baseDir, }, { cmd: { command: "rm", args: ["-rf", tmpDir] }, }, ]; const els = cmds.map(executeLogger_1.spawnExecuteLogger); return executeLogger_1.executeLoggers(els, gi.progressLog); }); } exports.npmReleasePreparation = npmReleasePreparation; exports.NpmReleasePreparations = [npmReleasePreparation]; function executeReleaseNpm(projectIdentifier, preparations = exports.NpmReleasePreparations, options) { if (!options.npmrc) { throw new Error(`No npmrc defined in NPM options`); } return (gi) => __awaiter(this, void 0, void 0, function* () { const { configuration, credentials, id, context } = gi; return configuration.sdm.projectLoader.doWithProject({ credentials, id, context, readOnly: false, }, (project) => __awaiter(this, void 0, void 0, function* () { if (!(yield sdm_1.projectConfigurationValue("npm.publish.enabled", project, true))) { return { code: 0, description: "Publish disabled", state: sdm_1.SdmGoalState.success, }; } yield fs.writeFile(path.join(project.baseDir, ".npmrc"), options.npmrc); for (const preparation of preparations) { const pResult = yield preparation(project, gi); if (pResult && pResult.code !== 0) { return pResult; } } const args = [ "publish", "--registry", options.registry, "--access", options.access ? options.access : "restricted", ]; const v = yield release_1.rwlcVersion(gi); const versionRelease = release_1.releaseOrPreRelease(v, gi); if (release_1.isNextVersion(versionRelease)) { args.push("--tag", "next"); } const result = yield sdm_1.spawnLog("npm", args, { cwd: project.baseDir, log: gi.progressLog, }); if (result.error) { return result; } const pi = yield projectIdentifier(project); const url = npmPackageUrl({ registry: options.registry, name: pi.name, version: pi.version, }); if (options.status) { yield sdm_core_1.github.createStatus(credentials.token, id, { context: "npm/atomist/package", description: "NPM package", target_url: url, state: "success", }); } const egr = { code: result.code, message: result.message, targetUrl: url, }; return egr; })); }); } exports.executeReleaseNpm = executeReleaseNpm; function typedocDir(baseDir) { const oldDir = path.join(baseDir, "build", "typedoc"); const dir = path.join(baseDir, "doc"); if (fs.existsSync(oldDir)) { return oldDir; } return dir; } function docsReleasePreparation(p, gi) { return __awaiter(this, void 0, void 0, function* () { const cmds = [ { cmd: { command: "npm", args: ["ci"], options: Object.assign({}, sdm_pack_node_1.DevelopmentEnvOptions, { log: gi.progressLog }), }, cwd: p.baseDir, }, { cmd: { command: "npm", args: ["run", "compile"] }, cwd: p.baseDir, }, { cmd: { command: "npm", args: ["run", "doc"] }, cwd: p.baseDir, }, ]; const els = cmds.map(executeLogger_1.spawnExecuteLogger); return executeLogger_1.executeLoggers(els, gi.progressLog); }); } exports.docsReleasePreparation = docsReleasePreparation; exports.DocsReleasePreparations = [docsReleasePreparation]; /** * Publish TypeDoc to gh-pages branch. */ function executeReleaseTypeDocs(preparations = exports.DocsReleasePreparations) { return (gi) => __awaiter(this, void 0, void 0, function* () { const { configuration, credentials, id, context } = gi; return configuration.sdm.projectLoader.doWithProject({ credentials, id, context, readOnly: false, }, (project) => __awaiter(this, void 0, void 0, function* () { for (const preparation of preparations) { const pResult = yield preparation(project, gi); if (pResult && pResult.code !== 0) { return pResult; } } const v = yield release_1.rwlcVersion(gi); const versionRelease = release_1.releaseOrPreRelease(v, gi); const commitMsg = `TypeDoc: publishing for version ${versionRelease} [atomist:generated]`; const docDir = typedocDir(project.baseDir); const els = [executeLogger_1.spawnExecuteLogger({ cmd: { command: "touch", args: [path.join(docDir, ".nojekyll")] }, cwd: project.baseDir, })]; const docProject = yield automation_client_1.NodeFsLocalProject.fromExistingDirectory(project.id, docDir); const docGitProject = automation_client_1.GitCommandGitProject.fromProject(docProject, credentials); const targetUrl = `https://${docGitProject.id.owner}.github.io/${docGitProject.id.repo}`; const rrr = project.id; els.push(executeLogger_1.gitExecuteLogger(docGitProject, () => docGitProject.init(), "init"), executeLogger_1.gitExecuteLogger(docGitProject, () => docGitProject.commit(commitMsg), "commit"), executeLogger_1.gitExecuteLogger(docGitProject, () => docGitProject.createBranch("gh-pages"), "createBranch"), executeLogger_1.gitExecuteLogger(docGitProject, () => docGitProject.setRemote(rrr.cloneUrl(credentials)), "setRemote"), executeLogger_1.gitExecuteLogger(docGitProject, () => docGitProject.push({ force: true }), "push")); const gitRes = yield executeLogger_1.executeLoggers(els, gi.progressLog); if (gitRes.code !== 0) { return gitRes; } return Object.assign({}, automation_client_1.Success, { targetUrl }); })); }); } exports.executeReleaseTypeDocs = executeReleaseTypeDocs; //# sourceMappingURL=nodeSupport.js.map