|
| 1 | +"use strict"; |
| 2 | +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
| 3 | + if (k2 === undefined) k2 = k; |
| 4 | + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |
| 5 | +}) : (function(o, m, k, k2) { |
| 6 | + if (k2 === undefined) k2 = k; |
| 7 | + o[k2] = m[k]; |
| 8 | +})); |
| 9 | +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
| 10 | + Object.defineProperty(o, "default", { enumerable: true, value: v }); |
| 11 | +}) : function(o, v) { |
| 12 | + o["default"] = v; |
| 13 | +}); |
| 14 | +var __importStar = (this && this.__importStar) || function (mod) { |
| 15 | + if (mod && mod.__esModule) return mod; |
| 16 | + var result = {}; |
| 17 | + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
| 18 | + __setModuleDefault(result, mod); |
| 19 | + return result; |
| 20 | +}; |
| 21 | +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { |
| 22 | + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |
| 23 | + return new (P || (P = Promise))(function (resolve, reject) { |
| 24 | + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } |
| 25 | + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } |
| 26 | + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } |
| 27 | + step((generator = generator.apply(thisArg, _arguments || [])).next()); |
| 28 | + }); |
| 29 | +}; |
| 30 | +var __importDefault = (this && this.__importDefault) || function (mod) { |
| 31 | + return (mod && mod.__esModule) ? mod : { "default": mod }; |
| 32 | +}; |
| 33 | +Object.defineProperty(exports, "__esModule", { value: true }); |
| 34 | +const core = __importStar(require("@actions/core")); |
| 35 | +const fs_1 = __importDefault(require("fs")); |
| 36 | +const node_fetch_1 = __importDefault(require("node-fetch")); |
| 37 | +const config_1 = require("./config"); |
| 38 | +const exec = require('@actions/exec'); |
| 39 | +const glob = require('@actions/glob'); |
| 40 | +const exec_command = (command) => __awaiter(void 0, void 0, void 0, function* () { |
| 41 | + /** |
| 42 | + * When we execute a program, it writes on two outputs : standard and error. |
| 43 | + * Initalizing empty variables to receive these outputs |
| 44 | + */ |
| 45 | + let stdout = ''; |
| 46 | + let stderr = ''; |
| 47 | + const options = {}; |
| 48 | + /** |
| 49 | + * Defining actions for both outputs |
| 50 | + */ |
| 51 | + options.listeners = { |
| 52 | + stdout: (data) => { |
| 53 | + stdout += data.toString(); |
| 54 | + }, |
| 55 | + stderr: (data) => { |
| 56 | + stderr += data.toString(); |
| 57 | + } |
| 58 | + }; |
| 59 | + yield exec.exec(command, [], options); |
| 60 | + return stdout; |
| 61 | +}); |
| 62 | +const create_aliases = (deploymentUrl, customDeploymentFile, failIfAliasNotLinked) => __awaiter(void 0, void 0, void 0, function* () { |
| 63 | + core.debug(`Starting to link aliases`); |
| 64 | + /** |
| 65 | + * Globber is a github action tool https://github.com/actions/toolkit/tree/master/packages/glob |
| 66 | + * It helps us to find the absolute path for a file. Indeed, because we don't know where the action will be run and we need to find this file, wherever it is. |
| 67 | + */ |
| 68 | + const globber = yield glob.create(customDeploymentFile); |
| 69 | + const vercelConfigFile = (yield globber.glob())[0] || config_1.VERCEL_CONFIG_FILE; |
| 70 | + if (vercelConfigFile && fs_1.default.existsSync(vercelConfigFile)) { |
| 71 | + core.debug(`Found custom config file: ${vercelConfigFile}`); |
| 72 | + core.debug(`Found real path: ${vercelConfigFile}`); |
| 73 | + const vercelConfig = JSON.parse(fs_1.default.readFileSync(vercelConfigFile, 'utf8')); |
| 74 | + const { id, ownerId } = (yield node_fetch_1.default(`https://api.vercel.com/v11/now/deployments/get?url=${deploymentUrl.replace("https://", "")}`, { |
| 75 | + headers: { |
| 76 | + Authorization: `Bearer ${process.env.VERCEL_TOKEN}` |
| 77 | + }, |
| 78 | + method: 'GET' |
| 79 | + }).then(data => data.json())); |
| 80 | + let aliasCreationPromises = []; |
| 81 | + for (const alias of vercelConfig.alias) { |
| 82 | + console.log(`Creating alias ${alias}`); |
| 83 | + aliasCreationPromises.push(node_fetch_1.default(`https://api.vercel.com/v2/now/deployments/${id}/aliases?teamId=${ownerId}`, { |
| 84 | + headers: { |
| 85 | + Authorization: `Bearer ${process.env.VERCEL_TOKEN}`, |
| 86 | + "Content-Type": "application/json" |
| 87 | + }, |
| 88 | + body: JSON.stringify({ |
| 89 | + alias: alias |
| 90 | + }), |
| 91 | + method: 'POST' |
| 92 | + }).then(data => data.json())); |
| 93 | + } |
| 94 | + core.debug(`Resolving alias promises`); |
| 95 | + const aliasesResponse = yield Promise.all(aliasCreationPromises); |
| 96 | + console.log(`Alias creation response: ${aliasesResponse}`); |
| 97 | + if (failIfAliasNotLinked && aliasesResponse) { |
| 98 | + const failedAliases = aliasesResponse.filter((response) => response.error).map((response) => response.error); |
| 99 | + core.setFailed(`Got following errors: ${JSON.stringify(failedAliases)}`); |
| 100 | + return; |
| 101 | + } |
| 102 | + for (const alias of aliasesResponse.filter(response => !response.error)) { |
| 103 | + console.log(`Created alias ${alias}`); |
| 104 | + } |
| 105 | + } |
| 106 | + else { |
| 107 | + core.setFailed(`Cannot access to vercel config file "${vercelConfigFile}". Deployment succeeded but no aliases has been created.`); |
| 108 | + } |
| 109 | +}); |
| 110 | +const deploy = (command, deployAlias, failIfAliasNotLinked) => __awaiter(void 0, void 0, void 0, function* () { |
| 111 | + var _a, _b, _c; |
| 112 | + const stdout = yield exec_command(command); |
| 113 | + /** |
| 114 | + * Parsing this huge output by using Regex match. |
| 115 | + * match function return strings matching with the pattern. |
| 116 | + * Pattern "/https?:\/\/[^ ]+.vercel.app/gi" |
| 117 | + * "/https?\/\/:" start matching when we find http:// or https:// |
| 118 | + * "[^ ]+.vercel.app" will catch everything as a vercel subdomain, so "*.vercel.app" |
| 119 | + * "/g" allows us to have many matchess |
| 120 | + * "i" make the regex case insensitive. It will match for "https://subDomainApp.vercel.app" and "https://subdomainapp.vercel.app" |
| 121 | + * shift returns the first occurence |
| 122 | + */ |
| 123 | + const deploymentUrl = (_a = stdout.match(/https?:\/\/[^ ]+.vercel.app/gi)) === null || _a === void 0 ? void 0 : _a.shift(); |
| 124 | + /** |
| 125 | + * Locating any custom config file for Vercel (if you are using one file per customer or deployment for the same app) |
| 126 | + * match function return strings matching with the pattern. |
| 127 | + * Pattern "/--local-config=.[^$]+?.json/gs" |
| 128 | + * "/--local-config=" starts matching on finding the argument local-config |
| 129 | + * "[^$]+?.json" with a json file provided as value |
| 130 | + * "/g" allows us to have many matchess |
| 131 | + * "s" reduce match scope on the same line |
| 132 | + * shift returns the first occurence |
| 133 | + * split isolates the json file |
| 134 | + * find automatically finds the matching json file |
| 135 | + */ |
| 136 | + const customDeploymentFile = (_c = (_b = stdout.match(/--local-config=.[^$]+?.json/gs)) === null || _b === void 0 ? void 0 : _b.shift()) === null || _c === void 0 ? void 0 : _c.split("=").find(el => el.endsWith(".json")); |
| 137 | + core.debug(`Command: ${command}`); |
| 138 | + core.debug(`Custom deploy file: ${customDeploymentFile}`); |
| 139 | + if (deploymentUrl) { |
| 140 | + const deploymentDomain = deploymentUrl.replace("https://", ""); |
| 141 | + console.log(`Found url deployment. Exporting it...`); |
| 142 | + console.log(`VERCEL_DEPLOYMENT_URL=${deploymentUrl}`); |
| 143 | + core.exportVariable("VERCEL_DEPLOYMENT_URL", deploymentUrl); |
| 144 | + core.setOutput("VERCEL_DEPLOYMENT_URL", deploymentUrl); |
| 145 | + console.log(`VERCEL_DEPLOYMENT_DOMAIN=${deploymentDomain}`); |
| 146 | + core.exportVariable("VERCEL_DEPLOYMENT_DOMAIN", deploymentDomain); |
| 147 | + core.setOutput("VERCEL_DEPLOYMENT_DOMAIN", deploymentDomain); |
| 148 | + if (deployAlias) { |
| 149 | + yield create_aliases(deploymentUrl, customDeploymentFile, failIfAliasNotLinked); |
| 150 | + } |
| 151 | + } |
| 152 | + else { |
| 153 | + core.setFailed(`"Error during command execution, cannot find any url matching (using a regex to retrieve a url as "https://*.vercel.app"`); |
| 154 | + } |
| 155 | +}); |
| 156 | +exports.default = deploy; |
0 commit comments