From caa2ca642de2e0ac667eaa1803ec39cbc5f8f14d Mon Sep 17 00:00:00 2001
From: Danny McCormick <damccorm@microsoft.com>
Date: Fri, 31 May 2019 12:17:28 -0400
Subject: [PATCH] Add auth and ci

---
 .github/main.workflow | 21 +++++++++++++++++++++
 README.md             | 13 ++++++++++++-
 lib/auth.js           | 40 ++++++++++++++++++++++++++++++++++++++++
 lib/installer.js      |  3 +--
 lib/setup-node.js     |  7 +++++++
 package-lock.json     | 24 ++++++++++++------------
 src/auth.ts           | 37 +++++++++++++++++++++++++++++++++++++
 src/installer.ts      |  3 +--
 src/setup-node.ts     |  8 ++++++++
 9 files changed, 139 insertions(+), 17 deletions(-)
 create mode 100644 .github/main.workflow
 create mode 100644 lib/auth.js
 create mode 100644 src/auth.ts

diff --git a/.github/main.workflow b/.github/main.workflow
new file mode 100644
index 00000000..0bb0f898
--- /dev/null
+++ b/.github/main.workflow
@@ -0,0 +1,21 @@
+workflow "CI" {
+  on = "push"
+  resolves = ["Format", "Build"]
+}
+
+action "Dependencies" {
+  uses = "actions/npm@v2.0.0"
+  args = "ci"
+}
+
+action "Build" {
+  needs = "Dependencies"
+  uses = "actions/npm@v2.0.0"
+  args = "run build"
+}
+
+action "Format" {
+  needs = "Dependencies"
+  uses = "actions/npm@v2.0.0"
+  args = "run format-check"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 7320ab16..9e6645a2 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ This action sets by node environment for use in actions by:
 
 - optionally downloading and caching a version of node - npm by version spec and add to PATH
 - TODO: registering problem matchers for error output 
-- TODO: configuring authentication for npm packages 
+- optionally configuring authentication for npm packages 
 - TODO: configuring proxy if the runner is configured to use a proxy (coming with private runners)
 
 # Usage
@@ -38,6 +38,17 @@ workflow:
       - run: npm test
 ```
 
+Auth:
+```yaml
+actions:
+- uses: actions/setup-node@latest
+  with:
+    registryUrl: 'https://mycustomregistry.example.org'
+    registryToken: $ {{ token }}
+    authFile: 'optional/path/to/.npmrc/file'
+- run: npm publish
+```
+
 # License
 
 The scripts and documentation in this project are released under the [MIT License](LICENSE)
diff --git a/lib/auth.js b/lib/auth.js
new file mode 100644
index 00000000..bc2ac846
--- /dev/null
+++ b/lib/auth.js
@@ -0,0 +1,40 @@
+"use strict";
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+    result["default"] = mod;
+    return result;
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const core = __importStar(require("@actions/core"));
+const path = __importStar(require("path"));
+const fs = __importStar(require("fs"));
+const os = __importStar(require("os"));
+function setNpmrc(registryUrl, registryToken, authFile) {
+    let projectNpmrc = path.resolve(process.cwd(), '.npmrc');
+    if (authFile) {
+        projectNpmrc = path.resolve(process.cwd(), authFile);
+    }
+    let newContents = '';
+    if (fs.existsSync(projectNpmrc)) {
+        const curContents = fs.readFileSync(projectNpmrc, 'utf8');
+        curContents.split(os.EOL).forEach(line => {
+            // Add current contents unless they are setting the registry
+            if (!line.startsWith('registry')) {
+                newContents += line + os.EOL;
+            }
+        });
+    }
+    newContents +=
+        'registry=' +
+            registryUrl +
+            os.EOL +
+            'always-auth=true' +
+            os.EOL +
+            registryUrl +
+            ':_authToken=${NPM_TOKEN}';
+    fs.writeFileSync(projectNpmrc, newContents);
+    core.exportSecret('NPM_TOKEN', registryToken);
+}
+exports.setNpmrc = setNpmrc;
diff --git a/lib/installer.js b/lib/installer.js
index e1201f15..a5046c98 100644
--- a/lib/installer.js
+++ b/lib/installer.js
@@ -63,8 +63,7 @@ function getNode(versionSpec) {
         //
         // prepend the tools path. instructs the agent to prepend for future tasks
         //
-        // TODO - addPath not implemented yet (this should probably actually be in core)
-        // tc.addPath(toolPath);
+        core.addPath(toolPath);
     });
 }
 exports.getNode = getNode;
diff --git a/lib/setup-node.js b/lib/setup-node.js
index 107564ee..a9792ffd 100644
--- a/lib/setup-node.js
+++ b/lib/setup-node.js
@@ -16,6 +16,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
 };
 Object.defineProperty(exports, "__esModule", { value: true });
 const core = __importStar(require("@actions/core"));
+const auth = __importStar(require("./auth"));
 const installer = __importStar(require("./installer"));
 function run() {
     return __awaiter(this, void 0, void 0, function* () {
@@ -29,6 +30,12 @@ function run() {
                 // TODO: installer doesn't support proxy
                 yield installer.getNode(version);
             }
+            const registryUrl = core.getInput('registryUrl');
+            if (registryUrl) {
+                const registryToken = core.getInput('registryToken', { required: true });
+                const authFile = core.getInput('authFile');
+                auth.setNpmrc(registryUrl, registryToken, authFile);
+            }
             // TODO: setup proxy from runner proxy config
             // TODO: problem matchers registered
         }
diff --git a/package-lock.json b/package-lock.json
index 4fe37449..c1bf2c56 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,34 +5,34 @@
   "requires": true,
   "dependencies": {
     "@actions/core": {
-      "version": "file:toolkit/actions-core-0.1.0.tgz",
+      "version": "file:../../../bryan/Projects/setup-node/toolkit/actions-core-0.1.0.tgz",
       "integrity": "sha512-1I2vFY5r80QcbM1R8Ika5Ke9uWGrF8nl33oQuP3bXVG47wMIw1DdAVK0A17CHJe5ObHU4gpwTuQakUdZaOlg0w==",
       "requires": {
-        "@actions/exit": "file:toolkit/actions-exit-0.0.0.tgz"
+        "@actions/exit": "^0.0.0"
       }
     },
     "@actions/exec": {
-      "version": "file:toolkit/actions-exec-1.0.0.tgz",
+      "version": "file:../../../bryan/Projects/setup-node/toolkit/actions-exec-1.0.0.tgz",
       "integrity": "sha512-AxtupsjQceVIf6nEECts5a1pDpWO4r3yq5lpTA73g1FXA0awDdTW3r9NFn8NGF6UaydkIN0BEOasQlS5qS30zg=="
     },
     "@actions/exit": {
-      "version": "file:toolkit/actions-exit-0.0.0.tgz",
+      "version": "file:../../../bryan/Projects/setup-node/toolkit/actions-exit-0.0.0.tgz",
       "integrity": "sha512-vQdxFWM0/AERkC79mQ886SqPmV4joWhrSF7hiSTiJoKkE9eTjrKV5WQtp7SXv6OntrQkKX+ZjgdGpv+0rvJRCw=="
     },
     "@actions/io": {
-      "version": "file:toolkit/actions-io-1.0.0.tgz",
+      "version": "file:../../../bryan/Projects/setup-node/toolkit/actions-io-1.0.0.tgz",
       "integrity": "sha512-Dox3bRCdyxoG0o1mSHt/uINbyQ2SfbhtJmmMuUQny6ARB1hU8ZUi+XR0cHUfd/SrwdzLUrxX4dV8x8ylNSBQpA=="
     },
     "@actions/tool-cache": {
-      "version": "file:toolkit/actions-tool-cache-1.0.0.tgz",
+      "version": "file:../../../bryan/Projects/setup-node/toolkit/actions-tool-cache-1.0.0.tgz",
       "integrity": "sha512-OfhQEpxnVfuaeBL2kbD+GfpoY1pOuBEIDKZowE/R0vPsJB/pML1VezhvBDbP8D8IBZA46aeQDA3l4iOsB69Hlw==",
       "requires": {
-        "@actions/core": "file:toolkit/actions-core-0.1.0.tgz",
-        "@actions/exec": "file:toolkit/actions-exec-1.0.0.tgz",
-        "@actions/io": "file:toolkit/actions-io-1.0.0.tgz",
-        "semver": "6.1.1",
-        "typed-rest-client": "1.4.0",
-        "uuid": "3.3.2"
+        "@actions/core": "^0.1.0",
+        "@actions/exec": "^1.0.0",
+        "@actions/io": "^1.0.0",
+        "semver": "^6.1.0",
+        "typed-rest-client": "^1.4.0",
+        "uuid": "^3.3.2"
       }
     },
     "@types/node": {
diff --git a/src/auth.ts b/src/auth.ts
new file mode 100644
index 00000000..17a45407
--- /dev/null
+++ b/src/auth.ts
@@ -0,0 +1,37 @@
+import * as core from '@actions/core';
+import * as path from 'path';
+import * as fs from 'fs';
+import * as os from 'os';
+
+export function setNpmrc(
+  registryUrl: string,
+  registryToken: string,
+  authFile?: string
+) {
+  let projectNpmrc: string = path.resolve(process.cwd(), '.npmrc');
+  if (authFile) {
+    projectNpmrc = path.resolve(process.cwd(), authFile);
+  }
+
+  let newContents = '';
+  if (fs.existsSync(projectNpmrc)) {
+    const curContents = fs.readFileSync(projectNpmrc, 'utf8');
+    curContents.split(os.EOL).forEach(line => {
+      // Add current contents unless they are setting the registry
+      if (!line.startsWith('registry')) {
+        newContents += line + os.EOL;
+      }
+    });
+  }
+  newContents +=
+    'registry=' +
+    registryUrl +
+    os.EOL +
+    'always-auth=true' +
+    os.EOL +
+    registryUrl +
+    ':_authToken=${NPM_TOKEN}';
+  fs.writeFileSync(projectNpmrc, newContents);
+
+  core.exportSecret('NPM_TOKEN', registryToken);
+}
diff --git a/src/installer.ts b/src/installer.ts
index abe24798..06fa8ae2 100644
--- a/src/installer.ts
+++ b/src/installer.ts
@@ -62,8 +62,7 @@ export async function getNode(versionSpec: string) {
   //
   // prepend the tools path. instructs the agent to prepend for future tasks
   //
-  // TODO - addPath not implemented yet (this should probably actually be in core)
-  // tc.addPath(toolPath);
+  core.addPath(toolPath);
 }
 
 async function queryLatestMatch(versionSpec: string): Promise<string> {
diff --git a/src/setup-node.ts b/src/setup-node.ts
index ce3c31f7..9d5d9e49 100644
--- a/src/setup-node.ts
+++ b/src/setup-node.ts
@@ -1,4 +1,5 @@
 import * as core from '@actions/core';
+import * as auth from './auth';
 import * as installer from './installer';
 
 async function run() {
@@ -13,6 +14,13 @@ async function run() {
       await installer.getNode(version);
     }
 
+    const registryUrl = core.getInput('registryUrl');
+    if (registryUrl) {
+      const registryToken = core.getInput('registryToken', {required: true});
+      const authFile = core.getInput('authFile');
+      auth.setNpmrc(registryUrl, registryToken, authFile);
+    }
+
     // TODO: setup proxy from runner proxy config
     // TODO: problem matchers registered
   } catch (error) {