├── .github ├── dependabot.yml └── workflows │ ├── integration.yml │ └── npm.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── LICENSE ├── README.md ├── __tests__ └── index.test.js ├── action.yml ├── dist ├── index.js └── licenses.txt ├── package-lock.json ├── package.json └── src ├── index.js └── utils.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "npm" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | name: integration 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '**.md' 9 | push: 10 | branches: 11 | - main 12 | paths-ignore: 13 | - '**.md' 14 | jobs: 15 | run: 16 | name: Run 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | - php-version: "7.4" 23 | drupal-version: "~8.9" 24 | - php-version: "7.4" 25 | drupal-version: "^9" 26 | - php-version: "8.0" 27 | drupal-version: "^9" 28 | - php-version: "8.1" 29 | drupal-version: "^10" 30 | - php-version: "8.2" 31 | drupal-version: "11.x-dev" 32 | env: 33 | extensions: zip, gd 34 | key: cache-v1 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@v4 38 | - name: Setup cache environment 39 | id: cache-env 40 | uses: shivammathur/cache-extensions@develop 41 | with: 42 | php-version: ${{ matrix.php-version }} 43 | extensions: ${{ env.extensions }} 44 | key: ${{ env.key }} 45 | 46 | - name: Cache extensions 47 | uses: actions/cache@v4 48 | with: 49 | path: ${{ steps.cache-env.outputs.dir }} 50 | key: ${{ steps.cache-env.outputs.key }} 51 | restore-keys: ${{ steps.cache-env.outputs.key }} 52 | 53 | - name: "Install PHP" 54 | uses: "shivammathur/setup-php@v2" 55 | with: 56 | coverage: "none" 57 | php-version: ${{ matrix.php-version }} 58 | extensions: ${{ env.extensions }} 59 | tools: composer:v2 60 | 61 | # Execute out script directly without `uses` 62 | # core.getInput() checks for environment variablts prefixed INPUT_* 63 | # process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '' 64 | - name: Setup Drupal 65 | run: node dist/index.js 66 | env: 67 | INPUT_VERSION: ${{ matrix.drupal-version }} 68 | INPUT_PATH: ~/drupal 69 | INPUT_ALLOW_PLUGINS: oomphinc/composer-installers-extender 70 | - name: Debug composer.json 71 | run: cat ~/drupal/composer.json 72 | - name: Include plugin 73 | run: cd ~/drupal && composer require oomphinc/composer-installers-extender 74 | - name: Verify build 75 | run: test -f ~/drupal/web/index.php 76 | -------------------------------------------------------------------------------- /.github/workflows/npm.yml: -------------------------------------------------------------------------------- 1 | name: npm 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '**.md' 9 | push: 10 | branches: 11 | - main 12 | paths-ignore: 13 | - '**.md' 14 | jobs: 15 | test: 16 | name: Test 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Use Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: 12.x 24 | - run: npm ci 25 | - run: npm test 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Serverless directories 79 | .serverless/ 80 | 81 | # FuseBox cache 82 | .fusebox/ 83 | 84 | # DynamoDB Local files 85 | .dynamodb/ 86 | 87 | # TernJS port file 88 | .tern-port 89 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run test 5 | npm run build 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Bluehorn Digital 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Setup Drupal in GitHub Actions 2 | 3 | GitHub Action to setup Drupal for testing an extension 4 | 5 | ## Inputs 6 | 7 | ### `version` 8 | 9 | The version constraint for Drupal. Defaults to `^9.0` 10 | 11 | Examples: 12 | 13 | * `^9.1` 14 | * `^8.8.9` 15 | * `~9.0` 16 | 17 | ### `path` 18 | 19 | Where to build Drupal. Defaults to `~/drupal`. 20 | 21 | ### `dependencies` 22 | 23 | Extra dependencies to install. 24 | 25 | ### `allow_plugins` 26 | 27 | Additional packages to configure with `allow-plugins`. 28 | 29 | ## Example usage 30 | 31 | ``` 32 | uses: bluehorndigital/setup-drupal@v1 33 | with: 34 | version: '9.2.x-dev' 35 | dependencies: 'drupal/token drupal/ctools' 36 | ``` 37 | -------------------------------------------------------------------------------- /__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | const utils = require ('../src/utils') 2 | 3 | test('resolved path', () => { 4 | expect(utils.resolvePath('~/drupal')).toBe(`${process.env.HOME}/drupal`); 5 | }); 6 | 7 | test('can find major version from constraint', () => { 8 | expect(utils.getMajorVersionFromConstraint('^9.1')).toBe(9); 9 | expect(utils.getMajorVersionFromConstraint('^9.2@alpha')).toBe(9); 10 | expect(utils.getMajorVersionFromConstraint('8.9.x-dev')).toBe(8); 11 | expect(utils.getMajorVersionFromConstraint('dev-8.9.x')).toBe(8); 12 | }); 13 | 14 | test('can get array from string', () => { 15 | expect(utils.stringToArray("composer/installers\nphpstan/extension-installer")).toEqual([ 16 | 'composer/installers', 17 | 'phpstan/extension-installer' 18 | ]); 19 | expect(utils.stringToArray("composer/installers\r\nphpstan/extension-installer")).toEqual([ 20 | 'composer/installers', 21 | 'phpstan/extension-installer' 22 | ]); 23 | expect(utils.stringToArray("composer/installers,phpstan/extension-installer")).toEqual([ 24 | 'composer/installers', 25 | 'phpstan/extension-installer' 26 | ]); 27 | }) 28 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Drupal action' 2 | author: bluehorndigital 3 | description: 'GitHub Action to setup Drupal for testing an extension' 4 | inputs: 5 | version: 6 | description: 'Drupal version constraint' 7 | required: true 8 | default: '^9.0' 9 | path: 10 | description: 'Path to create the Drupal project' 11 | required: true 12 | default: '~/drupal' 13 | dependencies: 14 | description: 'Additional dependencies to install' 15 | required: false 16 | allow_plugins: 17 | description: 'Packages to add to allow-plugins for Composer' 18 | required: false 19 | default: '' 20 | runs: 21 | using: 'node16' 22 | main: 'dist/index.js' 23 | branding: 24 | icon: 'box' 25 | color: 'blue' 26 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (() => { // webpackBootstrap 3 | /******/ var __webpack_modules__ = ({ 4 | 5 | /***/ 241: 6 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 7 | 8 | "use strict"; 9 | 10 | var __importStar = (this && this.__importStar) || function (mod) { 11 | if (mod && mod.__esModule) return mod; 12 | var result = {}; 13 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 14 | result["default"] = mod; 15 | return result; 16 | }; 17 | Object.defineProperty(exports, "__esModule", ({ value: true })); 18 | const os = __importStar(__nccwpck_require__(87)); 19 | const utils_1 = __nccwpck_require__(278); 20 | /** 21 | * Commands 22 | * 23 | * Command Format: 24 | * ::name key=value,key=value::message 25 | * 26 | * Examples: 27 | * ::warning::This is the message 28 | * ::set-env name=MY_VAR::some value 29 | */ 30 | function issueCommand(command, properties, message) { 31 | const cmd = new Command(command, properties, message); 32 | process.stdout.write(cmd.toString() + os.EOL); 33 | } 34 | exports.issueCommand = issueCommand; 35 | function issue(name, message = '') { 36 | issueCommand(name, {}, message); 37 | } 38 | exports.issue = issue; 39 | const CMD_STRING = '::'; 40 | class Command { 41 | constructor(command, properties, message) { 42 | if (!command) { 43 | command = 'missing.command'; 44 | } 45 | this.command = command; 46 | this.properties = properties; 47 | this.message = message; 48 | } 49 | toString() { 50 | let cmdStr = CMD_STRING + this.command; 51 | if (this.properties && Object.keys(this.properties).length > 0) { 52 | cmdStr += ' '; 53 | let first = true; 54 | for (const key in this.properties) { 55 | if (this.properties.hasOwnProperty(key)) { 56 | const val = this.properties[key]; 57 | if (val) { 58 | if (first) { 59 | first = false; 60 | } 61 | else { 62 | cmdStr += ','; 63 | } 64 | cmdStr += `${key}=${escapeProperty(val)}`; 65 | } 66 | } 67 | } 68 | } 69 | cmdStr += `${CMD_STRING}${escapeData(this.message)}`; 70 | return cmdStr; 71 | } 72 | } 73 | function escapeData(s) { 74 | return utils_1.toCommandValue(s) 75 | .replace(/%/g, '%25') 76 | .replace(/\r/g, '%0D') 77 | .replace(/\n/g, '%0A'); 78 | } 79 | function escapeProperty(s) { 80 | return utils_1.toCommandValue(s) 81 | .replace(/%/g, '%25') 82 | .replace(/\r/g, '%0D') 83 | .replace(/\n/g, '%0A') 84 | .replace(/:/g, '%3A') 85 | .replace(/,/g, '%2C'); 86 | } 87 | //# sourceMappingURL=command.js.map 88 | 89 | /***/ }), 90 | 91 | /***/ 186: 92 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 93 | 94 | "use strict"; 95 | 96 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 97 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 98 | return new (P || (P = Promise))(function (resolve, reject) { 99 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 100 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 101 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 102 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 103 | }); 104 | }; 105 | var __importStar = (this && this.__importStar) || function (mod) { 106 | if (mod && mod.__esModule) return mod; 107 | var result = {}; 108 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 109 | result["default"] = mod; 110 | return result; 111 | }; 112 | Object.defineProperty(exports, "__esModule", ({ value: true })); 113 | const command_1 = __nccwpck_require__(241); 114 | const file_command_1 = __nccwpck_require__(717); 115 | const utils_1 = __nccwpck_require__(278); 116 | const os = __importStar(__nccwpck_require__(87)); 117 | const path = __importStar(__nccwpck_require__(622)); 118 | /** 119 | * The code to exit an action 120 | */ 121 | var ExitCode; 122 | (function (ExitCode) { 123 | /** 124 | * A code indicating that the action was successful 125 | */ 126 | ExitCode[ExitCode["Success"] = 0] = "Success"; 127 | /** 128 | * A code indicating that the action was a failure 129 | */ 130 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 131 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 132 | //----------------------------------------------------------------------- 133 | // Variables 134 | //----------------------------------------------------------------------- 135 | /** 136 | * Sets env variable for this action and future actions in the job 137 | * @param name the name of the variable to set 138 | * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify 139 | */ 140 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 141 | function exportVariable(name, val) { 142 | const convertedVal = utils_1.toCommandValue(val); 143 | process.env[name] = convertedVal; 144 | const filePath = process.env['GITHUB_ENV'] || ''; 145 | if (filePath) { 146 | const delimiter = '_GitHubActionsFileCommandDelimeter_'; 147 | const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; 148 | file_command_1.issueCommand('ENV', commandValue); 149 | } 150 | else { 151 | command_1.issueCommand('set-env', { name }, convertedVal); 152 | } 153 | } 154 | exports.exportVariable = exportVariable; 155 | /** 156 | * Registers a secret which will get masked from logs 157 | * @param secret value of the secret 158 | */ 159 | function setSecret(secret) { 160 | command_1.issueCommand('add-mask', {}, secret); 161 | } 162 | exports.setSecret = setSecret; 163 | /** 164 | * Prepends inputPath to the PATH (for this action and future actions) 165 | * @param inputPath 166 | */ 167 | function addPath(inputPath) { 168 | const filePath = process.env['GITHUB_PATH'] || ''; 169 | if (filePath) { 170 | file_command_1.issueCommand('PATH', inputPath); 171 | } 172 | else { 173 | command_1.issueCommand('add-path', {}, inputPath); 174 | } 175 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 176 | } 177 | exports.addPath = addPath; 178 | /** 179 | * Gets the value of an input. The value is also trimmed. 180 | * 181 | * @param name name of the input to get 182 | * @param options optional. See InputOptions. 183 | * @returns string 184 | */ 185 | function getInput(name, options) { 186 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 187 | if (options && options.required && !val) { 188 | throw new Error(`Input required and not supplied: ${name}`); 189 | } 190 | return val.trim(); 191 | } 192 | exports.getInput = getInput; 193 | /** 194 | * Sets the value of an output. 195 | * 196 | * @param name name of the output to set 197 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 198 | */ 199 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 200 | function setOutput(name, value) { 201 | command_1.issueCommand('set-output', { name }, value); 202 | } 203 | exports.setOutput = setOutput; 204 | /** 205 | * Enables or disables the echoing of commands into stdout for the rest of the step. 206 | * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 207 | * 208 | */ 209 | function setCommandEcho(enabled) { 210 | command_1.issue('echo', enabled ? 'on' : 'off'); 211 | } 212 | exports.setCommandEcho = setCommandEcho; 213 | //----------------------------------------------------------------------- 214 | // Results 215 | //----------------------------------------------------------------------- 216 | /** 217 | * Sets the action status to failed. 218 | * When the action exits it will be with an exit code of 1 219 | * @param message add error issue message 220 | */ 221 | function setFailed(message) { 222 | process.exitCode = ExitCode.Failure; 223 | error(message); 224 | } 225 | exports.setFailed = setFailed; 226 | //----------------------------------------------------------------------- 227 | // Logging Commands 228 | //----------------------------------------------------------------------- 229 | /** 230 | * Gets whether Actions Step Debug is on or not 231 | */ 232 | function isDebug() { 233 | return process.env['RUNNER_DEBUG'] === '1'; 234 | } 235 | exports.isDebug = isDebug; 236 | /** 237 | * Writes debug message to user log 238 | * @param message debug message 239 | */ 240 | function debug(message) { 241 | command_1.issueCommand('debug', {}, message); 242 | } 243 | exports.debug = debug; 244 | /** 245 | * Adds an error issue 246 | * @param message error issue message. Errors will be converted to string via toString() 247 | */ 248 | function error(message) { 249 | command_1.issue('error', message instanceof Error ? message.toString() : message); 250 | } 251 | exports.error = error; 252 | /** 253 | * Adds an warning issue 254 | * @param message warning issue message. Errors will be converted to string via toString() 255 | */ 256 | function warning(message) { 257 | command_1.issue('warning', message instanceof Error ? message.toString() : message); 258 | } 259 | exports.warning = warning; 260 | /** 261 | * Writes info to log with console.log. 262 | * @param message info message 263 | */ 264 | function info(message) { 265 | process.stdout.write(message + os.EOL); 266 | } 267 | exports.info = info; 268 | /** 269 | * Begin an output group. 270 | * 271 | * Output until the next `groupEnd` will be foldable in this group 272 | * 273 | * @param name The name of the output group 274 | */ 275 | function startGroup(name) { 276 | command_1.issue('group', name); 277 | } 278 | exports.startGroup = startGroup; 279 | /** 280 | * End an output group. 281 | */ 282 | function endGroup() { 283 | command_1.issue('endgroup'); 284 | } 285 | exports.endGroup = endGroup; 286 | /** 287 | * Wrap an asynchronous function call in a group. 288 | * 289 | * Returns the same type as the function itself. 290 | * 291 | * @param name The name of the group 292 | * @param fn The function to wrap in the group 293 | */ 294 | function group(name, fn) { 295 | return __awaiter(this, void 0, void 0, function* () { 296 | startGroup(name); 297 | let result; 298 | try { 299 | result = yield fn(); 300 | } 301 | finally { 302 | endGroup(); 303 | } 304 | return result; 305 | }); 306 | } 307 | exports.group = group; 308 | //----------------------------------------------------------------------- 309 | // Wrapper action state 310 | //----------------------------------------------------------------------- 311 | /** 312 | * Saves state for current action, the state can only be retrieved by this action's post job execution. 313 | * 314 | * @param name name of the state to store 315 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 316 | */ 317 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 318 | function saveState(name, value) { 319 | command_1.issueCommand('save-state', { name }, value); 320 | } 321 | exports.saveState = saveState; 322 | /** 323 | * Gets the value of an state set by this action's main execution. 324 | * 325 | * @param name name of the state to get 326 | * @returns string 327 | */ 328 | function getState(name) { 329 | return process.env[`STATE_${name}`] || ''; 330 | } 331 | exports.getState = getState; 332 | //# sourceMappingURL=core.js.map 333 | 334 | /***/ }), 335 | 336 | /***/ 717: 337 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 338 | 339 | "use strict"; 340 | 341 | // For internal use, subject to change. 342 | var __importStar = (this && this.__importStar) || function (mod) { 343 | if (mod && mod.__esModule) return mod; 344 | var result = {}; 345 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 346 | result["default"] = mod; 347 | return result; 348 | }; 349 | Object.defineProperty(exports, "__esModule", ({ value: true })); 350 | // We use any as a valid input type 351 | /* eslint-disable @typescript-eslint/no-explicit-any */ 352 | const fs = __importStar(__nccwpck_require__(747)); 353 | const os = __importStar(__nccwpck_require__(87)); 354 | const utils_1 = __nccwpck_require__(278); 355 | function issueCommand(command, message) { 356 | const filePath = process.env[`GITHUB_${command}`]; 357 | if (!filePath) { 358 | throw new Error(`Unable to find environment variable for file command ${command}`); 359 | } 360 | if (!fs.existsSync(filePath)) { 361 | throw new Error(`Missing file at path: ${filePath}`); 362 | } 363 | fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { 364 | encoding: 'utf8' 365 | }); 366 | } 367 | exports.issueCommand = issueCommand; 368 | //# sourceMappingURL=file-command.js.map 369 | 370 | /***/ }), 371 | 372 | /***/ 278: 373 | /***/ ((__unused_webpack_module, exports) => { 374 | 375 | "use strict"; 376 | 377 | // We use any as a valid input type 378 | /* eslint-disable @typescript-eslint/no-explicit-any */ 379 | Object.defineProperty(exports, "__esModule", ({ value: true })); 380 | /** 381 | * Sanitizes an input into a string so it can be passed into issueCommand safely 382 | * @param input input to sanitize into a string 383 | */ 384 | function toCommandValue(input) { 385 | if (input === null || input === undefined) { 386 | return ''; 387 | } 388 | else if (typeof input === 'string' || input instanceof String) { 389 | return input; 390 | } 391 | return JSON.stringify(input); 392 | } 393 | exports.toCommandValue = toCommandValue; 394 | //# sourceMappingURL=utils.js.map 395 | 396 | /***/ }), 397 | 398 | /***/ 514: 399 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 400 | 401 | "use strict"; 402 | 403 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 404 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 405 | return new (P || (P = Promise))(function (resolve, reject) { 406 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 407 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 408 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 409 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 410 | }); 411 | }; 412 | var __importStar = (this && this.__importStar) || function (mod) { 413 | if (mod && mod.__esModule) return mod; 414 | var result = {}; 415 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 416 | result["default"] = mod; 417 | return result; 418 | }; 419 | Object.defineProperty(exports, "__esModule", ({ value: true })); 420 | const tr = __importStar(__nccwpck_require__(159)); 421 | /** 422 | * Exec a command. 423 | * Output will be streamed to the live console. 424 | * Returns promise with return code 425 | * 426 | * @param commandLine command to execute (can include additional args). Must be correctly escaped. 427 | * @param args optional arguments for tool. Escaping is handled by the lib. 428 | * @param options optional exec options. See ExecOptions 429 | * @returns Promise exit code 430 | */ 431 | function exec(commandLine, args, options) { 432 | return __awaiter(this, void 0, void 0, function* () { 433 | const commandArgs = tr.argStringToArray(commandLine); 434 | if (commandArgs.length === 0) { 435 | throw new Error(`Parameter 'commandLine' cannot be null or empty.`); 436 | } 437 | // Path to tool to execute should be first arg 438 | const toolPath = commandArgs[0]; 439 | args = commandArgs.slice(1).concat(args || []); 440 | const runner = new tr.ToolRunner(toolPath, args, options); 441 | return runner.exec(); 442 | }); 443 | } 444 | exports.exec = exec; 445 | //# sourceMappingURL=exec.js.map 446 | 447 | /***/ }), 448 | 449 | /***/ 159: 450 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 451 | 452 | "use strict"; 453 | 454 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 455 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 456 | return new (P || (P = Promise))(function (resolve, reject) { 457 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 458 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 459 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 460 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 461 | }); 462 | }; 463 | var __importStar = (this && this.__importStar) || function (mod) { 464 | if (mod && mod.__esModule) return mod; 465 | var result = {}; 466 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 467 | result["default"] = mod; 468 | return result; 469 | }; 470 | Object.defineProperty(exports, "__esModule", ({ value: true })); 471 | const os = __importStar(__nccwpck_require__(87)); 472 | const events = __importStar(__nccwpck_require__(614)); 473 | const child = __importStar(__nccwpck_require__(129)); 474 | const path = __importStar(__nccwpck_require__(622)); 475 | const io = __importStar(__nccwpck_require__(436)); 476 | const ioUtil = __importStar(__nccwpck_require__(962)); 477 | /* eslint-disable @typescript-eslint/unbound-method */ 478 | const IS_WINDOWS = process.platform === 'win32'; 479 | /* 480 | * Class for running command line tools. Handles quoting and arg parsing in a platform agnostic way. 481 | */ 482 | class ToolRunner extends events.EventEmitter { 483 | constructor(toolPath, args, options) { 484 | super(); 485 | if (!toolPath) { 486 | throw new Error("Parameter 'toolPath' cannot be null or empty."); 487 | } 488 | this.toolPath = toolPath; 489 | this.args = args || []; 490 | this.options = options || {}; 491 | } 492 | _debug(message) { 493 | if (this.options.listeners && this.options.listeners.debug) { 494 | this.options.listeners.debug(message); 495 | } 496 | } 497 | _getCommandString(options, noPrefix) { 498 | const toolPath = this._getSpawnFileName(); 499 | const args = this._getSpawnArgs(options); 500 | let cmd = noPrefix ? '' : '[command]'; // omit prefix when piped to a second tool 501 | if (IS_WINDOWS) { 502 | // Windows + cmd file 503 | if (this._isCmdFile()) { 504 | cmd += toolPath; 505 | for (const a of args) { 506 | cmd += ` ${a}`; 507 | } 508 | } 509 | // Windows + verbatim 510 | else if (options.windowsVerbatimArguments) { 511 | cmd += `"${toolPath}"`; 512 | for (const a of args) { 513 | cmd += ` ${a}`; 514 | } 515 | } 516 | // Windows (regular) 517 | else { 518 | cmd += this._windowsQuoteCmdArg(toolPath); 519 | for (const a of args) { 520 | cmd += ` ${this._windowsQuoteCmdArg(a)}`; 521 | } 522 | } 523 | } 524 | else { 525 | // OSX/Linux - this can likely be improved with some form of quoting. 526 | // creating processes on Unix is fundamentally different than Windows. 527 | // on Unix, execvp() takes an arg array. 528 | cmd += toolPath; 529 | for (const a of args) { 530 | cmd += ` ${a}`; 531 | } 532 | } 533 | return cmd; 534 | } 535 | _processLineBuffer(data, strBuffer, onLine) { 536 | try { 537 | let s = strBuffer + data.toString(); 538 | let n = s.indexOf(os.EOL); 539 | while (n > -1) { 540 | const line = s.substring(0, n); 541 | onLine(line); 542 | // the rest of the string ... 543 | s = s.substring(n + os.EOL.length); 544 | n = s.indexOf(os.EOL); 545 | } 546 | strBuffer = s; 547 | } 548 | catch (err) { 549 | // streaming lines to console is best effort. Don't fail a build. 550 | this._debug(`error processing line. Failed with error ${err}`); 551 | } 552 | } 553 | _getSpawnFileName() { 554 | if (IS_WINDOWS) { 555 | if (this._isCmdFile()) { 556 | return process.env['COMSPEC'] || 'cmd.exe'; 557 | } 558 | } 559 | return this.toolPath; 560 | } 561 | _getSpawnArgs(options) { 562 | if (IS_WINDOWS) { 563 | if (this._isCmdFile()) { 564 | let argline = `/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`; 565 | for (const a of this.args) { 566 | argline += ' '; 567 | argline += options.windowsVerbatimArguments 568 | ? a 569 | : this._windowsQuoteCmdArg(a); 570 | } 571 | argline += '"'; 572 | return [argline]; 573 | } 574 | } 575 | return this.args; 576 | } 577 | _endsWith(str, end) { 578 | return str.endsWith(end); 579 | } 580 | _isCmdFile() { 581 | const upperToolPath = this.toolPath.toUpperCase(); 582 | return (this._endsWith(upperToolPath, '.CMD') || 583 | this._endsWith(upperToolPath, '.BAT')); 584 | } 585 | _windowsQuoteCmdArg(arg) { 586 | // for .exe, apply the normal quoting rules that libuv applies 587 | if (!this._isCmdFile()) { 588 | return this._uvQuoteCmdArg(arg); 589 | } 590 | // otherwise apply quoting rules specific to the cmd.exe command line parser. 591 | // the libuv rules are generic and are not designed specifically for cmd.exe 592 | // command line parser. 593 | // 594 | // for a detailed description of the cmd.exe command line parser, refer to 595 | // http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912 596 | // need quotes for empty arg 597 | if (!arg) { 598 | return '""'; 599 | } 600 | // determine whether the arg needs to be quoted 601 | const cmdSpecialChars = [ 602 | ' ', 603 | '\t', 604 | '&', 605 | '(', 606 | ')', 607 | '[', 608 | ']', 609 | '{', 610 | '}', 611 | '^', 612 | '=', 613 | ';', 614 | '!', 615 | "'", 616 | '+', 617 | ',', 618 | '`', 619 | '~', 620 | '|', 621 | '<', 622 | '>', 623 | '"' 624 | ]; 625 | let needsQuotes = false; 626 | for (const char of arg) { 627 | if (cmdSpecialChars.some(x => x === char)) { 628 | needsQuotes = true; 629 | break; 630 | } 631 | } 632 | // short-circuit if quotes not needed 633 | if (!needsQuotes) { 634 | return arg; 635 | } 636 | // the following quoting rules are very similar to the rules that by libuv applies. 637 | // 638 | // 1) wrap the string in quotes 639 | // 640 | // 2) double-up quotes - i.e. " => "" 641 | // 642 | // this is different from the libuv quoting rules. libuv replaces " with \", which unfortunately 643 | // doesn't work well with a cmd.exe command line. 644 | // 645 | // note, replacing " with "" also works well if the arg is passed to a downstream .NET console app. 646 | // for example, the command line: 647 | // foo.exe "myarg:""my val""" 648 | // is parsed by a .NET console app into an arg array: 649 | // [ "myarg:\"my val\"" ] 650 | // which is the same end result when applying libuv quoting rules. although the actual 651 | // command line from libuv quoting rules would look like: 652 | // foo.exe "myarg:\"my val\"" 653 | // 654 | // 3) double-up slashes that precede a quote, 655 | // e.g. hello \world => "hello \world" 656 | // hello\"world => "hello\\""world" 657 | // hello\\"world => "hello\\\\""world" 658 | // hello world\ => "hello world\\" 659 | // 660 | // technically this is not required for a cmd.exe command line, or the batch argument parser. 661 | // the reasons for including this as a .cmd quoting rule are: 662 | // 663 | // a) this is optimized for the scenario where the argument is passed from the .cmd file to an 664 | // external program. many programs (e.g. .NET console apps) rely on the slash-doubling rule. 665 | // 666 | // b) it's what we've been doing previously (by deferring to node default behavior) and we 667 | // haven't heard any complaints about that aspect. 668 | // 669 | // note, a weakness of the quoting rules chosen here, is that % is not escaped. in fact, % cannot be 670 | // escaped when used on the command line directly - even though within a .cmd file % can be escaped 671 | // by using %%. 672 | // 673 | // the saving grace is, on the command line, %var% is left as-is if var is not defined. this contrasts 674 | // the line parsing rules within a .cmd file, where if var is not defined it is replaced with nothing. 675 | // 676 | // one option that was explored was replacing % with ^% - i.e. %var% => ^%var^%. this hack would 677 | // often work, since it is unlikely that var^ would exist, and the ^ character is removed when the 678 | // variable is used. the problem, however, is that ^ is not removed when %* is used to pass the args 679 | // to an external program. 680 | // 681 | // an unexplored potential solution for the % escaping problem, is to create a wrapper .cmd file. 682 | // % can be escaped within a .cmd file. 683 | let reverse = '"'; 684 | let quoteHit = true; 685 | for (let i = arg.length; i > 0; i--) { 686 | // walk the string in reverse 687 | reverse += arg[i - 1]; 688 | if (quoteHit && arg[i - 1] === '\\') { 689 | reverse += '\\'; // double the slash 690 | } 691 | else if (arg[i - 1] === '"') { 692 | quoteHit = true; 693 | reverse += '"'; // double the quote 694 | } 695 | else { 696 | quoteHit = false; 697 | } 698 | } 699 | reverse += '"'; 700 | return reverse 701 | .split('') 702 | .reverse() 703 | .join(''); 704 | } 705 | _uvQuoteCmdArg(arg) { 706 | // Tool runner wraps child_process.spawn() and needs to apply the same quoting as 707 | // Node in certain cases where the undocumented spawn option windowsVerbatimArguments 708 | // is used. 709 | // 710 | // Since this function is a port of quote_cmd_arg from Node 4.x (technically, lib UV, 711 | // see https://github.com/nodejs/node/blob/v4.x/deps/uv/src/win/process.c for details), 712 | // pasting copyright notice from Node within this function: 713 | // 714 | // Copyright Joyent, Inc. and other Node contributors. All rights reserved. 715 | // 716 | // Permission is hereby granted, free of charge, to any person obtaining a copy 717 | // of this software and associated documentation files (the "Software"), to 718 | // deal in the Software without restriction, including without limitation the 719 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 720 | // sell copies of the Software, and to permit persons to whom the Software is 721 | // furnished to do so, subject to the following conditions: 722 | // 723 | // The above copyright notice and this permission notice shall be included in 724 | // all copies or substantial portions of the Software. 725 | // 726 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 727 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 728 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 729 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 730 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 731 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 732 | // IN THE SOFTWARE. 733 | if (!arg) { 734 | // Need double quotation for empty argument 735 | return '""'; 736 | } 737 | if (!arg.includes(' ') && !arg.includes('\t') && !arg.includes('"')) { 738 | // No quotation needed 739 | return arg; 740 | } 741 | if (!arg.includes('"') && !arg.includes('\\')) { 742 | // No embedded double quotes or backslashes, so I can just wrap 743 | // quote marks around the whole thing. 744 | return `"${arg}"`; 745 | } 746 | // Expected input/output: 747 | // input : hello"world 748 | // output: "hello\"world" 749 | // input : hello""world 750 | // output: "hello\"\"world" 751 | // input : hello\world 752 | // output: hello\world 753 | // input : hello\\world 754 | // output: hello\\world 755 | // input : hello\"world 756 | // output: "hello\\\"world" 757 | // input : hello\\"world 758 | // output: "hello\\\\\"world" 759 | // input : hello world\ 760 | // output: "hello world\\" - note the comment in libuv actually reads "hello world\" 761 | // but it appears the comment is wrong, it should be "hello world\\" 762 | let reverse = '"'; 763 | let quoteHit = true; 764 | for (let i = arg.length; i > 0; i--) { 765 | // walk the string in reverse 766 | reverse += arg[i - 1]; 767 | if (quoteHit && arg[i - 1] === '\\') { 768 | reverse += '\\'; 769 | } 770 | else if (arg[i - 1] === '"') { 771 | quoteHit = true; 772 | reverse += '\\'; 773 | } 774 | else { 775 | quoteHit = false; 776 | } 777 | } 778 | reverse += '"'; 779 | return reverse 780 | .split('') 781 | .reverse() 782 | .join(''); 783 | } 784 | _cloneExecOptions(options) { 785 | options = options || {}; 786 | const result = { 787 | cwd: options.cwd || process.cwd(), 788 | env: options.env || process.env, 789 | silent: options.silent || false, 790 | windowsVerbatimArguments: options.windowsVerbatimArguments || false, 791 | failOnStdErr: options.failOnStdErr || false, 792 | ignoreReturnCode: options.ignoreReturnCode || false, 793 | delay: options.delay || 10000 794 | }; 795 | result.outStream = options.outStream || process.stdout; 796 | result.errStream = options.errStream || process.stderr; 797 | return result; 798 | } 799 | _getSpawnOptions(options, toolPath) { 800 | options = options || {}; 801 | const result = {}; 802 | result.cwd = options.cwd; 803 | result.env = options.env; 804 | result['windowsVerbatimArguments'] = 805 | options.windowsVerbatimArguments || this._isCmdFile(); 806 | if (options.windowsVerbatimArguments) { 807 | result.argv0 = `"${toolPath}"`; 808 | } 809 | return result; 810 | } 811 | /** 812 | * Exec a tool. 813 | * Output will be streamed to the live console. 814 | * Returns promise with return code 815 | * 816 | * @param tool path to tool to exec 817 | * @param options optional exec options. See ExecOptions 818 | * @returns number 819 | */ 820 | exec() { 821 | return __awaiter(this, void 0, void 0, function* () { 822 | // root the tool path if it is unrooted and contains relative pathing 823 | if (!ioUtil.isRooted(this.toolPath) && 824 | (this.toolPath.includes('/') || 825 | (IS_WINDOWS && this.toolPath.includes('\\')))) { 826 | // prefer options.cwd if it is specified, however options.cwd may also need to be rooted 827 | this.toolPath = path.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); 828 | } 829 | // if the tool is only a file name, then resolve it from the PATH 830 | // otherwise verify it exists (add extension on Windows if necessary) 831 | this.toolPath = yield io.which(this.toolPath, true); 832 | return new Promise((resolve, reject) => { 833 | this._debug(`exec tool: ${this.toolPath}`); 834 | this._debug('arguments:'); 835 | for (const arg of this.args) { 836 | this._debug(` ${arg}`); 837 | } 838 | const optionsNonNull = this._cloneExecOptions(this.options); 839 | if (!optionsNonNull.silent && optionsNonNull.outStream) { 840 | optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL); 841 | } 842 | const state = new ExecState(optionsNonNull, this.toolPath); 843 | state.on('debug', (message) => { 844 | this._debug(message); 845 | }); 846 | const fileName = this._getSpawnFileName(); 847 | const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName)); 848 | const stdbuffer = ''; 849 | if (cp.stdout) { 850 | cp.stdout.on('data', (data) => { 851 | if (this.options.listeners && this.options.listeners.stdout) { 852 | this.options.listeners.stdout(data); 853 | } 854 | if (!optionsNonNull.silent && optionsNonNull.outStream) { 855 | optionsNonNull.outStream.write(data); 856 | } 857 | this._processLineBuffer(data, stdbuffer, (line) => { 858 | if (this.options.listeners && this.options.listeners.stdline) { 859 | this.options.listeners.stdline(line); 860 | } 861 | }); 862 | }); 863 | } 864 | const errbuffer = ''; 865 | if (cp.stderr) { 866 | cp.stderr.on('data', (data) => { 867 | state.processStderr = true; 868 | if (this.options.listeners && this.options.listeners.stderr) { 869 | this.options.listeners.stderr(data); 870 | } 871 | if (!optionsNonNull.silent && 872 | optionsNonNull.errStream && 873 | optionsNonNull.outStream) { 874 | const s = optionsNonNull.failOnStdErr 875 | ? optionsNonNull.errStream 876 | : optionsNonNull.outStream; 877 | s.write(data); 878 | } 879 | this._processLineBuffer(data, errbuffer, (line) => { 880 | if (this.options.listeners && this.options.listeners.errline) { 881 | this.options.listeners.errline(line); 882 | } 883 | }); 884 | }); 885 | } 886 | cp.on('error', (err) => { 887 | state.processError = err.message; 888 | state.processExited = true; 889 | state.processClosed = true; 890 | state.CheckComplete(); 891 | }); 892 | cp.on('exit', (code) => { 893 | state.processExitCode = code; 894 | state.processExited = true; 895 | this._debug(`Exit code ${code} received from tool '${this.toolPath}'`); 896 | state.CheckComplete(); 897 | }); 898 | cp.on('close', (code) => { 899 | state.processExitCode = code; 900 | state.processExited = true; 901 | state.processClosed = true; 902 | this._debug(`STDIO streams have closed for tool '${this.toolPath}'`); 903 | state.CheckComplete(); 904 | }); 905 | state.on('done', (error, exitCode) => { 906 | if (stdbuffer.length > 0) { 907 | this.emit('stdline', stdbuffer); 908 | } 909 | if (errbuffer.length > 0) { 910 | this.emit('errline', errbuffer); 911 | } 912 | cp.removeAllListeners(); 913 | if (error) { 914 | reject(error); 915 | } 916 | else { 917 | resolve(exitCode); 918 | } 919 | }); 920 | if (this.options.input) { 921 | if (!cp.stdin) { 922 | throw new Error('child process missing stdin'); 923 | } 924 | cp.stdin.end(this.options.input); 925 | } 926 | }); 927 | }); 928 | } 929 | } 930 | exports.ToolRunner = ToolRunner; 931 | /** 932 | * Convert an arg string to an array of args. Handles escaping 933 | * 934 | * @param argString string of arguments 935 | * @returns string[] array of arguments 936 | */ 937 | function argStringToArray(argString) { 938 | const args = []; 939 | let inQuotes = false; 940 | let escaped = false; 941 | let arg = ''; 942 | function append(c) { 943 | // we only escape double quotes. 944 | if (escaped && c !== '"') { 945 | arg += '\\'; 946 | } 947 | arg += c; 948 | escaped = false; 949 | } 950 | for (let i = 0; i < argString.length; i++) { 951 | const c = argString.charAt(i); 952 | if (c === '"') { 953 | if (!escaped) { 954 | inQuotes = !inQuotes; 955 | } 956 | else { 957 | append(c); 958 | } 959 | continue; 960 | } 961 | if (c === '\\' && escaped) { 962 | append(c); 963 | continue; 964 | } 965 | if (c === '\\' && inQuotes) { 966 | escaped = true; 967 | continue; 968 | } 969 | if (c === ' ' && !inQuotes) { 970 | if (arg.length > 0) { 971 | args.push(arg); 972 | arg = ''; 973 | } 974 | continue; 975 | } 976 | append(c); 977 | } 978 | if (arg.length > 0) { 979 | args.push(arg.trim()); 980 | } 981 | return args; 982 | } 983 | exports.argStringToArray = argStringToArray; 984 | class ExecState extends events.EventEmitter { 985 | constructor(options, toolPath) { 986 | super(); 987 | this.processClosed = false; // tracks whether the process has exited and stdio is closed 988 | this.processError = ''; 989 | this.processExitCode = 0; 990 | this.processExited = false; // tracks whether the process has exited 991 | this.processStderr = false; // tracks whether stderr was written to 992 | this.delay = 10000; // 10 seconds 993 | this.done = false; 994 | this.timeout = null; 995 | if (!toolPath) { 996 | throw new Error('toolPath must not be empty'); 997 | } 998 | this.options = options; 999 | this.toolPath = toolPath; 1000 | if (options.delay) { 1001 | this.delay = options.delay; 1002 | } 1003 | } 1004 | CheckComplete() { 1005 | if (this.done) { 1006 | return; 1007 | } 1008 | if (this.processClosed) { 1009 | this._setResult(); 1010 | } 1011 | else if (this.processExited) { 1012 | this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this); 1013 | } 1014 | } 1015 | _debug(message) { 1016 | this.emit('debug', message); 1017 | } 1018 | _setResult() { 1019 | // determine whether there is an error 1020 | let error; 1021 | if (this.processExited) { 1022 | if (this.processError) { 1023 | error = new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`); 1024 | } 1025 | else if (this.processExitCode !== 0 && !this.options.ignoreReturnCode) { 1026 | error = new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`); 1027 | } 1028 | else if (this.processStderr && this.options.failOnStdErr) { 1029 | error = new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`); 1030 | } 1031 | } 1032 | // clear the timeout 1033 | if (this.timeout) { 1034 | clearTimeout(this.timeout); 1035 | this.timeout = null; 1036 | } 1037 | this.done = true; 1038 | this.emit('done', error, this.processExitCode); 1039 | } 1040 | static HandleTimeout(state) { 1041 | if (state.done) { 1042 | return; 1043 | } 1044 | if (!state.processClosed && state.processExited) { 1045 | const message = `The STDIO streams did not close within ${state.delay / 1046 | 1000} seconds of the exit event from process '${state.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`; 1047 | state._debug(message); 1048 | } 1049 | state._setResult(); 1050 | } 1051 | } 1052 | //# sourceMappingURL=toolrunner.js.map 1053 | 1054 | /***/ }), 1055 | 1056 | /***/ 962: 1057 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 1058 | 1059 | "use strict"; 1060 | 1061 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1062 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1063 | return new (P || (P = Promise))(function (resolve, reject) { 1064 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1065 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1066 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1067 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1068 | }); 1069 | }; 1070 | var _a; 1071 | Object.defineProperty(exports, "__esModule", ({ value: true })); 1072 | const assert_1 = __nccwpck_require__(357); 1073 | const fs = __nccwpck_require__(747); 1074 | const path = __nccwpck_require__(622); 1075 | _a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; 1076 | exports.IS_WINDOWS = process.platform === 'win32'; 1077 | function exists(fsPath) { 1078 | return __awaiter(this, void 0, void 0, function* () { 1079 | try { 1080 | yield exports.stat(fsPath); 1081 | } 1082 | catch (err) { 1083 | if (err.code === 'ENOENT') { 1084 | return false; 1085 | } 1086 | throw err; 1087 | } 1088 | return true; 1089 | }); 1090 | } 1091 | exports.exists = exists; 1092 | function isDirectory(fsPath, useStat = false) { 1093 | return __awaiter(this, void 0, void 0, function* () { 1094 | const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath); 1095 | return stats.isDirectory(); 1096 | }); 1097 | } 1098 | exports.isDirectory = isDirectory; 1099 | /** 1100 | * On OSX/Linux, true if path starts with '/'. On Windows, true for paths like: 1101 | * \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases). 1102 | */ 1103 | function isRooted(p) { 1104 | p = normalizeSeparators(p); 1105 | if (!p) { 1106 | throw new Error('isRooted() parameter "p" cannot be empty'); 1107 | } 1108 | if (exports.IS_WINDOWS) { 1109 | return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello 1110 | ); // e.g. C: or C:\hello 1111 | } 1112 | return p.startsWith('/'); 1113 | } 1114 | exports.isRooted = isRooted; 1115 | /** 1116 | * Recursively create a directory at `fsPath`. 1117 | * 1118 | * This implementation is optimistic, meaning it attempts to create the full 1119 | * path first, and backs up the path stack from there. 1120 | * 1121 | * @param fsPath The path to create 1122 | * @param maxDepth The maximum recursion depth 1123 | * @param depth The current recursion depth 1124 | */ 1125 | function mkdirP(fsPath, maxDepth = 1000, depth = 1) { 1126 | return __awaiter(this, void 0, void 0, function* () { 1127 | assert_1.ok(fsPath, 'a path argument must be provided'); 1128 | fsPath = path.resolve(fsPath); 1129 | if (depth >= maxDepth) 1130 | return exports.mkdir(fsPath); 1131 | try { 1132 | yield exports.mkdir(fsPath); 1133 | return; 1134 | } 1135 | catch (err) { 1136 | switch (err.code) { 1137 | case 'ENOENT': { 1138 | yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1); 1139 | yield exports.mkdir(fsPath); 1140 | return; 1141 | } 1142 | default: { 1143 | let stats; 1144 | try { 1145 | stats = yield exports.stat(fsPath); 1146 | } 1147 | catch (err2) { 1148 | throw err; 1149 | } 1150 | if (!stats.isDirectory()) 1151 | throw err; 1152 | } 1153 | } 1154 | } 1155 | }); 1156 | } 1157 | exports.mkdirP = mkdirP; 1158 | /** 1159 | * Best effort attempt to determine whether a file exists and is executable. 1160 | * @param filePath file path to check 1161 | * @param extensions additional file extensions to try 1162 | * @return if file exists and is executable, returns the file path. otherwise empty string. 1163 | */ 1164 | function tryGetExecutablePath(filePath, extensions) { 1165 | return __awaiter(this, void 0, void 0, function* () { 1166 | let stats = undefined; 1167 | try { 1168 | // test file exists 1169 | stats = yield exports.stat(filePath); 1170 | } 1171 | catch (err) { 1172 | if (err.code !== 'ENOENT') { 1173 | // eslint-disable-next-line no-console 1174 | console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); 1175 | } 1176 | } 1177 | if (stats && stats.isFile()) { 1178 | if (exports.IS_WINDOWS) { 1179 | // on Windows, test for valid extension 1180 | const upperExt = path.extname(filePath).toUpperCase(); 1181 | if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) { 1182 | return filePath; 1183 | } 1184 | } 1185 | else { 1186 | if (isUnixExecutable(stats)) { 1187 | return filePath; 1188 | } 1189 | } 1190 | } 1191 | // try each extension 1192 | const originalFilePath = filePath; 1193 | for (const extension of extensions) { 1194 | filePath = originalFilePath + extension; 1195 | stats = undefined; 1196 | try { 1197 | stats = yield exports.stat(filePath); 1198 | } 1199 | catch (err) { 1200 | if (err.code !== 'ENOENT') { 1201 | // eslint-disable-next-line no-console 1202 | console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); 1203 | } 1204 | } 1205 | if (stats && stats.isFile()) { 1206 | if (exports.IS_WINDOWS) { 1207 | // preserve the case of the actual file (since an extension was appended) 1208 | try { 1209 | const directory = path.dirname(filePath); 1210 | const upperName = path.basename(filePath).toUpperCase(); 1211 | for (const actualName of yield exports.readdir(directory)) { 1212 | if (upperName === actualName.toUpperCase()) { 1213 | filePath = path.join(directory, actualName); 1214 | break; 1215 | } 1216 | } 1217 | } 1218 | catch (err) { 1219 | // eslint-disable-next-line no-console 1220 | console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`); 1221 | } 1222 | return filePath; 1223 | } 1224 | else { 1225 | if (isUnixExecutable(stats)) { 1226 | return filePath; 1227 | } 1228 | } 1229 | } 1230 | } 1231 | return ''; 1232 | }); 1233 | } 1234 | exports.tryGetExecutablePath = tryGetExecutablePath; 1235 | function normalizeSeparators(p) { 1236 | p = p || ''; 1237 | if (exports.IS_WINDOWS) { 1238 | // convert slashes on Windows 1239 | p = p.replace(/\//g, '\\'); 1240 | // remove redundant slashes 1241 | return p.replace(/\\\\+/g, '\\'); 1242 | } 1243 | // remove redundant slashes 1244 | return p.replace(/\/\/+/g, '/'); 1245 | } 1246 | // on Mac/Linux, test the execute bit 1247 | // R W X R W X R W X 1248 | // 256 128 64 32 16 8 4 2 1 1249 | function isUnixExecutable(stats) { 1250 | return ((stats.mode & 1) > 0 || 1251 | ((stats.mode & 8) > 0 && stats.gid === process.getgid()) || 1252 | ((stats.mode & 64) > 0 && stats.uid === process.getuid())); 1253 | } 1254 | //# sourceMappingURL=io-util.js.map 1255 | 1256 | /***/ }), 1257 | 1258 | /***/ 436: 1259 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 1260 | 1261 | "use strict"; 1262 | 1263 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1264 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1265 | return new (P || (P = Promise))(function (resolve, reject) { 1266 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1267 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1268 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1269 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1270 | }); 1271 | }; 1272 | Object.defineProperty(exports, "__esModule", ({ value: true })); 1273 | const childProcess = __nccwpck_require__(129); 1274 | const path = __nccwpck_require__(622); 1275 | const util_1 = __nccwpck_require__(669); 1276 | const ioUtil = __nccwpck_require__(962); 1277 | const exec = util_1.promisify(childProcess.exec); 1278 | /** 1279 | * Copies a file or folder. 1280 | * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js 1281 | * 1282 | * @param source source path 1283 | * @param dest destination path 1284 | * @param options optional. See CopyOptions. 1285 | */ 1286 | function cp(source, dest, options = {}) { 1287 | return __awaiter(this, void 0, void 0, function* () { 1288 | const { force, recursive } = readCopyOptions(options); 1289 | const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null; 1290 | // Dest is an existing file, but not forcing 1291 | if (destStat && destStat.isFile() && !force) { 1292 | return; 1293 | } 1294 | // If dest is an existing directory, should copy inside. 1295 | const newDest = destStat && destStat.isDirectory() 1296 | ? path.join(dest, path.basename(source)) 1297 | : dest; 1298 | if (!(yield ioUtil.exists(source))) { 1299 | throw new Error(`no such file or directory: ${source}`); 1300 | } 1301 | const sourceStat = yield ioUtil.stat(source); 1302 | if (sourceStat.isDirectory()) { 1303 | if (!recursive) { 1304 | throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`); 1305 | } 1306 | else { 1307 | yield cpDirRecursive(source, newDest, 0, force); 1308 | } 1309 | } 1310 | else { 1311 | if (path.relative(source, newDest) === '') { 1312 | // a file cannot be copied to itself 1313 | throw new Error(`'${newDest}' and '${source}' are the same file`); 1314 | } 1315 | yield copyFile(source, newDest, force); 1316 | } 1317 | }); 1318 | } 1319 | exports.cp = cp; 1320 | /** 1321 | * Moves a path. 1322 | * 1323 | * @param source source path 1324 | * @param dest destination path 1325 | * @param options optional. See MoveOptions. 1326 | */ 1327 | function mv(source, dest, options = {}) { 1328 | return __awaiter(this, void 0, void 0, function* () { 1329 | if (yield ioUtil.exists(dest)) { 1330 | let destExists = true; 1331 | if (yield ioUtil.isDirectory(dest)) { 1332 | // If dest is directory copy src into dest 1333 | dest = path.join(dest, path.basename(source)); 1334 | destExists = yield ioUtil.exists(dest); 1335 | } 1336 | if (destExists) { 1337 | if (options.force == null || options.force) { 1338 | yield rmRF(dest); 1339 | } 1340 | else { 1341 | throw new Error('Destination already exists'); 1342 | } 1343 | } 1344 | } 1345 | yield mkdirP(path.dirname(dest)); 1346 | yield ioUtil.rename(source, dest); 1347 | }); 1348 | } 1349 | exports.mv = mv; 1350 | /** 1351 | * Remove a path recursively with force 1352 | * 1353 | * @param inputPath path to remove 1354 | */ 1355 | function rmRF(inputPath) { 1356 | return __awaiter(this, void 0, void 0, function* () { 1357 | if (ioUtil.IS_WINDOWS) { 1358 | // Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another 1359 | // program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del. 1360 | try { 1361 | if (yield ioUtil.isDirectory(inputPath, true)) { 1362 | yield exec(`rd /s /q "${inputPath}"`); 1363 | } 1364 | else { 1365 | yield exec(`del /f /a "${inputPath}"`); 1366 | } 1367 | } 1368 | catch (err) { 1369 | // if you try to delete a file that doesn't exist, desired result is achieved 1370 | // other errors are valid 1371 | if (err.code !== 'ENOENT') 1372 | throw err; 1373 | } 1374 | // Shelling out fails to remove a symlink folder with missing source, this unlink catches that 1375 | try { 1376 | yield ioUtil.unlink(inputPath); 1377 | } 1378 | catch (err) { 1379 | // if you try to delete a file that doesn't exist, desired result is achieved 1380 | // other errors are valid 1381 | if (err.code !== 'ENOENT') 1382 | throw err; 1383 | } 1384 | } 1385 | else { 1386 | let isDir = false; 1387 | try { 1388 | isDir = yield ioUtil.isDirectory(inputPath); 1389 | } 1390 | catch (err) { 1391 | // if you try to delete a file that doesn't exist, desired result is achieved 1392 | // other errors are valid 1393 | if (err.code !== 'ENOENT') 1394 | throw err; 1395 | return; 1396 | } 1397 | if (isDir) { 1398 | yield exec(`rm -rf "${inputPath}"`); 1399 | } 1400 | else { 1401 | yield ioUtil.unlink(inputPath); 1402 | } 1403 | } 1404 | }); 1405 | } 1406 | exports.rmRF = rmRF; 1407 | /** 1408 | * Make a directory. Creates the full path with folders in between 1409 | * Will throw if it fails 1410 | * 1411 | * @param fsPath path to create 1412 | * @returns Promise 1413 | */ 1414 | function mkdirP(fsPath) { 1415 | return __awaiter(this, void 0, void 0, function* () { 1416 | yield ioUtil.mkdirP(fsPath); 1417 | }); 1418 | } 1419 | exports.mkdirP = mkdirP; 1420 | /** 1421 | * Returns path of a tool had the tool actually been invoked. Resolves via paths. 1422 | * If you check and the tool does not exist, it will throw. 1423 | * 1424 | * @param tool name of the tool 1425 | * @param check whether to check if tool exists 1426 | * @returns Promise path to tool 1427 | */ 1428 | function which(tool, check) { 1429 | return __awaiter(this, void 0, void 0, function* () { 1430 | if (!tool) { 1431 | throw new Error("parameter 'tool' is required"); 1432 | } 1433 | // recursive when check=true 1434 | if (check) { 1435 | const result = yield which(tool, false); 1436 | if (!result) { 1437 | if (ioUtil.IS_WINDOWS) { 1438 | throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`); 1439 | } 1440 | else { 1441 | throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`); 1442 | } 1443 | } 1444 | } 1445 | try { 1446 | // build the list of extensions to try 1447 | const extensions = []; 1448 | if (ioUtil.IS_WINDOWS && process.env.PATHEXT) { 1449 | for (const extension of process.env.PATHEXT.split(path.delimiter)) { 1450 | if (extension) { 1451 | extensions.push(extension); 1452 | } 1453 | } 1454 | } 1455 | // if it's rooted, return it if exists. otherwise return empty. 1456 | if (ioUtil.isRooted(tool)) { 1457 | const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions); 1458 | if (filePath) { 1459 | return filePath; 1460 | } 1461 | return ''; 1462 | } 1463 | // if any path separators, return empty 1464 | if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) { 1465 | return ''; 1466 | } 1467 | // build the list of directories 1468 | // 1469 | // Note, technically "where" checks the current directory on Windows. From a toolkit perspective, 1470 | // it feels like we should not do this. Checking the current directory seems like more of a use 1471 | // case of a shell, and the which() function exposed by the toolkit should strive for consistency 1472 | // across platforms. 1473 | const directories = []; 1474 | if (process.env.PATH) { 1475 | for (const p of process.env.PATH.split(path.delimiter)) { 1476 | if (p) { 1477 | directories.push(p); 1478 | } 1479 | } 1480 | } 1481 | // return the first match 1482 | for (const directory of directories) { 1483 | const filePath = yield ioUtil.tryGetExecutablePath(directory + path.sep + tool, extensions); 1484 | if (filePath) { 1485 | return filePath; 1486 | } 1487 | } 1488 | return ''; 1489 | } 1490 | catch (err) { 1491 | throw new Error(`which failed with message ${err.message}`); 1492 | } 1493 | }); 1494 | } 1495 | exports.which = which; 1496 | function readCopyOptions(options) { 1497 | const force = options.force == null ? true : options.force; 1498 | const recursive = Boolean(options.recursive); 1499 | return { force, recursive }; 1500 | } 1501 | function cpDirRecursive(sourceDir, destDir, currentDepth, force) { 1502 | return __awaiter(this, void 0, void 0, function* () { 1503 | // Ensure there is not a run away recursive copy 1504 | if (currentDepth >= 255) 1505 | return; 1506 | currentDepth++; 1507 | yield mkdirP(destDir); 1508 | const files = yield ioUtil.readdir(sourceDir); 1509 | for (const fileName of files) { 1510 | const srcFile = `${sourceDir}/${fileName}`; 1511 | const destFile = `${destDir}/${fileName}`; 1512 | const srcFileStat = yield ioUtil.lstat(srcFile); 1513 | if (srcFileStat.isDirectory()) { 1514 | // Recurse 1515 | yield cpDirRecursive(srcFile, destFile, currentDepth, force); 1516 | } 1517 | else { 1518 | yield copyFile(srcFile, destFile, force); 1519 | } 1520 | } 1521 | // Change the mode for the newly created directory 1522 | yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode); 1523 | }); 1524 | } 1525 | // Buffered file copy 1526 | function copyFile(srcFile, destFile, force) { 1527 | return __awaiter(this, void 0, void 0, function* () { 1528 | if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) { 1529 | // unlink/re-link it 1530 | try { 1531 | yield ioUtil.lstat(destFile); 1532 | yield ioUtil.unlink(destFile); 1533 | } 1534 | catch (e) { 1535 | // Try to override file permission 1536 | if (e.code === 'EPERM') { 1537 | yield ioUtil.chmod(destFile, '0666'); 1538 | yield ioUtil.unlink(destFile); 1539 | } 1540 | // other errors = it doesn't exist, no work to do 1541 | } 1542 | // Copy over symlink 1543 | const symlinkFull = yield ioUtil.readlink(srcFile); 1544 | yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null); 1545 | } 1546 | else if (!(yield ioUtil.exists(destFile)) || force) { 1547 | yield ioUtil.copyFile(srcFile, destFile); 1548 | } 1549 | }); 1550 | } 1551 | //# sourceMappingURL=io.js.map 1552 | 1553 | /***/ }), 1554 | 1555 | /***/ 88: 1556 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 1557 | 1558 | const debug = __nccwpck_require__(427) 1559 | const { MAX_LENGTH, MAX_SAFE_INTEGER } = __nccwpck_require__(293) 1560 | const { re, t } = __nccwpck_require__(523) 1561 | 1562 | const parseOptions = __nccwpck_require__(785) 1563 | const { compareIdentifiers } = __nccwpck_require__(463) 1564 | class SemVer { 1565 | constructor (version, options) { 1566 | options = parseOptions(options) 1567 | 1568 | if (version instanceof SemVer) { 1569 | if (version.loose === !!options.loose && 1570 | version.includePrerelease === !!options.includePrerelease) { 1571 | return version 1572 | } else { 1573 | version = version.version 1574 | } 1575 | } else if (typeof version !== 'string') { 1576 | throw new TypeError(`Invalid Version: ${version}`) 1577 | } 1578 | 1579 | if (version.length > MAX_LENGTH) { 1580 | throw new TypeError( 1581 | `version is longer than ${MAX_LENGTH} characters` 1582 | ) 1583 | } 1584 | 1585 | debug('SemVer', version, options) 1586 | this.options = options 1587 | this.loose = !!options.loose 1588 | // this isn't actually relevant for versions, but keep it so that we 1589 | // don't run into trouble passing this.options around. 1590 | this.includePrerelease = !!options.includePrerelease 1591 | 1592 | const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]) 1593 | 1594 | if (!m) { 1595 | throw new TypeError(`Invalid Version: ${version}`) 1596 | } 1597 | 1598 | this.raw = version 1599 | 1600 | // these are actually numbers 1601 | this.major = +m[1] 1602 | this.minor = +m[2] 1603 | this.patch = +m[3] 1604 | 1605 | if (this.major > MAX_SAFE_INTEGER || this.major < 0) { 1606 | throw new TypeError('Invalid major version') 1607 | } 1608 | 1609 | if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { 1610 | throw new TypeError('Invalid minor version') 1611 | } 1612 | 1613 | if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { 1614 | throw new TypeError('Invalid patch version') 1615 | } 1616 | 1617 | // numberify any prerelease numeric ids 1618 | if (!m[4]) { 1619 | this.prerelease = [] 1620 | } else { 1621 | this.prerelease = m[4].split('.').map((id) => { 1622 | if (/^[0-9]+$/.test(id)) { 1623 | const num = +id 1624 | if (num >= 0 && num < MAX_SAFE_INTEGER) { 1625 | return num 1626 | } 1627 | } 1628 | return id 1629 | }) 1630 | } 1631 | 1632 | this.build = m[5] ? m[5].split('.') : [] 1633 | this.format() 1634 | } 1635 | 1636 | format () { 1637 | this.version = `${this.major}.${this.minor}.${this.patch}` 1638 | if (this.prerelease.length) { 1639 | this.version += `-${this.prerelease.join('.')}` 1640 | } 1641 | return this.version 1642 | } 1643 | 1644 | toString () { 1645 | return this.version 1646 | } 1647 | 1648 | compare (other) { 1649 | debug('SemVer.compare', this.version, this.options, other) 1650 | if (!(other instanceof SemVer)) { 1651 | if (typeof other === 'string' && other === this.version) { 1652 | return 0 1653 | } 1654 | other = new SemVer(other, this.options) 1655 | } 1656 | 1657 | if (other.version === this.version) { 1658 | return 0 1659 | } 1660 | 1661 | return this.compareMain(other) || this.comparePre(other) 1662 | } 1663 | 1664 | compareMain (other) { 1665 | if (!(other instanceof SemVer)) { 1666 | other = new SemVer(other, this.options) 1667 | } 1668 | 1669 | return ( 1670 | compareIdentifiers(this.major, other.major) || 1671 | compareIdentifiers(this.minor, other.minor) || 1672 | compareIdentifiers(this.patch, other.patch) 1673 | ) 1674 | } 1675 | 1676 | comparePre (other) { 1677 | if (!(other instanceof SemVer)) { 1678 | other = new SemVer(other, this.options) 1679 | } 1680 | 1681 | // NOT having a prerelease is > having one 1682 | if (this.prerelease.length && !other.prerelease.length) { 1683 | return -1 1684 | } else if (!this.prerelease.length && other.prerelease.length) { 1685 | return 1 1686 | } else if (!this.prerelease.length && !other.prerelease.length) { 1687 | return 0 1688 | } 1689 | 1690 | let i = 0 1691 | do { 1692 | const a = this.prerelease[i] 1693 | const b = other.prerelease[i] 1694 | debug('prerelease compare', i, a, b) 1695 | if (a === undefined && b === undefined) { 1696 | return 0 1697 | } else if (b === undefined) { 1698 | return 1 1699 | } else if (a === undefined) { 1700 | return -1 1701 | } else if (a === b) { 1702 | continue 1703 | } else { 1704 | return compareIdentifiers(a, b) 1705 | } 1706 | } while (++i) 1707 | } 1708 | 1709 | compareBuild (other) { 1710 | if (!(other instanceof SemVer)) { 1711 | other = new SemVer(other, this.options) 1712 | } 1713 | 1714 | let i = 0 1715 | do { 1716 | const a = this.build[i] 1717 | const b = other.build[i] 1718 | debug('prerelease compare', i, a, b) 1719 | if (a === undefined && b === undefined) { 1720 | return 0 1721 | } else if (b === undefined) { 1722 | return 1 1723 | } else if (a === undefined) { 1724 | return -1 1725 | } else if (a === b) { 1726 | continue 1727 | } else { 1728 | return compareIdentifiers(a, b) 1729 | } 1730 | } while (++i) 1731 | } 1732 | 1733 | // preminor will bump the version up to the next minor release, and immediately 1734 | // down to pre-release. premajor and prepatch work the same way. 1735 | inc (release, identifier) { 1736 | switch (release) { 1737 | case 'premajor': 1738 | this.prerelease.length = 0 1739 | this.patch = 0 1740 | this.minor = 0 1741 | this.major++ 1742 | this.inc('pre', identifier) 1743 | break 1744 | case 'preminor': 1745 | this.prerelease.length = 0 1746 | this.patch = 0 1747 | this.minor++ 1748 | this.inc('pre', identifier) 1749 | break 1750 | case 'prepatch': 1751 | // If this is already a prerelease, it will bump to the next version 1752 | // drop any prereleases that might already exist, since they are not 1753 | // relevant at this point. 1754 | this.prerelease.length = 0 1755 | this.inc('patch', identifier) 1756 | this.inc('pre', identifier) 1757 | break 1758 | // If the input is a non-prerelease version, this acts the same as 1759 | // prepatch. 1760 | case 'prerelease': 1761 | if (this.prerelease.length === 0) { 1762 | this.inc('patch', identifier) 1763 | } 1764 | this.inc('pre', identifier) 1765 | break 1766 | 1767 | case 'major': 1768 | // If this is a pre-major version, bump up to the same major version. 1769 | // Otherwise increment major. 1770 | // 1.0.0-5 bumps to 1.0.0 1771 | // 1.1.0 bumps to 2.0.0 1772 | if ( 1773 | this.minor !== 0 || 1774 | this.patch !== 0 || 1775 | this.prerelease.length === 0 1776 | ) { 1777 | this.major++ 1778 | } 1779 | this.minor = 0 1780 | this.patch = 0 1781 | this.prerelease = [] 1782 | break 1783 | case 'minor': 1784 | // If this is a pre-minor version, bump up to the same minor version. 1785 | // Otherwise increment minor. 1786 | // 1.2.0-5 bumps to 1.2.0 1787 | // 1.2.1 bumps to 1.3.0 1788 | if (this.patch !== 0 || this.prerelease.length === 0) { 1789 | this.minor++ 1790 | } 1791 | this.patch = 0 1792 | this.prerelease = [] 1793 | break 1794 | case 'patch': 1795 | // If this is not a pre-release version, it will increment the patch. 1796 | // If it is a pre-release it will bump up to the same patch version. 1797 | // 1.2.0-5 patches to 1.2.0 1798 | // 1.2.0 patches to 1.2.1 1799 | if (this.prerelease.length === 0) { 1800 | this.patch++ 1801 | } 1802 | this.prerelease = [] 1803 | break 1804 | // This probably shouldn't be used publicly. 1805 | // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction. 1806 | case 'pre': 1807 | if (this.prerelease.length === 0) { 1808 | this.prerelease = [0] 1809 | } else { 1810 | let i = this.prerelease.length 1811 | while (--i >= 0) { 1812 | if (typeof this.prerelease[i] === 'number') { 1813 | this.prerelease[i]++ 1814 | i = -2 1815 | } 1816 | } 1817 | if (i === -1) { 1818 | // didn't increment anything 1819 | this.prerelease.push(0) 1820 | } 1821 | } 1822 | if (identifier) { 1823 | // 1.2.0-beta.1 bumps to 1.2.0-beta.2, 1824 | // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 1825 | if (this.prerelease[0] === identifier) { 1826 | if (isNaN(this.prerelease[1])) { 1827 | this.prerelease = [identifier, 0] 1828 | } 1829 | } else { 1830 | this.prerelease = [identifier, 0] 1831 | } 1832 | } 1833 | break 1834 | 1835 | default: 1836 | throw new Error(`invalid increment argument: ${release}`) 1837 | } 1838 | this.format() 1839 | this.raw = this.version 1840 | return this 1841 | } 1842 | } 1843 | 1844 | module.exports = SemVer 1845 | 1846 | 1847 | /***/ }), 1848 | 1849 | /***/ 466: 1850 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 1851 | 1852 | const SemVer = __nccwpck_require__(88) 1853 | const parse = __nccwpck_require__(925) 1854 | const {re, t} = __nccwpck_require__(523) 1855 | 1856 | const coerce = (version, options) => { 1857 | if (version instanceof SemVer) { 1858 | return version 1859 | } 1860 | 1861 | if (typeof version === 'number') { 1862 | version = String(version) 1863 | } 1864 | 1865 | if (typeof version !== 'string') { 1866 | return null 1867 | } 1868 | 1869 | options = options || {} 1870 | 1871 | let match = null 1872 | if (!options.rtl) { 1873 | match = version.match(re[t.COERCE]) 1874 | } else { 1875 | // Find the right-most coercible string that does not share 1876 | // a terminus with a more left-ward coercible string. 1877 | // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' 1878 | // 1879 | // Walk through the string checking with a /g regexp 1880 | // Manually set the index so as to pick up overlapping matches. 1881 | // Stop when we get a match that ends at the string end, since no 1882 | // coercible string can be more right-ward without the same terminus. 1883 | let next 1884 | while ((next = re[t.COERCERTL].exec(version)) && 1885 | (!match || match.index + match[0].length !== version.length) 1886 | ) { 1887 | if (!match || 1888 | next.index + next[0].length !== match.index + match[0].length) { 1889 | match = next 1890 | } 1891 | re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length 1892 | } 1893 | // leave it in a clean state 1894 | re[t.COERCERTL].lastIndex = -1 1895 | } 1896 | 1897 | if (match === null) 1898 | return null 1899 | 1900 | return parse(`${match[2]}.${match[3] || '0'}.${match[4] || '0'}`, options) 1901 | } 1902 | module.exports = coerce 1903 | 1904 | 1905 | /***/ }), 1906 | 1907 | /***/ 688: 1908 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 1909 | 1910 | const SemVer = __nccwpck_require__(88) 1911 | const major = (a, loose) => new SemVer(a, loose).major 1912 | module.exports = major 1913 | 1914 | 1915 | /***/ }), 1916 | 1917 | /***/ 925: 1918 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 1919 | 1920 | const {MAX_LENGTH} = __nccwpck_require__(293) 1921 | const { re, t } = __nccwpck_require__(523) 1922 | const SemVer = __nccwpck_require__(88) 1923 | 1924 | const parseOptions = __nccwpck_require__(785) 1925 | const parse = (version, options) => { 1926 | options = parseOptions(options) 1927 | 1928 | if (version instanceof SemVer) { 1929 | return version 1930 | } 1931 | 1932 | if (typeof version !== 'string') { 1933 | return null 1934 | } 1935 | 1936 | if (version.length > MAX_LENGTH) { 1937 | return null 1938 | } 1939 | 1940 | const r = options.loose ? re[t.LOOSE] : re[t.FULL] 1941 | if (!r.test(version)) { 1942 | return null 1943 | } 1944 | 1945 | try { 1946 | return new SemVer(version, options) 1947 | } catch (er) { 1948 | return null 1949 | } 1950 | } 1951 | 1952 | module.exports = parse 1953 | 1954 | 1955 | /***/ }), 1956 | 1957 | /***/ 293: 1958 | /***/ ((module) => { 1959 | 1960 | // Note: this is the semver.org version of the spec that it implements 1961 | // Not necessarily the package version of this code. 1962 | const SEMVER_SPEC_VERSION = '2.0.0' 1963 | 1964 | const MAX_LENGTH = 256 1965 | const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 1966 | /* istanbul ignore next */ 9007199254740991 1967 | 1968 | // Max safe segment length for coercion. 1969 | const MAX_SAFE_COMPONENT_LENGTH = 16 1970 | 1971 | module.exports = { 1972 | SEMVER_SPEC_VERSION, 1973 | MAX_LENGTH, 1974 | MAX_SAFE_INTEGER, 1975 | MAX_SAFE_COMPONENT_LENGTH 1976 | } 1977 | 1978 | 1979 | /***/ }), 1980 | 1981 | /***/ 427: 1982 | /***/ ((module) => { 1983 | 1984 | const debug = ( 1985 | typeof process === 'object' && 1986 | process.env && 1987 | process.env.NODE_DEBUG && 1988 | /\bsemver\b/i.test(process.env.NODE_DEBUG) 1989 | ) ? (...args) => console.error('SEMVER', ...args) 1990 | : () => {} 1991 | 1992 | module.exports = debug 1993 | 1994 | 1995 | /***/ }), 1996 | 1997 | /***/ 463: 1998 | /***/ ((module) => { 1999 | 2000 | const numeric = /^[0-9]+$/ 2001 | const compareIdentifiers = (a, b) => { 2002 | const anum = numeric.test(a) 2003 | const bnum = numeric.test(b) 2004 | 2005 | if (anum && bnum) { 2006 | a = +a 2007 | b = +b 2008 | } 2009 | 2010 | return a === b ? 0 2011 | : (anum && !bnum) ? -1 2012 | : (bnum && !anum) ? 1 2013 | : a < b ? -1 2014 | : 1 2015 | } 2016 | 2017 | const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a) 2018 | 2019 | module.exports = { 2020 | compareIdentifiers, 2021 | rcompareIdentifiers 2022 | } 2023 | 2024 | 2025 | /***/ }), 2026 | 2027 | /***/ 785: 2028 | /***/ ((module) => { 2029 | 2030 | // parse out just the options we care about so we always get a consistent 2031 | // obj with keys in a consistent order. 2032 | const opts = ['includePrerelease', 'loose', 'rtl'] 2033 | const parseOptions = options => 2034 | !options ? {} 2035 | : typeof options !== 'object' ? { loose: true } 2036 | : opts.filter(k => options[k]).reduce((options, k) => { 2037 | options[k] = true 2038 | return options 2039 | }, {}) 2040 | module.exports = parseOptions 2041 | 2042 | 2043 | /***/ }), 2044 | 2045 | /***/ 523: 2046 | /***/ ((module, exports, __nccwpck_require__) => { 2047 | 2048 | const { MAX_SAFE_COMPONENT_LENGTH } = __nccwpck_require__(293) 2049 | const debug = __nccwpck_require__(427) 2050 | exports = module.exports = {} 2051 | 2052 | // The actual regexps go on exports.re 2053 | const re = exports.re = [] 2054 | const src = exports.src = [] 2055 | const t = exports.t = {} 2056 | let R = 0 2057 | 2058 | const createToken = (name, value, isGlobal) => { 2059 | const index = R++ 2060 | debug(index, value) 2061 | t[name] = index 2062 | src[index] = value 2063 | re[index] = new RegExp(value, isGlobal ? 'g' : undefined) 2064 | } 2065 | 2066 | // The following Regular Expressions can be used for tokenizing, 2067 | // validating, and parsing SemVer version strings. 2068 | 2069 | // ## Numeric Identifier 2070 | // A single `0`, or a non-zero digit followed by zero or more digits. 2071 | 2072 | createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') 2073 | createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+') 2074 | 2075 | // ## Non-numeric Identifier 2076 | // Zero or more digits, followed by a letter or hyphen, and then zero or 2077 | // more letters, digits, or hyphens. 2078 | 2079 | createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*') 2080 | 2081 | // ## Main Version 2082 | // Three dot-separated numeric identifiers. 2083 | 2084 | createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` + 2085 | `(${src[t.NUMERICIDENTIFIER]})\\.` + 2086 | `(${src[t.NUMERICIDENTIFIER]})`) 2087 | 2088 | createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + 2089 | `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + 2090 | `(${src[t.NUMERICIDENTIFIERLOOSE]})`) 2091 | 2092 | // ## Pre-release Version Identifier 2093 | // A numeric identifier, or a non-numeric identifier. 2094 | 2095 | createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER] 2096 | }|${src[t.NONNUMERICIDENTIFIER]})`) 2097 | 2098 | createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE] 2099 | }|${src[t.NONNUMERICIDENTIFIER]})`) 2100 | 2101 | // ## Pre-release Version 2102 | // Hyphen, followed by one or more dot-separated pre-release version 2103 | // identifiers. 2104 | 2105 | createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER] 2106 | }(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`) 2107 | 2108 | createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] 2109 | }(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`) 2110 | 2111 | // ## Build Metadata Identifier 2112 | // Any combination of digits, letters, or hyphens. 2113 | 2114 | createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+') 2115 | 2116 | // ## Build Metadata 2117 | // Plus sign, followed by one or more period-separated build metadata 2118 | // identifiers. 2119 | 2120 | createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER] 2121 | }(?:\\.${src[t.BUILDIDENTIFIER]})*))`) 2122 | 2123 | // ## Full Version String 2124 | // A main version, followed optionally by a pre-release version and 2125 | // build metadata. 2126 | 2127 | // Note that the only major, minor, patch, and pre-release sections of 2128 | // the version string are capturing groups. The build metadata is not a 2129 | // capturing group, because it should not ever be used in version 2130 | // comparison. 2131 | 2132 | createToken('FULLPLAIN', `v?${src[t.MAINVERSION] 2133 | }${src[t.PRERELEASE]}?${ 2134 | src[t.BUILD]}?`) 2135 | 2136 | createToken('FULL', `^${src[t.FULLPLAIN]}$`) 2137 | 2138 | // like full, but allows v1.2.3 and =1.2.3, which people do sometimes. 2139 | // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty 2140 | // common in the npm registry. 2141 | createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE] 2142 | }${src[t.PRERELEASELOOSE]}?${ 2143 | src[t.BUILD]}?`) 2144 | 2145 | createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`) 2146 | 2147 | createToken('GTLT', '((?:<|>)?=?)') 2148 | 2149 | // Something like "2.*" or "1.2.x". 2150 | // Note that "x.x" is a valid xRange identifer, meaning "any version" 2151 | // Only the first item is strictly required. 2152 | createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`) 2153 | createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`) 2154 | 2155 | createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` + 2156 | `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + 2157 | `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + 2158 | `(?:${src[t.PRERELEASE]})?${ 2159 | src[t.BUILD]}?` + 2160 | `)?)?`) 2161 | 2162 | createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` + 2163 | `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + 2164 | `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + 2165 | `(?:${src[t.PRERELEASELOOSE]})?${ 2166 | src[t.BUILD]}?` + 2167 | `)?)?`) 2168 | 2169 | createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`) 2170 | createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) 2171 | 2172 | // Coercion. 2173 | // Extract anything that could conceivably be a part of a valid semver 2174 | createToken('COERCE', `${'(^|[^\\d])' + 2175 | '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + 2176 | `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + 2177 | `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + 2178 | `(?:$|[^\\d])`) 2179 | createToken('COERCERTL', src[t.COERCE], true) 2180 | 2181 | // Tilde ranges. 2182 | // Meaning is "reasonably at or greater than" 2183 | createToken('LONETILDE', '(?:~>?)') 2184 | 2185 | createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true) 2186 | exports.tildeTrimReplace = '$1~' 2187 | 2188 | createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`) 2189 | createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`) 2190 | 2191 | // Caret ranges. 2192 | // Meaning is "at least and backwards compatible with" 2193 | createToken('LONECARET', '(?:\\^)') 2194 | 2195 | createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true) 2196 | exports.caretTrimReplace = '$1^' 2197 | 2198 | createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`) 2199 | createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`) 2200 | 2201 | // A simple gt/lt/eq thing, or just "" to indicate "any version" 2202 | createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`) 2203 | createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`) 2204 | 2205 | // An expression to strip any whitespace between the gtlt and the thing 2206 | // it modifies, so that `> 1.2.3` ==> `>1.2.3` 2207 | createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT] 2208 | }\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true) 2209 | exports.comparatorTrimReplace = '$1$2$3' 2210 | 2211 | // Something like `1.2.3 - 1.2.4` 2212 | // Note that these all use the loose form, because they'll be 2213 | // checked against either the strict or loose comparator form 2214 | // later. 2215 | createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` + 2216 | `\\s+-\\s+` + 2217 | `(${src[t.XRANGEPLAIN]})` + 2218 | `\\s*$`) 2219 | 2220 | createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` + 2221 | `\\s+-\\s+` + 2222 | `(${src[t.XRANGEPLAINLOOSE]})` + 2223 | `\\s*$`) 2224 | 2225 | // Star ranges basically just allow anything at all. 2226 | createToken('STAR', '(<|>)?=?\\s*\\*') 2227 | // >=0.0.0 is like a star 2228 | createToken('GTE0', '^\\s*>=\\s*0\.0\.0\\s*$') 2229 | createToken('GTE0PRE', '^\\s*>=\\s*0\.0\.0-0\\s*$') 2230 | 2231 | 2232 | /***/ }), 2233 | 2234 | /***/ 351: 2235 | /***/ ((__unused_webpack_module, __unused_webpack_exports, __nccwpck_require__) => { 2236 | 2237 | const core = __nccwpck_require__(186); 2238 | const exec = __nccwpck_require__(514); 2239 | const utils = __nccwpck_require__ (608) 2240 | 2241 | async function doScript() { 2242 | // taken from actions/checkout 2243 | let githubWorkspacePath = process.env['GITHUB_WORKSPACE'] 2244 | if (!githubWorkspacePath) { 2245 | throw new Error('GITHUB_WORKSPACE not defined') 2246 | } 2247 | githubWorkspacePath = utils.resolvePath(githubWorkspacePath) 2248 | 2249 | const drupalVersion = core.getInput('version', { 2250 | required: true, 2251 | }); 2252 | const drupalPath = utils.resolvePath(core.getInput('path') || '~/drupal'); 2253 | const extraDependencies = core.getInput('dependencies') 2254 | const allowPlugins = utils.stringToArray(core.getInput('allow_plugins')) 2255 | 2256 | await exec.exec('composer', [ 2257 | 'create-project', 2258 | `drupal/recommended-project:${drupalVersion}`, 2259 | drupalPath, 2260 | '--no-interaction' 2261 | ]); 2262 | 2263 | const commands = [ 2264 | ['config', 'minimum-stability', 'dev'], 2265 | ['config', 'prefer-stable', 'true'], 2266 | ['config', 'preferred-install', 'dist'], 2267 | ['require', '--dev', `drupal/core-dev:${drupalVersion}`], 2268 | ['config', 'repositories.0', `{"type": "path", "url": "${githubWorkspacePath}", "options": {"symlink": false}}`], 2269 | ['config', 'repositories.1', 'composer', 'https://packages.drupal.org/8'], 2270 | ]; 2271 | 2272 | if (utils.getMajorVersionFromConstraint(drupalVersion) === 8) { 2273 | commands.push(['config', '--no-plugins', 'allow-plugins.drupal/core-composer-scaffold', 'true']); 2274 | commands.push(['config', '--no-plugins', 'allow-plugins.drupal/core-project-message', 'true']); 2275 | } 2276 | commands.push(['config', '--no-plugins', 'allow-plugins.composer/installers', 'true']); 2277 | commands.push(['config', '--no-plugins', 'allow-plugins.dealerdirect/phpcodesniffer-composer-installer', 'true']); 2278 | commands.push(['config', '--no-plugins', 'allow-plugins.phpstan/extension-installer', 'true']); 2279 | 2280 | allowPlugins.forEach(package => { 2281 | commands.push(['config', '--no-plugins', 'allow-plugins.' + package, 'true']); 2282 | }); 2283 | 2284 | if (utils.getMajorVersionFromConstraint(drupalVersion) > 8) { 2285 | commands.push(['require', '--dev', '--with-all-dependencies', 'phpspec/prophecy-phpunit:^2']); 2286 | } 2287 | 2288 | if (extraDependencies) { 2289 | commands.push(['require', extraDependencies]); 2290 | } 2291 | 2292 | for (command of commands) { 2293 | core.debug(`Executing: composer ${command}`) 2294 | await exec.exec('composer', command, { 2295 | cwd: drupalPath, 2296 | }); 2297 | } 2298 | } 2299 | 2300 | doScript().catch(error => core.setFailed(error.message)); 2301 | 2302 | 2303 | /***/ }), 2304 | 2305 | /***/ 608: 2306 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 2307 | 2308 | const path = __nccwpck_require__(622); 2309 | const semverMajor = __nccwpck_require__(688) 2310 | const smeverCoerce = __nccwpck_require__(466); 2311 | const { access } = __nccwpck_require__(747); 2312 | 2313 | function resolvePath(filepath) { 2314 | if (filepath[0] === '~') { 2315 | return path.join(process.env.HOME, filepath.slice(1)); 2316 | } 2317 | return path.resolve(filepath) 2318 | } 2319 | 2320 | function getMajorVersionFromConstraint(constraint) { 2321 | return semverMajor(smeverCoerce(constraint)) 2322 | } 2323 | function stringToArray(string) { 2324 | return string.split(/\r?\n/).reduce( 2325 | (acc, line) => 2326 | acc 2327 | .concat(line.split(",")) 2328 | .filter(pat => pat) 2329 | .map(pat => pat.trim()), 2330 | [] 2331 | ); 2332 | } 2333 | 2334 | module.exports = { 2335 | resolvePath, 2336 | getMajorVersionFromConstraint, 2337 | stringToArray 2338 | } 2339 | 2340 | 2341 | /***/ }), 2342 | 2343 | /***/ 357: 2344 | /***/ ((module) => { 2345 | 2346 | "use strict"; 2347 | module.exports = require("assert");; 2348 | 2349 | /***/ }), 2350 | 2351 | /***/ 129: 2352 | /***/ ((module) => { 2353 | 2354 | "use strict"; 2355 | module.exports = require("child_process");; 2356 | 2357 | /***/ }), 2358 | 2359 | /***/ 614: 2360 | /***/ ((module) => { 2361 | 2362 | "use strict"; 2363 | module.exports = require("events");; 2364 | 2365 | /***/ }), 2366 | 2367 | /***/ 747: 2368 | /***/ ((module) => { 2369 | 2370 | "use strict"; 2371 | module.exports = require("fs");; 2372 | 2373 | /***/ }), 2374 | 2375 | /***/ 87: 2376 | /***/ ((module) => { 2377 | 2378 | "use strict"; 2379 | module.exports = require("os");; 2380 | 2381 | /***/ }), 2382 | 2383 | /***/ 622: 2384 | /***/ ((module) => { 2385 | 2386 | "use strict"; 2387 | module.exports = require("path");; 2388 | 2389 | /***/ }), 2390 | 2391 | /***/ 669: 2392 | /***/ ((module) => { 2393 | 2394 | "use strict"; 2395 | module.exports = require("util");; 2396 | 2397 | /***/ }) 2398 | 2399 | /******/ }); 2400 | /************************************************************************/ 2401 | /******/ // The module cache 2402 | /******/ var __webpack_module_cache__ = {}; 2403 | /******/ 2404 | /******/ // The require function 2405 | /******/ function __nccwpck_require__(moduleId) { 2406 | /******/ // Check if module is in cache 2407 | /******/ if(__webpack_module_cache__[moduleId]) { 2408 | /******/ return __webpack_module_cache__[moduleId].exports; 2409 | /******/ } 2410 | /******/ // Create a new module (and put it into the cache) 2411 | /******/ var module = __webpack_module_cache__[moduleId] = { 2412 | /******/ // no module.id needed 2413 | /******/ // no module.loaded needed 2414 | /******/ exports: {} 2415 | /******/ }; 2416 | /******/ 2417 | /******/ // Execute the module function 2418 | /******/ var threw = true; 2419 | /******/ try { 2420 | /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); 2421 | /******/ threw = false; 2422 | /******/ } finally { 2423 | /******/ if(threw) delete __webpack_module_cache__[moduleId]; 2424 | /******/ } 2425 | /******/ 2426 | /******/ // Return the exports of the module 2427 | /******/ return module.exports; 2428 | /******/ } 2429 | /******/ 2430 | /************************************************************************/ 2431 | /******/ /* webpack/runtime/compat */ 2432 | /******/ 2433 | /******/ __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ 2434 | /******/ // module exports must be returned from runtime so entry inlining is disabled 2435 | /******/ // startup 2436 | /******/ // Load entry module and return exports 2437 | /******/ return __nccwpck_require__(351); 2438 | /******/ })() 2439 | ; -------------------------------------------------------------------------------- /dist/licenses.txt: -------------------------------------------------------------------------------- 1 | @actions/core 2 | MIT 3 | The MIT License (MIT) 4 | 5 | Copyright 2019 GitHub 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | @actions/exec 14 | MIT 15 | 16 | @actions/io 17 | MIT 18 | 19 | semver 20 | ISC 21 | The ISC License 22 | 23 | Copyright (c) Isaac Z. Schlueter and Contributors 24 | 25 | Permission to use, copy, modify, and/or distribute this software for any 26 | purpose with or without fee is hereby granted, provided that the above 27 | copyright notice and this permission notice appear in all copies. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 30 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 31 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 32 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 33 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 34 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 35 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "setup-drupal", 3 | "version": "1.0.0", 4 | "description": "GitHub Action to setup Drupal for testing an extension", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "jest", 8 | "build": "ncc build src/index.js --license licenses.txt && git add dist/", 9 | "prepare": "husky install", 10 | "debug:run": "npm run build && act -P ubuntu-latest=shivammathur/node:latest --job run" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/bluehorndigital/setup-drupal.git" 15 | }, 16 | "keywords": [ 17 | "actions", 18 | "drupal", 19 | "setup" 20 | ], 21 | "author": "Bluehorn Digital ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/bluehorndigital/setup-drupal/issues" 25 | }, 26 | "homepage": "https://github.com/bluehorndigital/setup-drupal#readme", 27 | "dependencies": { 28 | "@actions/core": "^1.2.6", 29 | "@actions/exec": "^1.1.1", 30 | "@actions/github": "^6.0.0", 31 | "semver": "^7.6.0" 32 | }, 33 | "devDependencies": { 34 | "@vercel/ncc": "^0.27.0", 35 | "husky": "^5.1.3", 36 | "jest": "^26.6.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const exec = require('@actions/exec'); 3 | const utils = require ('./utils') 4 | 5 | async function doScript() { 6 | // taken from actions/checkout 7 | let githubWorkspacePath = process.env['GITHUB_WORKSPACE'] 8 | if (!githubWorkspacePath) { 9 | throw new Error('GITHUB_WORKSPACE not defined') 10 | } 11 | githubWorkspacePath = utils.resolvePath(githubWorkspacePath) 12 | 13 | const drupalVersion = core.getInput('version', { 14 | required: true, 15 | }); 16 | const drupalPath = utils.resolvePath(core.getInput('path') || '~/drupal'); 17 | const extraDependencies = core.getInput('dependencies') 18 | const allowPlugins = utils.stringToArray(core.getInput('allow_plugins')) 19 | 20 | await exec.exec('composer', [ 21 | 'create-project', 22 | `drupal/recommended-project:${drupalVersion}`, 23 | drupalPath, 24 | '--no-interaction' 25 | ]); 26 | 27 | const commands = [ 28 | ['config', 'minimum-stability', 'dev'], 29 | ['config', 'prefer-stable', 'true'], 30 | ['config', 'preferred-install', 'dist'], 31 | ['require', '--dev', `drupal/core-dev:${drupalVersion}`], 32 | ['config', 'repositories.0', `{"type": "path", "url": "${githubWorkspacePath}", "options": {"symlink": false}}`], 33 | ['config', 'repositories.1', 'composer', 'https://packages.drupal.org/8'], 34 | ]; 35 | 36 | if (utils.getMajorVersionFromConstraint(drupalVersion) === 8) { 37 | commands.push(['config', '--no-plugins', 'allow-plugins.drupal/core-composer-scaffold', 'true']); 38 | commands.push(['config', '--no-plugins', 'allow-plugins.drupal/core-project-message', 'true']); 39 | } 40 | commands.push(['config', '--no-plugins', 'allow-plugins.composer/installers', 'true']); 41 | commands.push(['config', '--no-plugins', 'allow-plugins.dealerdirect/phpcodesniffer-composer-installer', 'true']); 42 | commands.push(['config', '--no-plugins', 'allow-plugins.phpstan/extension-installer', 'true']); 43 | 44 | allowPlugins.forEach(package => { 45 | commands.push(['config', '--no-plugins', 'allow-plugins.' + package, 'true']); 46 | }); 47 | 48 | if (utils.getMajorVersionFromConstraint(drupalVersion) > 8) { 49 | commands.push(['require', '--dev', '--with-all-dependencies', 'phpspec/prophecy-phpunit:^2']); 50 | } 51 | 52 | if (extraDependencies) { 53 | commands.push(['require', extraDependencies]); 54 | } 55 | 56 | for (command of commands) { 57 | core.debug(`Executing: composer ${command}`) 58 | await exec.exec('composer', command, { 59 | cwd: drupalPath, 60 | }); 61 | } 62 | } 63 | 64 | doScript().catch(error => core.setFailed(error.message)); 65 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const semverMajor = require('semver/functions/major') 3 | const smeverCoerce = require('semver/functions/coerce'); 4 | const { access } = require('fs'); 5 | 6 | function resolvePath(filepath) { 7 | if (filepath[0] === '~') { 8 | return path.join(process.env.HOME, filepath.slice(1)); 9 | } 10 | return path.resolve(filepath) 11 | } 12 | 13 | function getMajorVersionFromConstraint(constraint) { 14 | return semverMajor(smeverCoerce(constraint)) 15 | } 16 | function stringToArray(string) { 17 | return string.split(/\r?\n/).reduce( 18 | (acc, line) => 19 | acc 20 | .concat(line.split(",")) 21 | .filter(pat => pat) 22 | .map(pat => pat.trim()), 23 | [] 24 | ); 25 | } 26 | 27 | module.exports = { 28 | resolvePath, 29 | getMajorVersionFromConstraint, 30 | stringToArray 31 | } 32 | --------------------------------------------------------------------------------