diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..4bb74db
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,25 @@
+.idea/
+*.iml
+.vscode/
+**/*~
+**/.#*
+.npm*
+.travis.yml
+.atomist/
+.nyc_output/
+assets/kubectl/
+node_modules/
+# build/
+coverage/
+doc/
+log/
+scripts/
+src/
+test/
+CO*.md
+**/*.log
+**/*.txt
+
+build/test/
+build/typedoc/
+img/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..cbc37fc
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,36 @@
+FROM ubuntu:focal
+
+# tools
+RUN apt-get update && apt-get install -y \
+ curl \
+ wget \
+ gnupg \
+ build-essential \
+ && rm -rf /var/lib/apt/lists/*
+
+# nvm
+RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
+RUN echo 'export NVM_DIR="$HOME/.nvm"' >> "$HOME/.bashrc" \
+ && echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm' >> "$HOME/.bashrc"
+
+# nodejs and tools
+RUN bash -c "source $HOME/.nvm/nvm.sh \
+ && nvm install 10 \
+ && nvm install 12 \
+ && nvm install 14 \
+ && nvm use --lts"
+
+WORKDIR "/skill"
+
+COPY package.json package-lock.json ./
+
+RUN bash -c "source $HOME/.nvm/nvm.sh \
+ && npm ci --no-optional \
+ && npm cache clean --force"
+
+COPY . ./
+
+WORKDIR "/atm/home"
+
+ENTRYPOINT ["node", "--no-deprecation", "--trace-warnings", "--expose_gc", "--optimize_for_size", "--always_compact", "--max_old_space_size=512", "/skill/node_modules/.bin/atm-skill"]
+CMD ["run"]
diff --git a/docs/images/icon.svg b/docs/images/icon.svg
index 37230a5..36d99e8 100644
--- a/docs/images/icon.svg
+++ b/docs/images/icon.svg
@@ -1 +1,9 @@
-
+
+
+
+
diff --git a/graphql/query/repos.graphql b/graphql/query/repos.graphql
deleted file mode 100644
index 81afad5..0000000
--- a/graphql/query/repos.graphql
+++ /dev/null
@@ -1,6 +0,0 @@
-query Repositories {
- Repo {
- name
- owner
- }
-}
diff --git a/graphql/subscription/buildOnPush.graphql b/graphql/subscription/buildOnPush.graphql
new file mode 100644
index 0000000..ebbe436
--- /dev/null
+++ b/graphql/subscription/buildOnPush.graphql
@@ -0,0 +1,27 @@
+subscription buildOnPush {
+ Push {
+ repo {
+ url
+ owner
+ name
+ org {
+ provider {
+ apiUrl
+ gitUrl
+ }
+ }
+ channels {
+ name
+ team {
+ id
+ }
+ }
+ }
+ branch
+ after {
+ timestamp
+ sha
+ url
+ }
+ }
+}
diff --git a/lib/commands/helloWorld.ts b/lib/commands/helloWorld.ts
deleted file mode 100644
index 2a9a6db..0000000
--- a/lib/commands/helloWorld.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright © 2020 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.
- */
-
-import { CommandHandler, log } from "@atomist/skill";
-import { Configuration } from "../configuration";
-
-export const handler: CommandHandler = async ctx => {
- log.debug("Incoming parameters: %s", JSON.stringify(ctx.parameters));
-};
diff --git a/lib/configuration.ts b/lib/configuration.ts
index 51695f4..801f3a9 100644
--- a/lib/configuration.ts
+++ b/lib/configuration.ts
@@ -15,5 +15,7 @@
*/
export interface Configuration {
- world: string;
+ version: string;
+ scripts: string[];
+ docker_cache: string[];
}
diff --git a/lib/events/buildOnPush.ts b/lib/events/buildOnPush.ts
new file mode 100644
index 0000000..ac4c768
--- /dev/null
+++ b/lib/events/buildOnPush.ts
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2020 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.
+ */
+
+import {
+ EventContext,
+ EventHandler,
+ Step,
+ secret,
+ repository,
+ project,
+ runSteps,
+ StepListener,
+ HandlerStatus,
+ github,
+} from "@atomist/skill";
+import { Configuration } from "../configuration";
+import { BuildOnPushSubscription } from "../typings/types";
+import * as fs from "fs-extra";
+import * as df from "dateformat";
+
+interface NpmParameters {
+ project: project.Project;
+ version: string;
+ check: github.Check;
+}
+
+type NpmStep = Step, NpmParameters>;
+
+const LoadProjectStep: NpmStep = {
+ name: "load",
+ run: async (ctx, params) => {
+ const push = ctx.data.Push[0];
+ const repo = push.repo;
+
+ const credential = await ctx.credential.resolve(
+ secret.gitHubAppToken({ owner: repo.owner, repo: repo.name, apiUrl: repo.org.provider.apiUrl }),
+ );
+
+ const project: project.Project = await ctx.project.load(
+ repository.gitHub({
+ owner: repo.owner,
+ repo: repo.name,
+ credential,
+ }),
+ process.cwd(),
+ );
+ params.project = project;
+
+ return {
+ visibility: "hidden",
+ code: 0,
+ };
+ },
+};
+
+const ValidateStep: NpmStep = {
+ name: "validate",
+ run: async (ctx, params) => {
+ if (!(await fs.pathExists(params.project.path("package.json")))) {
+ return {
+ visibility: "hidden",
+ code: 1,
+ reason: `Ignoring push to non-NPM project`,
+ };
+ }
+ return {
+ visibility: "hidden",
+ code: 0,
+ };
+ },
+};
+
+const SetupNodeStep: NpmStep = {
+ name: "setup node",
+ run: async (ctx, params) => {
+ const cfg = ctx.configuration?.[0]?.parameters;
+ // Set up node version
+ const result = await params.project.spawn("nvm", ["install", cfg.version]);
+ return {
+ code: result.status,
+ };
+ },
+};
+
+const NodeVersionStep: NpmStep = {
+ name: "version",
+ run: async (ctx, params) => {
+ const pj = await fs.readJson(params.project.path("package.json"));
+ const branch = ctx.data.Push[0].branch.split("/").join(".");
+ const branchSuffix = `${branch}.`;
+
+ let pjVersion = pj.version;
+ if (!pjVersion || pjVersion.length === 0) {
+ pjVersion = "0.0.1";
+ }
+
+ const version = `${pjVersion}-${gitBranchToNpmVersion(branchSuffix)}${formatDate()}`;
+ params.version = version;
+ const result = await params.project.spawn("npm", ["version", "--no-git-tag-version", version]);
+ return {
+ code: result.status,
+ };
+ },
+};
+
+function gitBranchToNpmVersion(branchName: string): string {
+ return branchName
+ .replace(/\//g, "-")
+ .replace(/_/g, "-")
+ .replace(/@/g, "");
+}
+
+function formatDate(date = new Date(), format = "yyyymmddHHMMss", utc = true) {
+ return df(date, format, utc);
+}
+
+const NpmInstallStep: NpmStep = {
+ name: "npm install",
+ run: async (ctx, params) => {
+ const opts = { env: { ...process.env, NODE_ENV: "development" } };
+ let result;
+ if (await fs.pathExists(params.project.path("package-lock.json"))) {
+ result = await params.project.spawn("npm", ["ci"], opts);
+ } else {
+ result = await params.project.spawn("npm", ["install"], opts);
+ }
+
+ return {
+ code: result.status,
+ };
+ },
+};
+
+const NodeScriptsStep: NpmStep = {
+ name: "npm run",
+ run: async (ctx, params) => {
+ const cfg = ctx.configuration?.[0]?.parameters;
+ const scripts = cfg.scripts;
+ // Run scripts
+ for (const script of scripts) {
+ const result = await params.project.spawn("npm", ["run", "--if-present", script]);
+ if (result.status !== 0) {
+ return {
+ code: result.status,
+ };
+ }
+ }
+ return {
+ code: 0,
+ };
+ },
+};
+
+export const handler: EventHandler = async ctx => {
+ return runSteps({
+ context: ctx,
+ steps: [LoadProjectStep, ValidateStep, SetupNodeStep, NodeVersionStep, NpmInstallStep, NodeScriptsStep],
+ listeners: [checkListener],
+ });
+};
diff --git a/lib/events/helloWorld.ts b/lib/events/helloWorld.ts
deleted file mode 100644
index 90d2221..0000000
--- a/lib/events/helloWorld.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright © 2020 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.
- */
-
-import { EventHandler, log } from "@atomist/skill";
-import { Configuration } from "../configuration";
-
-export const handler: EventHandler = async ctx => {
- log.debug("Incoming event: %s", JSON.stringify(ctx.data));
-};
diff --git a/package-lock.json b/package-lock.json
index cebf0ce..c7a20fa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1780,6 +1780,11 @@
"@types/node": "*"
}
},
+ "@types/dateformat": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz",
+ "integrity": "sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g=="
+ },
"@types/debounce": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.0.tgz",
@@ -3384,6 +3389,11 @@
"integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==",
"dev": true
},
+ "dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q=="
+ },
"de-indent": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
diff --git a/package.json b/package.json
index 97e8d2e..8d32198 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,9 @@
{
"main": "node_modules/@atomist/skill/lib/function.js",
"dependencies": {
- "@atomist/skill": "0.1.0-master.20200702145252"
+ "@atomist/skill": "0.1.0-master.20200702145252",
+ "@types/dateformat": "^3.0.1",
+ "dateformat": "^3.0.3"
},
"devDependencies": {
"@google-cloud/functions-framework": "^1.6.0",
@@ -48,7 +50,7 @@
"start": "functions-framework --target=entryPoint --signature-type=event",
"test": "mocha --require espower-typescript/guess \"test/**/*.test.ts\" --reporter min",
"test:one": "mocha --require espower-typescript/guess \"test/**/${TEST:-*.test.ts}\"",
- "skill": "run-s compile test skill:generate skill:bundle skill:package",
+ "skill": "run-s compile test skill:generate",
"skill:generate": "atm-skill generate",
"skill:clean": "atm-skill clean",
"skill:bundle": "atm-skill bundle --minify --source-map",
diff --git a/skill.package.yaml b/skill.package.yaml
index e4972cc..0c561f8 100644
--- a/skill.package.yaml
+++ b/skill.package.yaml
@@ -14,6 +14,8 @@
# limitations under the License.
#
+---
apiVersion: 1
package:
- type: atomist/node-skill
+ type: atomist/container-skill
+ command: npm ci && npm run skill
diff --git a/skill.ts b/skill.ts
index e58f44c..86d177d 100644
--- a/skill.ts
+++ b/skill.ts
@@ -14,48 +14,46 @@
* limitations under the License.
*/
-import { parameter, ParameterType, resourceProvider, skill } from "@atomist/skill";
+import { Category, parameter, ParameterType, resourceProvider, skill } from "@atomist/skill";
import { Configuration } from "./lib/configuration";
export const Skill = skill({
name: "npm-skill",
namespace: "atomist",
- displayName: "NPM",
- author: "atomist-skills",
- categories: [],
+ displayName: "NPM Scripts",
+ author: "Atomist",
+ categories: [Category.DevEx],
license: "Apache-2.0",
homepageUrl: "https://github.com/atomist-skills/npm-skill",
repositoryUrl: "https://github.com/atomist-skills/npm-skill.git",
iconUrl: "file://docs/images/icon.svg",
- runtime: {
- memory: 2048,
- timeout: 540,
- },
-
resourceProviders: {
github: resourceProvider.gitHub({ minRequired: 1 }),
chat: resourceProvider.chat({ minRequired: 0 }),
},
parameters: {
- world: {
+ version: {
type: ParameterType.String,
- displayName: "World",
- description: "",
+ displayName: "Node.js version",
+ description: "Version of Node.js to install (should be valid nvm alias or version)",
+ required: false,
+ },
+ scripts: {
+ type: ParameterType.StringArray,
+ displayName: "NPM scripts",
+ description: "Provide name of NPM scripts to run in order",
+ required: true,
+ },
+ docker_cache: {
+ type: ParameterType.StringArray,
+ displayName: "Cache files or folders",
+ description: "Cache and restore file system content between executions of this skill",
required: false,
},
repos: parameter.repoFilter(),
},
- commands: [
- {
- name: "helloWorld",
- displayName: "HelloWorld",
- pattern: /^hello world$/,
- description: "Simple hello world command",
- },
- ],
-
subscriptions: ["file://graphql/subscription/*.graphql"],
});
diff --git a/tsconfig.json b/tsconfig.json
index 9e69ac6..f9665ba 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,7 +11,7 @@
"lib": [
"DOM"
],
- "strict": true,
+ "strict": false,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noUnusedLocals": true,