diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml new file mode 100644 index 00000000..ed7dd03b --- /dev/null +++ b/.github/workflows/release-pr.yml @@ -0,0 +1,14 @@ +name: Create release PR + +on: + workflow_dispatch: + inputs: + release: + description: "Define release version (ex: v1, v2, v3)" + required: true + +jobs: + release-pr: + uses: OliverMKing/javascript-release-workflow/.github/workflows/release-pr.yml@main + with: + release: ${{ github.event.inputs.release }} \ No newline at end of file diff --git a/.github/workflows/tag-and-draft.yml b/.github/workflows/tag-and-draft.yml new file mode 100644 index 00000000..ef653d0e --- /dev/null +++ b/.github/workflows/tag-and-draft.yml @@ -0,0 +1,10 @@ +name: Tag and create release draft + +on: + push: + branches: + - releases/* + +jobs: + tag-and-release: + uses: OliverMKing/javascript-release-workflow/.github/workflows/tag-and-release.yml@main \ No newline at end of file diff --git a/.github/workflows/ts-build-check.yml b/.github/workflows/ts-build-check.yml deleted file mode 100644 index 38ab2fba..00000000 --- a/.github/workflows/ts-build-check.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: TypeScript Build Check - -on: pull_request - -jobs: - ts-build-check: - runs-on: ubuntu-latest - steps: - - name: Checkout Pull Request - uses: actions/checkout@v2 - with: - ref: ${{github.event.pull_request.head.ref}} - repository: ${{github.event.pull_request.head.repo.full_name}} - path: original-pr - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: 12.x - - name: Clone and Build Pull Request - run: | - cp $GITHUB_WORKSPACE/original-pr/ $GITHUB_WORKSPACE/built-pr -r - cd $GITHUB_WORKSPACE/built-pr/ - npm i - npm run build - - name: Compare Built Directories - id: diff - run: | - DIFF=$(diff $GITHUB_WORKSPACE/original-pr/lib $GITHUB_WORKSPACE/built-pr/lib -rqiEZbwBd) - if [ "$DIFF" != "" ]; then exit 1; else echo -e "PR contains up-to-date compiled JavaScript."; fi - - name: Comment Unbuilt TypeScript - if: failure() && steps.diff.outcome == 'failure' - uses: actions/github-script@v2 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - github.issues.createComment({ - issue_number: ${{ github.event.number }}, - owner: context.repo.owner, - repo: context.repo.repo, - body: 'Please compile the TypeScript code with `npm run build`. The compiled JavaScript is not up-to-date.' - }) diff --git a/.gitignore b/.gitignore index 794407c2..261a2dae 100644 --- a/.gitignore +++ b/.gitignore @@ -329,3 +329,6 @@ ASALocalRun/ .mfractor/ node_modules coverage + +# Transpiled JS +lib/ diff --git a/lib/kubeconfigs/arc.js b/lib/kubeconfigs/arc.js deleted file mode 100644 index f88a5abd..00000000 --- a/lib/kubeconfigs/arc.js +++ /dev/null @@ -1,84 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -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)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - 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) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getArcKubeconfig = exports.KUBECONFIG_LOCATION = void 0; -const core = __importStar(require("@actions/core")); -const io = __importStar(require("@actions/io")); -const method_1 = require("../types/method"); -const path = __importStar(require("path")); -const azCommands_1 = require("./azCommands"); -const RUNNER_TEMP = process.env["RUNNER_TEMP"] || ""; -exports.KUBECONFIG_LOCATION = path.join(RUNNER_TEMP, `arc_kubeconfig_${Date.now()}`); -/** - * Gets the kubeconfig based on provided method for an Arc Kubernetes cluster - * @returns The kubeconfig wrapped in a Promise - */ -function getArcKubeconfig() { - return __awaiter(this, void 0, void 0, function* () { - const resourceGroupName = core.getInput("resource-group", { required: true }); - const clusterName = core.getInput("cluster-name", { required: true }); - const azPath = yield io.which("az", true); - const method = method_1.parseMethod(core.getInput("method", { required: true })); - yield azCommands_1.runAzCliCommand(azPath, ["extension", "add", "-n", "connectedk8s"]); - switch (method) { - case method_1.Method.SERVICE_ACCOUNT: - const saToken = core.getInput("token", { required: true }); - return yield azCommands_1.runAzKubeconfigCommandBlocking(azPath, [ - "connectedk8s", - "proxy", - "-n", - clusterName, - "-g", - resourceGroupName, - "--token", - saToken, - "-f", - exports.KUBECONFIG_LOCATION, - ], exports.KUBECONFIG_LOCATION); - case method_1.Method.SERVICE_PRINCIPAL: - return yield azCommands_1.runAzKubeconfigCommandBlocking(azPath, [ - "connectedk8s", - "proxy", - "-n", - clusterName, - "-g", - resourceGroupName, - "-f", - exports.KUBECONFIG_LOCATION, - ], exports.KUBECONFIG_LOCATION); - case undefined: - core.warning("Defaulting to kubeconfig method"); - case method_1.Method.KUBECONFIG: - default: - throw Error("Kubeconfig method not supported for Arc cluster"); - } - }); -} -exports.getArcKubeconfig = getArcKubeconfig; diff --git a/lib/kubeconfigs/azCommands.js b/lib/kubeconfigs/azCommands.js deleted file mode 100644 index e1ed438d..00000000 --- a/lib/kubeconfigs/azCommands.js +++ /dev/null @@ -1,67 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -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)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - 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) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.runAzKubeconfigCommandBlocking = exports.runAzCliCommand = void 0; -const fs = __importStar(require("fs")); -const exec_1 = require("@actions/exec"); -const child_process_1 = require("child_process"); -const AZ_TIMEOUT_SECONDS = 120; -/** - * Executes an az cli command - * @param azPath The path to the az tool - * @param args The arguments to be invoked - * @param options Optional options for the command execution - */ -function runAzCliCommand(azPath, args, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - yield exec_1.exec(azPath, args, options); - }); -} -exports.runAzCliCommand = runAzCliCommand; -/** - * Executes an az cli command that will set the kubeconfig - * @param azPath The path to the az tool - * @param args The arguments to be be invoked - * @param kubeconfigPath The path to the kubeconfig that is updated by the command - * @returns The contents of the kubeconfig - */ -function runAzKubeconfigCommandBlocking(azPath, args, kubeconfigPath) { - return __awaiter(this, void 0, void 0, function* () { - const proc = child_process_1.spawn(azPath, args, { - detached: true, - stdio: "ignore", - }); - proc.unref(); - yield sleep(AZ_TIMEOUT_SECONDS); - return fs.readFileSync(kubeconfigPath).toString(); - }); -} -exports.runAzKubeconfigCommandBlocking = runAzKubeconfigCommandBlocking; -const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000)); diff --git a/lib/kubeconfigs/default.js b/lib/kubeconfigs/default.js deleted file mode 100644 index 113a3f27..00000000 --- a/lib/kubeconfigs/default.js +++ /dev/null @@ -1,87 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -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)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createKubeconfig = exports.getDefaultKubeconfig = void 0; -const core = __importStar(require("@actions/core")); -const jsyaml = __importStar(require("js-yaml")); -const k8sSecret_1 = require("../types/k8sSecret"); -const method_1 = require("../types/method"); -/** - * Gets the kubeconfig based on provided method for a default Kubernetes cluster - * @returns The kubeconfig - */ -function getDefaultKubeconfig() { - const method = method_1.parseMethod(core.getInput("method", { required: true })); - switch (method) { - case method_1.Method.SERVICE_ACCOUNT: { - const clusterUrl = core.getInput("k8s-url", { required: true }); - core.debug("Found clusterUrl. Creating kubeconfig using certificate and token"); - const k8sSecret = core.getInput("k8s-secret", { - required: true, - }); - const parsedK8sSecret = k8sSecret_1.parseK8sSecret(jsyaml.load(k8sSecret)); - const certAuth = parsedK8sSecret.data["ca.crt"]; - const token = Buffer.from(parsedK8sSecret.data.token, "base64").toString(); - return createKubeconfig(certAuth, token, clusterUrl); - } - case method_1.Method.SERVICE_PRINCIPAL: { - core.warning("Service Principal method not supported for default cluster type"); - } - case undefined: { - core.warning("Defaulting to kubeconfig method"); - } - default: { - core.debug("Setting context using kubeconfig"); - return core.getInput("kubeconfig", { required: true }); - } - } -} -exports.getDefaultKubeconfig = getDefaultKubeconfig; -/** - * Creates a kubeconfig and returns the string representation - * @param certAuth The certificate authentication of the cluster - * @param token The user token - * @param clusterUrl The server url of the cluster - * @returns The kubeconfig as a string - */ -function createKubeconfig(certAuth, token, clusterUrl) { - const kubeconfig = { - apiVersion: "v1", - kind: "Config", - clusters: [ - { - cluster: { - "certificate-authority-data": certAuth, - server: clusterUrl, - }, - }, - ], - users: [ - { - user: { - token: token, - }, - }, - ], - }; - return JSON.stringify(kubeconfig); -} -exports.createKubeconfig = createKubeconfig; diff --git a/lib/run.js b/lib/run.js deleted file mode 100644 index 86908fc1..00000000 --- a/lib/run.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -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)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - 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) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.run = void 0; -const core = __importStar(require("@actions/core")); -const path = __importStar(require("path")); -const fs = __importStar(require("fs")); -const cluster_1 = require("./types/cluster"); -const utils_1 = require("./utils"); -/** - * Sets the Kubernetes context based on supplied action inputs - */ -function run() { - return __awaiter(this, void 0, void 0, function* () { - // get inputs - const clusterType = cluster_1.parseCluster(core.getInput("cluster-type", { - required: true, - })); - const runnerTempDirectory = process.env["RUNNER_TEMP"]; - const kubeconfigPath = path.join(runnerTempDirectory, `kubeconfig_${Date.now()}`); - // get kubeconfig and update context - const kubeconfig = yield utils_1.getKubeconfig(clusterType); - const kubeconfigWithContext = utils_1.setContext(kubeconfig); - // output kubeconfig - core.debug(`Writing kubeconfig contents to ${kubeconfigPath}`); - fs.writeFileSync(kubeconfigPath, kubeconfigWithContext); - fs.chmodSync(kubeconfigPath, "600"); - core.debug("Setting KUBECONFIG environment variable"); - core.exportVariable("KUBECONFIG", kubeconfigPath); - }); -} -exports.run = run; -// Run the application -run().catch(core.setFailed); diff --git a/lib/types/cluster.js b/lib/types/cluster.js deleted file mode 100644 index 899bfef0..00000000 --- a/lib/types/cluster.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseCluster = exports.Cluster = void 0; -var Cluster; -(function (Cluster) { - Cluster["ARC"] = "arc"; - Cluster["GENERIC"] = "generic"; -})(Cluster = exports.Cluster || (exports.Cluster = {})); -/** - * Converts a string to the Cluster enum - * @param str The cluster type (case insensitive) - * @returns The Cluster enum or undefined if it can't be parsed - */ -exports.parseCluster = (str) => Cluster[Object.keys(Cluster).filter((k) => Cluster[k].toString().toLowerCase() === str.toLowerCase())[0]]; diff --git a/lib/types/k8sSecret.js b/lib/types/k8sSecret.js deleted file mode 100644 index fc416e2d..00000000 --- a/lib/types/k8sSecret.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -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)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseK8sSecret = void 0; -const util = __importStar(require("util")); -/** - * Throws an error if an object does not have all required fields to be a K8sSecret - * @param secret - * @returns A type guarded K8sSecret - */ -function parseK8sSecret(secret) { - if (!secret) - throw Error("K8s secret yaml is invalid"); - if (!secret.data) - throw k8sSecretMissingFieldError("data"); - if (!secret.data.token) - throw k8sSecretMissingFieldError("token"); - if (!secret.data["ca.crt"]) - throw k8sSecretMissingFieldError("ca.crt"); - return secret; -} -exports.parseK8sSecret = parseK8sSecret; -const k8sSecretMissingFieldError = (field) => Error(util.format("K8s secret yaml does not contain %s field", field)); diff --git a/lib/types/method.js b/lib/types/method.js deleted file mode 100644 index 7828e7fb..00000000 --- a/lib/types/method.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseMethod = exports.Method = void 0; -var Method; -(function (Method) { - Method["KUBECONFIG"] = "kubeconfig"; - Method["SERVICE_ACCOUNT"] = "service-account"; - Method["SERVICE_PRINCIPAL"] = "service-principal"; -})(Method = exports.Method || (exports.Method = {})); -/** - * Converts a string to the Method enum - * @param str The method (case insensitive) - * @returns The Method enum or undefined if it can't be parsed - */ -exports.parseMethod = (str) => Method[Object.keys(Method).filter((k) => Method[k].toString().toLowerCase() === str.toLowerCase())[0]]; diff --git a/lib/utils.js b/lib/utils.js deleted file mode 100644 index b13f5515..00000000 --- a/lib/utils.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -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)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - 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) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.setContext = exports.getKubeconfig = void 0; -const core = __importStar(require("@actions/core")); -const client_node_1 = require("@kubernetes/client-node"); -const default_1 = require("./kubeconfigs/default"); -const arc_1 = require("./kubeconfigs/arc"); -const cluster_1 = require("./types/cluster"); -/** - * Gets the kubeconfig based on Kubernetes cluster type - * @param type The cluster type for the kubeconfig (defaults to generic) - * @returns A promise of the kubeconfig - */ -function getKubeconfig(type) { - return __awaiter(this, void 0, void 0, function* () { - switch (type) { - case cluster_1.Cluster.ARC: { - return yield arc_1.getArcKubeconfig(); - } - case undefined: { - core.warning("Cluster type not recognized. Defaulting to generic."); - } - default: { - return default_1.getDefaultKubeconfig(); - } - } - }); -} -exports.getKubeconfig = getKubeconfig; -/** - * Sets the context by updating the kubeconfig - * @param kubeconfig The kubeconfig - * @returns Updated kubeconfig with the context - */ -function setContext(kubeconfig) { - const context = core.getInput("context"); - if (!context) { - core.debug("Can't set context because context is unspecified."); - return kubeconfig; - } - // load current kubeconfig - const kc = new client_node_1.KubeConfig(); - kc.loadFromString(kubeconfig); - // update kubeconfig - kc.setCurrentContext(context); - return kc.exportConfig(); -} -exports.setContext = setContext;