├── static └── example.png ├── .github └── dependabot.yml ├── action.yml ├── package.json ├── LICENSE ├── README.md ├── .gitignore ├── index.js └── dist ├── licenses.txt └── index.js /static/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guyarb/golang-test-annotations/HEAD/static/example.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: 'npm' 9 | directory: '/' 10 | schedule: 11 | interval: 'weekly' 12 | reviewers: 13 | - "guyarb" 14 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Golang Test Annotations" 2 | description: "Given a test output of go test, the failed tests will be annotated." 3 | inputs: 4 | test-results: # Path of the test results 5 | description: "The path of the go test results" 6 | required: true 7 | default: "test.json" 8 | package-name: 9 | required: false 10 | description: "Package name override" 11 | default: 12 | working-directory: 13 | description: "The path of the go module" 14 | required: false 15 | default: 16 | runs: 17 | using: "node20" 18 | main: "dist/index.js" 19 | branding: 20 | icon: "check" 21 | color: "green" 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "golang-test-annoations", 3 | "version": "1.0.0", 4 | "description": "A github action which annotates failed tests.", 5 | "main": "index.js", 6 | "scripts": { 7 | "run": "node index.js", 8 | "build": "ncc build index.js --license licenses.txt", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/guyarb/golang-test-annoations.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/guyarb/golang-test-annoations/issues" 20 | }, 21 | "homepage": "https://github.com/guyarb/golang-test-annoations#readme", 22 | "dependencies": { 23 | "@actions/core": "^1.6.0", 24 | "@vercel/ncc": "^0.36.1", 25 | "line-by-line": "^0.1.6" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Guy Arbitman 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 | # golang-test-annotations 2 | A github action which annotates failed tests. 3 | 4 | ![GitHub Annotations](./static/example.png) 5 | 6 | An example run can be found [here](https://github.com/guyarb/golang-test-annotations-example/actions/runs/505258482) 7 | 8 | ## How to use 9 | 10 | Add to your workflow the following contents: 11 | 12 | ```yaml 13 | name: pr 14 | 15 | on: 16 | pull_request: 17 | branches: [ '**' ] 18 | workflow_dispatch: 19 | branches: [ '**' ] 20 | 21 | jobs: 22 | full_ci: 23 | strategy: 24 | matrix: 25 | go_version: [ 1.18.x ] 26 | 27 | runs-on: ubuntu-20.04 28 | 29 | steps: 30 | - name: checkout 31 | uses: actions/checkout@v2 32 | 33 | - name: Set up Go 34 | uses: actions/setup-go@v3 35 | with: 36 | go-version: ${{ matrix.go_version }} 37 | 38 | - name: run tests 39 | run: go test -json ./... > test.json 40 | 41 | - name: Annotate tests 42 | if: always() 43 | uses: guyarb/golang-test-annotations@v0.5.1 44 | with: 45 | test-results: test.json 46 | package-name: foobar # optional, if using custom package name, github.com/owner/repo stripped from the pathname by default 47 | ``` 48 | 49 | ## Development of this action 50 | 51 | 1. Fork this repo. 52 | 2. Create a branch with your feature/bugfix. 53 | 3. Open a PR to me. 54 | 55 | ## Issues 56 | Please open issues for any bug or suggestion you have. 57 | -------------------------------------------------------------------------------- /.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 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | #dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | .idea/ 107 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const lineReader = require('line-by-line'); 3 | const fs = require('fs'); 4 | 5 | 6 | try { 7 | const regex = /(\s*[\w\d]+_test.go:\d+:)(.*?)(Test:\s+Test[\w\d]*?\S+)/gu; // Extracts only the failure from the logs (including whitespace) 8 | 9 | const testResultsPath = core.getInput('test-results'); 10 | const customPackageName = core.getInput('package-name'); 11 | const workingDirectory = core.getInput('working-directory'); 12 | 13 | if (!fs.existsSync(testResultsPath)) { 14 | core.warning( 15 | `No file was found with the provided path: ${testResultsPath}.` 16 | ) 17 | return 18 | } 19 | 20 | let obj = {}; 21 | let lr = new lineReader(testResultsPath); 22 | lr.on('line', function (line) { 23 | const currentLine = JSON.parse(line); 24 | const testName = currentLine.Test; 25 | if (typeof testName === "undefined") { 26 | return; 27 | } 28 | 29 | let output = currentLine.Output; 30 | if (typeof output === "undefined") { 31 | return; 32 | } 33 | output = output.replace("\n", "%0A").replace("\r", "%0D") 34 | // Strip github.com/owner/repo package from the path by default 35 | let packageName = currentLine.Package.split("/").slice(3).join("/"); 36 | // If custom package is provided, strip custom package name from the path 37 | if (customPackageName !== "") { 38 | if (!currentLine.Package.startsWith(customPackageName)) { 39 | core.warning( 40 | `Expected ${currentLine.Package} to start with ${customPackageName} since "package-name" was provided.` 41 | ) 42 | } else { 43 | packageName = currentLine.Package.replace(customPackageName + "/", "") 44 | } 45 | } 46 | if (workingDirectory !== "") { 47 | packageName = workingDirectory + "/" + packageName 48 | } 49 | let newEntry = packageName + "/" + testName; 50 | if (!obj.hasOwnProperty(newEntry)) { 51 | obj[newEntry] = output; 52 | } else { 53 | obj[newEntry] += output; 54 | } 55 | }); 56 | lr.on('end', function () { 57 | for (const [key, value] of Object.entries(obj)) { 58 | if (value.includes("FAIL") && value.includes("_test.go")) { 59 | var result; 60 | while ((result = regex.exec(value)) !== null) { 61 | const parts = result[0].split(":"); 62 | const file = key.split("/").slice(0, -2).join("/") + "/" + parts[0].trimStart(); 63 | const lineNumber = parts[1]; 64 | core.info(`::error file=${file},line=${lineNumber}::${result[0]}`); 65 | } 66 | } 67 | } 68 | }); 69 | } catch (error) { 70 | core.setFailed(error.message); 71 | } 72 | -------------------------------------------------------------------------------- /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/http-client 14 | MIT 15 | Actions Http Client for Node.js 16 | 17 | Copyright (c) GitHub, Inc. 18 | 19 | All rights reserved. 20 | 21 | MIT License 22 | 23 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 24 | associated documentation files (the "Software"), to deal in the Software without restriction, 25 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 26 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 27 | subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 32 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 33 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 35 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | 37 | 38 | line-by-line 39 | MIT 40 | 41 | Copyright (c) 2012 Markus von der Wehd 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining 44 | a copy of this software and associated documentation files (the "Software"), 45 | to deal in the Software without restriction, including without limitation 46 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 47 | and/or sell copies of the Software, and to permit persons to whom the Software 48 | is furnished to do so, subject to the following conditions: 49 | 50 | The above copyright notice and this permission notice shall be included 51 | in all copies or substantial portions of the Software. 52 | 53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 54 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 56 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 57 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 58 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 59 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 60 | 61 | 62 | tunnel 63 | MIT 64 | The MIT License (MIT) 65 | 66 | Copyright (c) 2012 Koichi Kobayashi 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy 69 | of this software and associated documentation files (the "Software"), to deal 70 | in the Software without restriction, including without limitation the rights 71 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 72 | copies of the Software, and to permit persons to whom the Software is 73 | furnished to do so, subject to the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be included in 76 | all copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 79 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 80 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 81 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 82 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 83 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 84 | THE SOFTWARE. 85 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | /******/ (() => { // webpackBootstrap 2 | /******/ var __webpack_modules__ = ({ 3 | 4 | /***/ 351: 5 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 6 | 7 | "use strict"; 8 | 9 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 12 | }) : (function(o, m, k, k2) { 13 | if (k2 === undefined) k2 = k; 14 | o[k2] = m[k]; 15 | })); 16 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 17 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 18 | }) : function(o, v) { 19 | o["default"] = v; 20 | }); 21 | var __importStar = (this && this.__importStar) || function (mod) { 22 | if (mod && mod.__esModule) return mod; 23 | var result = {}; 24 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 25 | __setModuleDefault(result, mod); 26 | return result; 27 | }; 28 | Object.defineProperty(exports, "__esModule", ({ value: true })); 29 | exports.issue = exports.issueCommand = void 0; 30 | const os = __importStar(__nccwpck_require__(37)); 31 | const utils_1 = __nccwpck_require__(278); 32 | /** 33 | * Commands 34 | * 35 | * Command Format: 36 | * ::name key=value,key=value::message 37 | * 38 | * Examples: 39 | * ::warning::This is the message 40 | * ::set-env name=MY_VAR::some value 41 | */ 42 | function issueCommand(command, properties, message) { 43 | const cmd = new Command(command, properties, message); 44 | process.stdout.write(cmd.toString() + os.EOL); 45 | } 46 | exports.issueCommand = issueCommand; 47 | function issue(name, message = '') { 48 | issueCommand(name, {}, message); 49 | } 50 | exports.issue = issue; 51 | const CMD_STRING = '::'; 52 | class Command { 53 | constructor(command, properties, message) { 54 | if (!command) { 55 | command = 'missing.command'; 56 | } 57 | this.command = command; 58 | this.properties = properties; 59 | this.message = message; 60 | } 61 | toString() { 62 | let cmdStr = CMD_STRING + this.command; 63 | if (this.properties && Object.keys(this.properties).length > 0) { 64 | cmdStr += ' '; 65 | let first = true; 66 | for (const key in this.properties) { 67 | if (this.properties.hasOwnProperty(key)) { 68 | const val = this.properties[key]; 69 | if (val) { 70 | if (first) { 71 | first = false; 72 | } 73 | else { 74 | cmdStr += ','; 75 | } 76 | cmdStr += `${key}=${escapeProperty(val)}`; 77 | } 78 | } 79 | } 80 | } 81 | cmdStr += `${CMD_STRING}${escapeData(this.message)}`; 82 | return cmdStr; 83 | } 84 | } 85 | function escapeData(s) { 86 | return utils_1.toCommandValue(s) 87 | .replace(/%/g, '%25') 88 | .replace(/\r/g, '%0D') 89 | .replace(/\n/g, '%0A'); 90 | } 91 | function escapeProperty(s) { 92 | return utils_1.toCommandValue(s) 93 | .replace(/%/g, '%25') 94 | .replace(/\r/g, '%0D') 95 | .replace(/\n/g, '%0A') 96 | .replace(/:/g, '%3A') 97 | .replace(/,/g, '%2C'); 98 | } 99 | //# sourceMappingURL=command.js.map 100 | 101 | /***/ }), 102 | 103 | /***/ 186: 104 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 105 | 106 | "use strict"; 107 | 108 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 109 | if (k2 === undefined) k2 = k; 110 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 111 | }) : (function(o, m, k, k2) { 112 | if (k2 === undefined) k2 = k; 113 | o[k2] = m[k]; 114 | })); 115 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 116 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 117 | }) : function(o, v) { 118 | o["default"] = v; 119 | }); 120 | var __importStar = (this && this.__importStar) || function (mod) { 121 | if (mod && mod.__esModule) return mod; 122 | var result = {}; 123 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 124 | __setModuleDefault(result, mod); 125 | return result; 126 | }; 127 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 128 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 129 | return new (P || (P = Promise))(function (resolve, reject) { 130 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 131 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 132 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 133 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 134 | }); 135 | }; 136 | Object.defineProperty(exports, "__esModule", ({ value: true })); 137 | exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; 138 | const command_1 = __nccwpck_require__(351); 139 | const file_command_1 = __nccwpck_require__(717); 140 | const utils_1 = __nccwpck_require__(278); 141 | const os = __importStar(__nccwpck_require__(37)); 142 | const path = __importStar(__nccwpck_require__(17)); 143 | const oidc_utils_1 = __nccwpck_require__(41); 144 | /** 145 | * The code to exit an action 146 | */ 147 | var ExitCode; 148 | (function (ExitCode) { 149 | /** 150 | * A code indicating that the action was successful 151 | */ 152 | ExitCode[ExitCode["Success"] = 0] = "Success"; 153 | /** 154 | * A code indicating that the action was a failure 155 | */ 156 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 157 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 158 | //----------------------------------------------------------------------- 159 | // Variables 160 | //----------------------------------------------------------------------- 161 | /** 162 | * Sets env variable for this action and future actions in the job 163 | * @param name the name of the variable to set 164 | * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify 165 | */ 166 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 167 | function exportVariable(name, val) { 168 | const convertedVal = utils_1.toCommandValue(val); 169 | process.env[name] = convertedVal; 170 | const filePath = process.env['GITHUB_ENV'] || ''; 171 | if (filePath) { 172 | const delimiter = '_GitHubActionsFileCommandDelimeter_'; 173 | const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; 174 | file_command_1.issueCommand('ENV', commandValue); 175 | } 176 | else { 177 | command_1.issueCommand('set-env', { name }, convertedVal); 178 | } 179 | } 180 | exports.exportVariable = exportVariable; 181 | /** 182 | * Registers a secret which will get masked from logs 183 | * @param secret value of the secret 184 | */ 185 | function setSecret(secret) { 186 | command_1.issueCommand('add-mask', {}, secret); 187 | } 188 | exports.setSecret = setSecret; 189 | /** 190 | * Prepends inputPath to the PATH (for this action and future actions) 191 | * @param inputPath 192 | */ 193 | function addPath(inputPath) { 194 | const filePath = process.env['GITHUB_PATH'] || ''; 195 | if (filePath) { 196 | file_command_1.issueCommand('PATH', inputPath); 197 | } 198 | else { 199 | command_1.issueCommand('add-path', {}, inputPath); 200 | } 201 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 202 | } 203 | exports.addPath = addPath; 204 | /** 205 | * Gets the value of an input. 206 | * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed. 207 | * Returns an empty string if the value is not defined. 208 | * 209 | * @param name name of the input to get 210 | * @param options optional. See InputOptions. 211 | * @returns string 212 | */ 213 | function getInput(name, options) { 214 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 215 | if (options && options.required && !val) { 216 | throw new Error(`Input required and not supplied: ${name}`); 217 | } 218 | if (options && options.trimWhitespace === false) { 219 | return val; 220 | } 221 | return val.trim(); 222 | } 223 | exports.getInput = getInput; 224 | /** 225 | * Gets the values of an multiline input. Each value is also trimmed. 226 | * 227 | * @param name name of the input to get 228 | * @param options optional. See InputOptions. 229 | * @returns string[] 230 | * 231 | */ 232 | function getMultilineInput(name, options) { 233 | const inputs = getInput(name, options) 234 | .split('\n') 235 | .filter(x => x !== ''); 236 | return inputs; 237 | } 238 | exports.getMultilineInput = getMultilineInput; 239 | /** 240 | * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification. 241 | * Support boolean input list: `true | True | TRUE | false | False | FALSE` . 242 | * The return value is also in boolean type. 243 | * ref: https://yaml.org/spec/1.2/spec.html#id2804923 244 | * 245 | * @param name name of the input to get 246 | * @param options optional. See InputOptions. 247 | * @returns boolean 248 | */ 249 | function getBooleanInput(name, options) { 250 | const trueValue = ['true', 'True', 'TRUE']; 251 | const falseValue = ['false', 'False', 'FALSE']; 252 | const val = getInput(name, options); 253 | if (trueValue.includes(val)) 254 | return true; 255 | if (falseValue.includes(val)) 256 | return false; 257 | throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` + 258 | `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); 259 | } 260 | exports.getBooleanInput = getBooleanInput; 261 | /** 262 | * Sets the value of an output. 263 | * 264 | * @param name name of the output to set 265 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 266 | */ 267 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 268 | function setOutput(name, value) { 269 | process.stdout.write(os.EOL); 270 | command_1.issueCommand('set-output', { name }, value); 271 | } 272 | exports.setOutput = setOutput; 273 | /** 274 | * Enables or disables the echoing of commands into stdout for the rest of the step. 275 | * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 276 | * 277 | */ 278 | function setCommandEcho(enabled) { 279 | command_1.issue('echo', enabled ? 'on' : 'off'); 280 | } 281 | exports.setCommandEcho = setCommandEcho; 282 | //----------------------------------------------------------------------- 283 | // Results 284 | //----------------------------------------------------------------------- 285 | /** 286 | * Sets the action status to failed. 287 | * When the action exits it will be with an exit code of 1 288 | * @param message add error issue message 289 | */ 290 | function setFailed(message) { 291 | process.exitCode = ExitCode.Failure; 292 | error(message); 293 | } 294 | exports.setFailed = setFailed; 295 | //----------------------------------------------------------------------- 296 | // Logging Commands 297 | //----------------------------------------------------------------------- 298 | /** 299 | * Gets whether Actions Step Debug is on or not 300 | */ 301 | function isDebug() { 302 | return process.env['RUNNER_DEBUG'] === '1'; 303 | } 304 | exports.isDebug = isDebug; 305 | /** 306 | * Writes debug message to user log 307 | * @param message debug message 308 | */ 309 | function debug(message) { 310 | command_1.issueCommand('debug', {}, message); 311 | } 312 | exports.debug = debug; 313 | /** 314 | * Adds an error issue 315 | * @param message error issue message. Errors will be converted to string via toString() 316 | * @param properties optional properties to add to the annotation. 317 | */ 318 | function error(message, properties = {}) { 319 | command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); 320 | } 321 | exports.error = error; 322 | /** 323 | * Adds a warning issue 324 | * @param message warning issue message. Errors will be converted to string via toString() 325 | * @param properties optional properties to add to the annotation. 326 | */ 327 | function warning(message, properties = {}) { 328 | command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); 329 | } 330 | exports.warning = warning; 331 | /** 332 | * Adds a notice issue 333 | * @param message notice issue message. Errors will be converted to string via toString() 334 | * @param properties optional properties to add to the annotation. 335 | */ 336 | function notice(message, properties = {}) { 337 | command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); 338 | } 339 | exports.notice = notice; 340 | /** 341 | * Writes info to log with console.log. 342 | * @param message info message 343 | */ 344 | function info(message) { 345 | process.stdout.write(message + os.EOL); 346 | } 347 | exports.info = info; 348 | /** 349 | * Begin an output group. 350 | * 351 | * Output until the next `groupEnd` will be foldable in this group 352 | * 353 | * @param name The name of the output group 354 | */ 355 | function startGroup(name) { 356 | command_1.issue('group', name); 357 | } 358 | exports.startGroup = startGroup; 359 | /** 360 | * End an output group. 361 | */ 362 | function endGroup() { 363 | command_1.issue('endgroup'); 364 | } 365 | exports.endGroup = endGroup; 366 | /** 367 | * Wrap an asynchronous function call in a group. 368 | * 369 | * Returns the same type as the function itself. 370 | * 371 | * @param name The name of the group 372 | * @param fn The function to wrap in the group 373 | */ 374 | function group(name, fn) { 375 | return __awaiter(this, void 0, void 0, function* () { 376 | startGroup(name); 377 | let result; 378 | try { 379 | result = yield fn(); 380 | } 381 | finally { 382 | endGroup(); 383 | } 384 | return result; 385 | }); 386 | } 387 | exports.group = group; 388 | //----------------------------------------------------------------------- 389 | // Wrapper action state 390 | //----------------------------------------------------------------------- 391 | /** 392 | * Saves state for current action, the state can only be retrieved by this action's post job execution. 393 | * 394 | * @param name name of the state to store 395 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 396 | */ 397 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 398 | function saveState(name, value) { 399 | command_1.issueCommand('save-state', { name }, value); 400 | } 401 | exports.saveState = saveState; 402 | /** 403 | * Gets the value of an state set by this action's main execution. 404 | * 405 | * @param name name of the state to get 406 | * @returns string 407 | */ 408 | function getState(name) { 409 | return process.env[`STATE_${name}`] || ''; 410 | } 411 | exports.getState = getState; 412 | function getIDToken(aud) { 413 | return __awaiter(this, void 0, void 0, function* () { 414 | return yield oidc_utils_1.OidcClient.getIDToken(aud); 415 | }); 416 | } 417 | exports.getIDToken = getIDToken; 418 | //# sourceMappingURL=core.js.map 419 | 420 | /***/ }), 421 | 422 | /***/ 717: 423 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 424 | 425 | "use strict"; 426 | 427 | // For internal use, subject to change. 428 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 429 | if (k2 === undefined) k2 = k; 430 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 431 | }) : (function(o, m, k, k2) { 432 | if (k2 === undefined) k2 = k; 433 | o[k2] = m[k]; 434 | })); 435 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 436 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 437 | }) : function(o, v) { 438 | o["default"] = v; 439 | }); 440 | var __importStar = (this && this.__importStar) || function (mod) { 441 | if (mod && mod.__esModule) return mod; 442 | var result = {}; 443 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 444 | __setModuleDefault(result, mod); 445 | return result; 446 | }; 447 | Object.defineProperty(exports, "__esModule", ({ value: true })); 448 | exports.issueCommand = void 0; 449 | // We use any as a valid input type 450 | /* eslint-disable @typescript-eslint/no-explicit-any */ 451 | const fs = __importStar(__nccwpck_require__(147)); 452 | const os = __importStar(__nccwpck_require__(37)); 453 | const utils_1 = __nccwpck_require__(278); 454 | function issueCommand(command, message) { 455 | const filePath = process.env[`GITHUB_${command}`]; 456 | if (!filePath) { 457 | throw new Error(`Unable to find environment variable for file command ${command}`); 458 | } 459 | if (!fs.existsSync(filePath)) { 460 | throw new Error(`Missing file at path: ${filePath}`); 461 | } 462 | fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { 463 | encoding: 'utf8' 464 | }); 465 | } 466 | exports.issueCommand = issueCommand; 467 | //# sourceMappingURL=file-command.js.map 468 | 469 | /***/ }), 470 | 471 | /***/ 41: 472 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 473 | 474 | "use strict"; 475 | 476 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 477 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 478 | return new (P || (P = Promise))(function (resolve, reject) { 479 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 480 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 481 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 482 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 483 | }); 484 | }; 485 | Object.defineProperty(exports, "__esModule", ({ value: true })); 486 | exports.OidcClient = void 0; 487 | const http_client_1 = __nccwpck_require__(925); 488 | const auth_1 = __nccwpck_require__(702); 489 | const core_1 = __nccwpck_require__(186); 490 | class OidcClient { 491 | static createHttpClient(allowRetry = true, maxRetry = 10) { 492 | const requestOptions = { 493 | allowRetries: allowRetry, 494 | maxRetries: maxRetry 495 | }; 496 | return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions); 497 | } 498 | static getRequestToken() { 499 | const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN']; 500 | if (!token) { 501 | throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable'); 502 | } 503 | return token; 504 | } 505 | static getIDTokenUrl() { 506 | const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL']; 507 | if (!runtimeUrl) { 508 | throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'); 509 | } 510 | return runtimeUrl; 511 | } 512 | static getCall(id_token_url) { 513 | var _a; 514 | return __awaiter(this, void 0, void 0, function* () { 515 | const httpclient = OidcClient.createHttpClient(); 516 | const res = yield httpclient 517 | .getJson(id_token_url) 518 | .catch(error => { 519 | throw new Error(`Failed to get ID Token. \n 520 | Error Code : ${error.statusCode}\n 521 | Error Message: ${error.result.message}`); 522 | }); 523 | const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; 524 | if (!id_token) { 525 | throw new Error('Response json body do not have ID Token field'); 526 | } 527 | return id_token; 528 | }); 529 | } 530 | static getIDToken(audience) { 531 | return __awaiter(this, void 0, void 0, function* () { 532 | try { 533 | // New ID Token is requested from action service 534 | let id_token_url = OidcClient.getIDTokenUrl(); 535 | if (audience) { 536 | const encodedAudience = encodeURIComponent(audience); 537 | id_token_url = `${id_token_url}&audience=${encodedAudience}`; 538 | } 539 | core_1.debug(`ID token url is ${id_token_url}`); 540 | const id_token = yield OidcClient.getCall(id_token_url); 541 | core_1.setSecret(id_token); 542 | return id_token; 543 | } 544 | catch (error) { 545 | throw new Error(`Error message: ${error.message}`); 546 | } 547 | }); 548 | } 549 | } 550 | exports.OidcClient = OidcClient; 551 | //# sourceMappingURL=oidc-utils.js.map 552 | 553 | /***/ }), 554 | 555 | /***/ 278: 556 | /***/ ((__unused_webpack_module, exports) => { 557 | 558 | "use strict"; 559 | 560 | // We use any as a valid input type 561 | /* eslint-disable @typescript-eslint/no-explicit-any */ 562 | Object.defineProperty(exports, "__esModule", ({ value: true })); 563 | exports.toCommandProperties = exports.toCommandValue = void 0; 564 | /** 565 | * Sanitizes an input into a string so it can be passed into issueCommand safely 566 | * @param input input to sanitize into a string 567 | */ 568 | function toCommandValue(input) { 569 | if (input === null || input === undefined) { 570 | return ''; 571 | } 572 | else if (typeof input === 'string' || input instanceof String) { 573 | return input; 574 | } 575 | return JSON.stringify(input); 576 | } 577 | exports.toCommandValue = toCommandValue; 578 | /** 579 | * 580 | * @param annotationProperties 581 | * @returns The command properties to send with the actual annotation command 582 | * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646 583 | */ 584 | function toCommandProperties(annotationProperties) { 585 | if (!Object.keys(annotationProperties).length) { 586 | return {}; 587 | } 588 | return { 589 | title: annotationProperties.title, 590 | file: annotationProperties.file, 591 | line: annotationProperties.startLine, 592 | endLine: annotationProperties.endLine, 593 | col: annotationProperties.startColumn, 594 | endColumn: annotationProperties.endColumn 595 | }; 596 | } 597 | exports.toCommandProperties = toCommandProperties; 598 | //# sourceMappingURL=utils.js.map 599 | 600 | /***/ }), 601 | 602 | /***/ 702: 603 | /***/ ((__unused_webpack_module, exports) => { 604 | 605 | "use strict"; 606 | 607 | Object.defineProperty(exports, "__esModule", ({ value: true })); 608 | class BasicCredentialHandler { 609 | constructor(username, password) { 610 | this.username = username; 611 | this.password = password; 612 | } 613 | prepareRequest(options) { 614 | options.headers['Authorization'] = 615 | 'Basic ' + 616 | Buffer.from(this.username + ':' + this.password).toString('base64'); 617 | } 618 | // This handler cannot handle 401 619 | canHandleAuthentication(response) { 620 | return false; 621 | } 622 | handleAuthentication(httpClient, requestInfo, objs) { 623 | return null; 624 | } 625 | } 626 | exports.BasicCredentialHandler = BasicCredentialHandler; 627 | class BearerCredentialHandler { 628 | constructor(token) { 629 | this.token = token; 630 | } 631 | // currently implements pre-authorization 632 | // TODO: support preAuth = false where it hooks on 401 633 | prepareRequest(options) { 634 | options.headers['Authorization'] = 'Bearer ' + this.token; 635 | } 636 | // This handler cannot handle 401 637 | canHandleAuthentication(response) { 638 | return false; 639 | } 640 | handleAuthentication(httpClient, requestInfo, objs) { 641 | return null; 642 | } 643 | } 644 | exports.BearerCredentialHandler = BearerCredentialHandler; 645 | class PersonalAccessTokenCredentialHandler { 646 | constructor(token) { 647 | this.token = token; 648 | } 649 | // currently implements pre-authorization 650 | // TODO: support preAuth = false where it hooks on 401 651 | prepareRequest(options) { 652 | options.headers['Authorization'] = 653 | 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64'); 654 | } 655 | // This handler cannot handle 401 656 | canHandleAuthentication(response) { 657 | return false; 658 | } 659 | handleAuthentication(httpClient, requestInfo, objs) { 660 | return null; 661 | } 662 | } 663 | exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; 664 | 665 | 666 | /***/ }), 667 | 668 | /***/ 925: 669 | /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { 670 | 671 | "use strict"; 672 | 673 | Object.defineProperty(exports, "__esModule", ({ value: true })); 674 | const http = __nccwpck_require__(685); 675 | const https = __nccwpck_require__(687); 676 | const pm = __nccwpck_require__(443); 677 | let tunnel; 678 | var HttpCodes; 679 | (function (HttpCodes) { 680 | HttpCodes[HttpCodes["OK"] = 200] = "OK"; 681 | HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices"; 682 | HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently"; 683 | HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved"; 684 | HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther"; 685 | HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified"; 686 | HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy"; 687 | HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy"; 688 | HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect"; 689 | HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect"; 690 | HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest"; 691 | HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized"; 692 | HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired"; 693 | HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden"; 694 | HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound"; 695 | HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed"; 696 | HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable"; 697 | HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; 698 | HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout"; 699 | HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict"; 700 | HttpCodes[HttpCodes["Gone"] = 410] = "Gone"; 701 | HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests"; 702 | HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError"; 703 | HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented"; 704 | HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; 705 | HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; 706 | HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; 707 | })(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {})); 708 | var Headers; 709 | (function (Headers) { 710 | Headers["Accept"] = "accept"; 711 | Headers["ContentType"] = "content-type"; 712 | })(Headers = exports.Headers || (exports.Headers = {})); 713 | var MediaTypes; 714 | (function (MediaTypes) { 715 | MediaTypes["ApplicationJson"] = "application/json"; 716 | })(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {})); 717 | /** 718 | * Returns the proxy URL, depending upon the supplied url and proxy environment variables. 719 | * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com 720 | */ 721 | function getProxyUrl(serverUrl) { 722 | let proxyUrl = pm.getProxyUrl(new URL(serverUrl)); 723 | return proxyUrl ? proxyUrl.href : ''; 724 | } 725 | exports.getProxyUrl = getProxyUrl; 726 | const HttpRedirectCodes = [ 727 | HttpCodes.MovedPermanently, 728 | HttpCodes.ResourceMoved, 729 | HttpCodes.SeeOther, 730 | HttpCodes.TemporaryRedirect, 731 | HttpCodes.PermanentRedirect 732 | ]; 733 | const HttpResponseRetryCodes = [ 734 | HttpCodes.BadGateway, 735 | HttpCodes.ServiceUnavailable, 736 | HttpCodes.GatewayTimeout 737 | ]; 738 | const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; 739 | const ExponentialBackoffCeiling = 10; 740 | const ExponentialBackoffTimeSlice = 5; 741 | class HttpClientError extends Error { 742 | constructor(message, statusCode) { 743 | super(message); 744 | this.name = 'HttpClientError'; 745 | this.statusCode = statusCode; 746 | Object.setPrototypeOf(this, HttpClientError.prototype); 747 | } 748 | } 749 | exports.HttpClientError = HttpClientError; 750 | class HttpClientResponse { 751 | constructor(message) { 752 | this.message = message; 753 | } 754 | readBody() { 755 | return new Promise(async (resolve, reject) => { 756 | let output = Buffer.alloc(0); 757 | this.message.on('data', (chunk) => { 758 | output = Buffer.concat([output, chunk]); 759 | }); 760 | this.message.on('end', () => { 761 | resolve(output.toString()); 762 | }); 763 | }); 764 | } 765 | } 766 | exports.HttpClientResponse = HttpClientResponse; 767 | function isHttps(requestUrl) { 768 | let parsedUrl = new URL(requestUrl); 769 | return parsedUrl.protocol === 'https:'; 770 | } 771 | exports.isHttps = isHttps; 772 | class HttpClient { 773 | constructor(userAgent, handlers, requestOptions) { 774 | this._ignoreSslError = false; 775 | this._allowRedirects = true; 776 | this._allowRedirectDowngrade = false; 777 | this._maxRedirects = 50; 778 | this._allowRetries = false; 779 | this._maxRetries = 1; 780 | this._keepAlive = false; 781 | this._disposed = false; 782 | this.userAgent = userAgent; 783 | this.handlers = handlers || []; 784 | this.requestOptions = requestOptions; 785 | if (requestOptions) { 786 | if (requestOptions.ignoreSslError != null) { 787 | this._ignoreSslError = requestOptions.ignoreSslError; 788 | } 789 | this._socketTimeout = requestOptions.socketTimeout; 790 | if (requestOptions.allowRedirects != null) { 791 | this._allowRedirects = requestOptions.allowRedirects; 792 | } 793 | if (requestOptions.allowRedirectDowngrade != null) { 794 | this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; 795 | } 796 | if (requestOptions.maxRedirects != null) { 797 | this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); 798 | } 799 | if (requestOptions.keepAlive != null) { 800 | this._keepAlive = requestOptions.keepAlive; 801 | } 802 | if (requestOptions.allowRetries != null) { 803 | this._allowRetries = requestOptions.allowRetries; 804 | } 805 | if (requestOptions.maxRetries != null) { 806 | this._maxRetries = requestOptions.maxRetries; 807 | } 808 | } 809 | } 810 | options(requestUrl, additionalHeaders) { 811 | return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); 812 | } 813 | get(requestUrl, additionalHeaders) { 814 | return this.request('GET', requestUrl, null, additionalHeaders || {}); 815 | } 816 | del(requestUrl, additionalHeaders) { 817 | return this.request('DELETE', requestUrl, null, additionalHeaders || {}); 818 | } 819 | post(requestUrl, data, additionalHeaders) { 820 | return this.request('POST', requestUrl, data, additionalHeaders || {}); 821 | } 822 | patch(requestUrl, data, additionalHeaders) { 823 | return this.request('PATCH', requestUrl, data, additionalHeaders || {}); 824 | } 825 | put(requestUrl, data, additionalHeaders) { 826 | return this.request('PUT', requestUrl, data, additionalHeaders || {}); 827 | } 828 | head(requestUrl, additionalHeaders) { 829 | return this.request('HEAD', requestUrl, null, additionalHeaders || {}); 830 | } 831 | sendStream(verb, requestUrl, stream, additionalHeaders) { 832 | return this.request(verb, requestUrl, stream, additionalHeaders); 833 | } 834 | /** 835 | * Gets a typed object from an endpoint 836 | * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise 837 | */ 838 | async getJson(requestUrl, additionalHeaders = {}) { 839 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 840 | let res = await this.get(requestUrl, additionalHeaders); 841 | return this._processResponse(res, this.requestOptions); 842 | } 843 | async postJson(requestUrl, obj, additionalHeaders = {}) { 844 | let data = JSON.stringify(obj, null, 2); 845 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 846 | additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 847 | let res = await this.post(requestUrl, data, additionalHeaders); 848 | return this._processResponse(res, this.requestOptions); 849 | } 850 | async putJson(requestUrl, obj, additionalHeaders = {}) { 851 | let data = JSON.stringify(obj, null, 2); 852 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 853 | additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 854 | let res = await this.put(requestUrl, data, additionalHeaders); 855 | return this._processResponse(res, this.requestOptions); 856 | } 857 | async patchJson(requestUrl, obj, additionalHeaders = {}) { 858 | let data = JSON.stringify(obj, null, 2); 859 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 860 | additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 861 | let res = await this.patch(requestUrl, data, additionalHeaders); 862 | return this._processResponse(res, this.requestOptions); 863 | } 864 | /** 865 | * Makes a raw http request. 866 | * All other methods such as get, post, patch, and request ultimately call this. 867 | * Prefer get, del, post and patch 868 | */ 869 | async request(verb, requestUrl, data, headers) { 870 | if (this._disposed) { 871 | throw new Error('Client has already been disposed.'); 872 | } 873 | let parsedUrl = new URL(requestUrl); 874 | let info = this._prepareRequest(verb, parsedUrl, headers); 875 | // Only perform retries on reads since writes may not be idempotent. 876 | let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1 877 | ? this._maxRetries + 1 878 | : 1; 879 | let numTries = 0; 880 | let response; 881 | while (numTries < maxTries) { 882 | response = await this.requestRaw(info, data); 883 | // Check if it's an authentication challenge 884 | if (response && 885 | response.message && 886 | response.message.statusCode === HttpCodes.Unauthorized) { 887 | let authenticationHandler; 888 | for (let i = 0; i < this.handlers.length; i++) { 889 | if (this.handlers[i].canHandleAuthentication(response)) { 890 | authenticationHandler = this.handlers[i]; 891 | break; 892 | } 893 | } 894 | if (authenticationHandler) { 895 | return authenticationHandler.handleAuthentication(this, info, data); 896 | } 897 | else { 898 | // We have received an unauthorized response but have no handlers to handle it. 899 | // Let the response return to the caller. 900 | return response; 901 | } 902 | } 903 | let redirectsRemaining = this._maxRedirects; 904 | while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 && 905 | this._allowRedirects && 906 | redirectsRemaining > 0) { 907 | const redirectUrl = response.message.headers['location']; 908 | if (!redirectUrl) { 909 | // if there's no location to redirect to, we won't 910 | break; 911 | } 912 | let parsedRedirectUrl = new URL(redirectUrl); 913 | if (parsedUrl.protocol == 'https:' && 914 | parsedUrl.protocol != parsedRedirectUrl.protocol && 915 | !this._allowRedirectDowngrade) { 916 | throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.'); 917 | } 918 | // we need to finish reading the response before reassigning response 919 | // which will leak the open socket. 920 | await response.readBody(); 921 | // strip authorization header if redirected to a different hostname 922 | if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { 923 | for (let header in headers) { 924 | // header names are case insensitive 925 | if (header.toLowerCase() === 'authorization') { 926 | delete headers[header]; 927 | } 928 | } 929 | } 930 | // let's make the request with the new redirectUrl 931 | info = this._prepareRequest(verb, parsedRedirectUrl, headers); 932 | response = await this.requestRaw(info, data); 933 | redirectsRemaining--; 934 | } 935 | if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) { 936 | // If not a retry code, return immediately instead of retrying 937 | return response; 938 | } 939 | numTries += 1; 940 | if (numTries < maxTries) { 941 | await response.readBody(); 942 | await this._performExponentialBackoff(numTries); 943 | } 944 | } 945 | return response; 946 | } 947 | /** 948 | * Needs to be called if keepAlive is set to true in request options. 949 | */ 950 | dispose() { 951 | if (this._agent) { 952 | this._agent.destroy(); 953 | } 954 | this._disposed = true; 955 | } 956 | /** 957 | * Raw request. 958 | * @param info 959 | * @param data 960 | */ 961 | requestRaw(info, data) { 962 | return new Promise((resolve, reject) => { 963 | let callbackForResult = function (err, res) { 964 | if (err) { 965 | reject(err); 966 | } 967 | resolve(res); 968 | }; 969 | this.requestRawWithCallback(info, data, callbackForResult); 970 | }); 971 | } 972 | /** 973 | * Raw request with callback. 974 | * @param info 975 | * @param data 976 | * @param onResult 977 | */ 978 | requestRawWithCallback(info, data, onResult) { 979 | let socket; 980 | if (typeof data === 'string') { 981 | info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); 982 | } 983 | let callbackCalled = false; 984 | let handleResult = (err, res) => { 985 | if (!callbackCalled) { 986 | callbackCalled = true; 987 | onResult(err, res); 988 | } 989 | }; 990 | let req = info.httpModule.request(info.options, (msg) => { 991 | let res = new HttpClientResponse(msg); 992 | handleResult(null, res); 993 | }); 994 | req.on('socket', sock => { 995 | socket = sock; 996 | }); 997 | // If we ever get disconnected, we want the socket to timeout eventually 998 | req.setTimeout(this._socketTimeout || 3 * 60000, () => { 999 | if (socket) { 1000 | socket.end(); 1001 | } 1002 | handleResult(new Error('Request timeout: ' + info.options.path), null); 1003 | }); 1004 | req.on('error', function (err) { 1005 | // err has statusCode property 1006 | // res should have headers 1007 | handleResult(err, null); 1008 | }); 1009 | if (data && typeof data === 'string') { 1010 | req.write(data, 'utf8'); 1011 | } 1012 | if (data && typeof data !== 'string') { 1013 | data.on('close', function () { 1014 | req.end(); 1015 | }); 1016 | data.pipe(req); 1017 | } 1018 | else { 1019 | req.end(); 1020 | } 1021 | } 1022 | /** 1023 | * Gets an http agent. This function is useful when you need an http agent that handles 1024 | * routing through a proxy server - depending upon the url and proxy environment variables. 1025 | * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com 1026 | */ 1027 | getAgent(serverUrl) { 1028 | let parsedUrl = new URL(serverUrl); 1029 | return this._getAgent(parsedUrl); 1030 | } 1031 | _prepareRequest(method, requestUrl, headers) { 1032 | const info = {}; 1033 | info.parsedUrl = requestUrl; 1034 | const usingSsl = info.parsedUrl.protocol === 'https:'; 1035 | info.httpModule = usingSsl ? https : http; 1036 | const defaultPort = usingSsl ? 443 : 80; 1037 | info.options = {}; 1038 | info.options.host = info.parsedUrl.hostname; 1039 | info.options.port = info.parsedUrl.port 1040 | ? parseInt(info.parsedUrl.port) 1041 | : defaultPort; 1042 | info.options.path = 1043 | (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); 1044 | info.options.method = method; 1045 | info.options.headers = this._mergeHeaders(headers); 1046 | if (this.userAgent != null) { 1047 | info.options.headers['user-agent'] = this.userAgent; 1048 | } 1049 | info.options.agent = this._getAgent(info.parsedUrl); 1050 | // gives handlers an opportunity to participate 1051 | if (this.handlers) { 1052 | this.handlers.forEach(handler => { 1053 | handler.prepareRequest(info.options); 1054 | }); 1055 | } 1056 | return info; 1057 | } 1058 | _mergeHeaders(headers) { 1059 | const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); 1060 | if (this.requestOptions && this.requestOptions.headers) { 1061 | return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers)); 1062 | } 1063 | return lowercaseKeys(headers || {}); 1064 | } 1065 | _getExistingOrDefaultHeader(additionalHeaders, header, _default) { 1066 | const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); 1067 | let clientHeader; 1068 | if (this.requestOptions && this.requestOptions.headers) { 1069 | clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; 1070 | } 1071 | return additionalHeaders[header] || clientHeader || _default; 1072 | } 1073 | _getAgent(parsedUrl) { 1074 | let agent; 1075 | let proxyUrl = pm.getProxyUrl(parsedUrl); 1076 | let useProxy = proxyUrl && proxyUrl.hostname; 1077 | if (this._keepAlive && useProxy) { 1078 | agent = this._proxyAgent; 1079 | } 1080 | if (this._keepAlive && !useProxy) { 1081 | agent = this._agent; 1082 | } 1083 | // if agent is already assigned use that agent. 1084 | if (!!agent) { 1085 | return agent; 1086 | } 1087 | const usingSsl = parsedUrl.protocol === 'https:'; 1088 | let maxSockets = 100; 1089 | if (!!this.requestOptions) { 1090 | maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets; 1091 | } 1092 | if (useProxy) { 1093 | // If using proxy, need tunnel 1094 | if (!tunnel) { 1095 | tunnel = __nccwpck_require__(294); 1096 | } 1097 | const agentOptions = { 1098 | maxSockets: maxSockets, 1099 | keepAlive: this._keepAlive, 1100 | proxy: { 1101 | ...((proxyUrl.username || proxyUrl.password) && { 1102 | proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` 1103 | }), 1104 | host: proxyUrl.hostname, 1105 | port: proxyUrl.port 1106 | } 1107 | }; 1108 | let tunnelAgent; 1109 | const overHttps = proxyUrl.protocol === 'https:'; 1110 | if (usingSsl) { 1111 | tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp; 1112 | } 1113 | else { 1114 | tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp; 1115 | } 1116 | agent = tunnelAgent(agentOptions); 1117 | this._proxyAgent = agent; 1118 | } 1119 | // if reusing agent across request and tunneling agent isn't assigned create a new agent 1120 | if (this._keepAlive && !agent) { 1121 | const options = { keepAlive: this._keepAlive, maxSockets: maxSockets }; 1122 | agent = usingSsl ? new https.Agent(options) : new http.Agent(options); 1123 | this._agent = agent; 1124 | } 1125 | // if not using private agent and tunnel agent isn't setup then use global agent 1126 | if (!agent) { 1127 | agent = usingSsl ? https.globalAgent : http.globalAgent; 1128 | } 1129 | if (usingSsl && this._ignoreSslError) { 1130 | // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process 1131 | // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options 1132 | // we have to cast it to any and change it directly 1133 | agent.options = Object.assign(agent.options || {}, { 1134 | rejectUnauthorized: false 1135 | }); 1136 | } 1137 | return agent; 1138 | } 1139 | _performExponentialBackoff(retryNumber) { 1140 | retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); 1141 | const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); 1142 | return new Promise(resolve => setTimeout(() => resolve(), ms)); 1143 | } 1144 | static dateTimeDeserializer(key, value) { 1145 | if (typeof value === 'string') { 1146 | let a = new Date(value); 1147 | if (!isNaN(a.valueOf())) { 1148 | return a; 1149 | } 1150 | } 1151 | return value; 1152 | } 1153 | async _processResponse(res, options) { 1154 | return new Promise(async (resolve, reject) => { 1155 | const statusCode = res.message.statusCode; 1156 | const response = { 1157 | statusCode: statusCode, 1158 | result: null, 1159 | headers: {} 1160 | }; 1161 | // not found leads to null obj returned 1162 | if (statusCode == HttpCodes.NotFound) { 1163 | resolve(response); 1164 | } 1165 | let obj; 1166 | let contents; 1167 | // get the result from the body 1168 | try { 1169 | contents = await res.readBody(); 1170 | if (contents && contents.length > 0) { 1171 | if (options && options.deserializeDates) { 1172 | obj = JSON.parse(contents, HttpClient.dateTimeDeserializer); 1173 | } 1174 | else { 1175 | obj = JSON.parse(contents); 1176 | } 1177 | response.result = obj; 1178 | } 1179 | response.headers = res.message.headers; 1180 | } 1181 | catch (err) { 1182 | // Invalid resource (contents not json); leaving result obj null 1183 | } 1184 | // note that 3xx redirects are handled by the http layer. 1185 | if (statusCode > 299) { 1186 | let msg; 1187 | // if exception/error in body, attempt to get better error 1188 | if (obj && obj.message) { 1189 | msg = obj.message; 1190 | } 1191 | else if (contents && contents.length > 0) { 1192 | // it may be the case that the exception is in the body message as string 1193 | msg = contents; 1194 | } 1195 | else { 1196 | msg = 'Failed request: (' + statusCode + ')'; 1197 | } 1198 | let err = new HttpClientError(msg, statusCode); 1199 | err.result = response.result; 1200 | reject(err); 1201 | } 1202 | else { 1203 | resolve(response); 1204 | } 1205 | }); 1206 | } 1207 | } 1208 | exports.HttpClient = HttpClient; 1209 | 1210 | 1211 | /***/ }), 1212 | 1213 | /***/ 443: 1214 | /***/ ((__unused_webpack_module, exports) => { 1215 | 1216 | "use strict"; 1217 | 1218 | Object.defineProperty(exports, "__esModule", ({ value: true })); 1219 | function getProxyUrl(reqUrl) { 1220 | let usingSsl = reqUrl.protocol === 'https:'; 1221 | let proxyUrl; 1222 | if (checkBypass(reqUrl)) { 1223 | return proxyUrl; 1224 | } 1225 | let proxyVar; 1226 | if (usingSsl) { 1227 | proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY']; 1228 | } 1229 | else { 1230 | proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY']; 1231 | } 1232 | if (proxyVar) { 1233 | proxyUrl = new URL(proxyVar); 1234 | } 1235 | return proxyUrl; 1236 | } 1237 | exports.getProxyUrl = getProxyUrl; 1238 | function checkBypass(reqUrl) { 1239 | if (!reqUrl.hostname) { 1240 | return false; 1241 | } 1242 | let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; 1243 | if (!noProxy) { 1244 | return false; 1245 | } 1246 | // Determine the request port 1247 | let reqPort; 1248 | if (reqUrl.port) { 1249 | reqPort = Number(reqUrl.port); 1250 | } 1251 | else if (reqUrl.protocol === 'http:') { 1252 | reqPort = 80; 1253 | } 1254 | else if (reqUrl.protocol === 'https:') { 1255 | reqPort = 443; 1256 | } 1257 | // Format the request hostname and hostname with port 1258 | let upperReqHosts = [reqUrl.hostname.toUpperCase()]; 1259 | if (typeof reqPort === 'number') { 1260 | upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`); 1261 | } 1262 | // Compare request host against noproxy 1263 | for (let upperNoProxyItem of noProxy 1264 | .split(',') 1265 | .map(x => x.trim().toUpperCase()) 1266 | .filter(x => x)) { 1267 | if (upperReqHosts.some(x => x === upperNoProxyItem)) { 1268 | return true; 1269 | } 1270 | } 1271 | return false; 1272 | } 1273 | exports.checkBypass = checkBypass; 1274 | 1275 | 1276 | /***/ }), 1277 | 1278 | /***/ 752: 1279 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 1280 | 1281 | /* 1282 | * Line By Line 1283 | * 1284 | * A NodeJS module that helps you reading large text files, line by line, 1285 | * without buffering the files into memory. 1286 | * 1287 | * Copyright (c) 2012 Markus von der Wehd 1288 | * MIT License, see LICENSE.txt, see http://www.opensource.org/licenses/mit-license.php 1289 | */ 1290 | 1291 | var stream = __nccwpck_require__(781); 1292 | var StringDecoder = (__nccwpck_require__(576).StringDecoder); 1293 | var path = __nccwpck_require__(17); 1294 | var fs = __nccwpck_require__(147); 1295 | var events = __nccwpck_require__(361); 1296 | 1297 | // let's make sure we have a setImmediate function (node.js <0.10) 1298 | if (typeof global.setImmediate == 'undefined') { setImmediate = process.nextTick;} 1299 | 1300 | var LineByLineReader = function (filepath, options) { 1301 | var self = this; 1302 | 1303 | this._encoding = options && options.encoding || 'utf8'; 1304 | if (filepath instanceof stream.Readable) { 1305 | this._readStream = filepath; 1306 | } 1307 | else { 1308 | this._readStream = null; 1309 | this._filepath = path.normalize(filepath); 1310 | this._streamOptions = { encoding: this._encoding }; 1311 | 1312 | if (options && options.start) { 1313 | this._streamOptions.start = options.start; 1314 | } 1315 | 1316 | if (options && options.end) { 1317 | this._streamOptions.end = options.end; 1318 | } 1319 | } 1320 | this._skipEmptyLines = options && options.skipEmptyLines || false; 1321 | 1322 | this._lines = []; 1323 | this._lineFragment = ''; 1324 | this._paused = false; 1325 | this._end = false; 1326 | this._ended = false; 1327 | this.decoder = new StringDecoder(this._encoding); 1328 | 1329 | events.EventEmitter.call(this); 1330 | 1331 | setImmediate(function () { 1332 | self._initStream(); 1333 | }); 1334 | }; 1335 | 1336 | LineByLineReader.prototype = Object.create(events.EventEmitter.prototype, { 1337 | constructor: { 1338 | value: LineByLineReader, 1339 | enumerable: false 1340 | } 1341 | }); 1342 | 1343 | LineByLineReader.prototype._initStream = function () { 1344 | var self = this, 1345 | readStream = this._readStream ? this._readStream : 1346 | fs.createReadStream(this._filepath, this._streamOptions); 1347 | 1348 | readStream.on('error', function (err) { 1349 | self.emit('error', err); 1350 | }); 1351 | 1352 | readStream.on('open', function () { 1353 | self.emit('open'); 1354 | }); 1355 | 1356 | readStream.on('data', function (data) { 1357 | self._readStream.pause(); 1358 | var dataAsString = data; 1359 | if (data instanceof Buffer) { 1360 | dataAsString = self.decoder.write(data); 1361 | } 1362 | self._lines = self._lines.concat(dataAsString.split(/(?:\n|\r\n|\r)/g)); 1363 | 1364 | self._lines[0] = self._lineFragment + self._lines[0]; 1365 | self._lineFragment = self._lines.pop() || ''; 1366 | 1367 | setImmediate(function () { 1368 | self._nextLine(); 1369 | }); 1370 | }); 1371 | 1372 | readStream.on('end', function () { 1373 | self._end = true; 1374 | 1375 | setImmediate(function () { 1376 | self._nextLine(); 1377 | }); 1378 | }); 1379 | 1380 | this._readStream = readStream; 1381 | }; 1382 | 1383 | LineByLineReader.prototype._nextLine = function () { 1384 | var self = this, 1385 | line; 1386 | 1387 | if (this._paused) { 1388 | return; 1389 | } 1390 | 1391 | if (this._lines.length === 0) { 1392 | if (this._end) { 1393 | if (this._lineFragment) { 1394 | this.emit('line', this._lineFragment); 1395 | this._lineFragment = ''; 1396 | } 1397 | if (!this._paused) { 1398 | this.end(); 1399 | } 1400 | } else { 1401 | this._readStream.resume(); 1402 | } 1403 | return; 1404 | } 1405 | 1406 | line = this._lines.shift(); 1407 | 1408 | if (!this._skipEmptyLines || line.length > 0) { 1409 | this.emit('line', line); 1410 | } 1411 | 1412 | setImmediate(function () { 1413 | if (!this._paused) { 1414 | self._nextLine(); 1415 | } 1416 | }); 1417 | }; 1418 | 1419 | LineByLineReader.prototype.pause = function () { 1420 | this._paused = true; 1421 | }; 1422 | 1423 | LineByLineReader.prototype.resume = function () { 1424 | var self = this; 1425 | 1426 | this._paused = false; 1427 | 1428 | setImmediate(function () { 1429 | self._nextLine(); 1430 | }); 1431 | }; 1432 | 1433 | LineByLineReader.prototype.end = function () { 1434 | if (!this._ended){ 1435 | this._ended = true; 1436 | this.emit('end'); 1437 | } 1438 | }; 1439 | 1440 | LineByLineReader.prototype.close = function () { 1441 | var self = this; 1442 | 1443 | this._readStream.destroy(); 1444 | this._end = true; 1445 | this._lines = []; 1446 | 1447 | setImmediate(function () { 1448 | self._nextLine(); 1449 | }); 1450 | }; 1451 | 1452 | module.exports = LineByLineReader; 1453 | 1454 | 1455 | /***/ }), 1456 | 1457 | /***/ 294: 1458 | /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { 1459 | 1460 | module.exports = __nccwpck_require__(219); 1461 | 1462 | 1463 | /***/ }), 1464 | 1465 | /***/ 219: 1466 | /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { 1467 | 1468 | "use strict"; 1469 | 1470 | 1471 | var net = __nccwpck_require__(808); 1472 | var tls = __nccwpck_require__(404); 1473 | var http = __nccwpck_require__(685); 1474 | var https = __nccwpck_require__(687); 1475 | var events = __nccwpck_require__(361); 1476 | var assert = __nccwpck_require__(491); 1477 | var util = __nccwpck_require__(837); 1478 | 1479 | 1480 | exports.httpOverHttp = httpOverHttp; 1481 | exports.httpsOverHttp = httpsOverHttp; 1482 | exports.httpOverHttps = httpOverHttps; 1483 | exports.httpsOverHttps = httpsOverHttps; 1484 | 1485 | 1486 | function httpOverHttp(options) { 1487 | var agent = new TunnelingAgent(options); 1488 | agent.request = http.request; 1489 | return agent; 1490 | } 1491 | 1492 | function httpsOverHttp(options) { 1493 | var agent = new TunnelingAgent(options); 1494 | agent.request = http.request; 1495 | agent.createSocket = createSecureSocket; 1496 | agent.defaultPort = 443; 1497 | return agent; 1498 | } 1499 | 1500 | function httpOverHttps(options) { 1501 | var agent = new TunnelingAgent(options); 1502 | agent.request = https.request; 1503 | return agent; 1504 | } 1505 | 1506 | function httpsOverHttps(options) { 1507 | var agent = new TunnelingAgent(options); 1508 | agent.request = https.request; 1509 | agent.createSocket = createSecureSocket; 1510 | agent.defaultPort = 443; 1511 | return agent; 1512 | } 1513 | 1514 | 1515 | function TunnelingAgent(options) { 1516 | var self = this; 1517 | self.options = options || {}; 1518 | self.proxyOptions = self.options.proxy || {}; 1519 | self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets; 1520 | self.requests = []; 1521 | self.sockets = []; 1522 | 1523 | self.on('free', function onFree(socket, host, port, localAddress) { 1524 | var options = toOptions(host, port, localAddress); 1525 | for (var i = 0, len = self.requests.length; i < len; ++i) { 1526 | var pending = self.requests[i]; 1527 | if (pending.host === options.host && pending.port === options.port) { 1528 | // Detect the request to connect same origin server, 1529 | // reuse the connection. 1530 | self.requests.splice(i, 1); 1531 | pending.request.onSocket(socket); 1532 | return; 1533 | } 1534 | } 1535 | socket.destroy(); 1536 | self.removeSocket(socket); 1537 | }); 1538 | } 1539 | util.inherits(TunnelingAgent, events.EventEmitter); 1540 | 1541 | TunnelingAgent.prototype.addRequest = function addRequest(req, host, port, localAddress) { 1542 | var self = this; 1543 | var options = mergeOptions({request: req}, self.options, toOptions(host, port, localAddress)); 1544 | 1545 | if (self.sockets.length >= this.maxSockets) { 1546 | // We are over limit so we'll add it to the queue. 1547 | self.requests.push(options); 1548 | return; 1549 | } 1550 | 1551 | // If we are under maxSockets create a new one. 1552 | self.createSocket(options, function(socket) { 1553 | socket.on('free', onFree); 1554 | socket.on('close', onCloseOrRemove); 1555 | socket.on('agentRemove', onCloseOrRemove); 1556 | req.onSocket(socket); 1557 | 1558 | function onFree() { 1559 | self.emit('free', socket, options); 1560 | } 1561 | 1562 | function onCloseOrRemove(err) { 1563 | self.removeSocket(socket); 1564 | socket.removeListener('free', onFree); 1565 | socket.removeListener('close', onCloseOrRemove); 1566 | socket.removeListener('agentRemove', onCloseOrRemove); 1567 | } 1568 | }); 1569 | }; 1570 | 1571 | TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { 1572 | var self = this; 1573 | var placeholder = {}; 1574 | self.sockets.push(placeholder); 1575 | 1576 | var connectOptions = mergeOptions({}, self.proxyOptions, { 1577 | method: 'CONNECT', 1578 | path: options.host + ':' + options.port, 1579 | agent: false, 1580 | headers: { 1581 | host: options.host + ':' + options.port 1582 | } 1583 | }); 1584 | if (options.localAddress) { 1585 | connectOptions.localAddress = options.localAddress; 1586 | } 1587 | if (connectOptions.proxyAuth) { 1588 | connectOptions.headers = connectOptions.headers || {}; 1589 | connectOptions.headers['Proxy-Authorization'] = 'Basic ' + 1590 | new Buffer(connectOptions.proxyAuth).toString('base64'); 1591 | } 1592 | 1593 | debug('making CONNECT request'); 1594 | var connectReq = self.request(connectOptions); 1595 | connectReq.useChunkedEncodingByDefault = false; // for v0.6 1596 | connectReq.once('response', onResponse); // for v0.6 1597 | connectReq.once('upgrade', onUpgrade); // for v0.6 1598 | connectReq.once('connect', onConnect); // for v0.7 or later 1599 | connectReq.once('error', onError); 1600 | connectReq.end(); 1601 | 1602 | function onResponse(res) { 1603 | // Very hacky. This is necessary to avoid http-parser leaks. 1604 | res.upgrade = true; 1605 | } 1606 | 1607 | function onUpgrade(res, socket, head) { 1608 | // Hacky. 1609 | process.nextTick(function() { 1610 | onConnect(res, socket, head); 1611 | }); 1612 | } 1613 | 1614 | function onConnect(res, socket, head) { 1615 | connectReq.removeAllListeners(); 1616 | socket.removeAllListeners(); 1617 | 1618 | if (res.statusCode !== 200) { 1619 | debug('tunneling socket could not be established, statusCode=%d', 1620 | res.statusCode); 1621 | socket.destroy(); 1622 | var error = new Error('tunneling socket could not be established, ' + 1623 | 'statusCode=' + res.statusCode); 1624 | error.code = 'ECONNRESET'; 1625 | options.request.emit('error', error); 1626 | self.removeSocket(placeholder); 1627 | return; 1628 | } 1629 | if (head.length > 0) { 1630 | debug('got illegal response body from proxy'); 1631 | socket.destroy(); 1632 | var error = new Error('got illegal response body from proxy'); 1633 | error.code = 'ECONNRESET'; 1634 | options.request.emit('error', error); 1635 | self.removeSocket(placeholder); 1636 | return; 1637 | } 1638 | debug('tunneling connection has established'); 1639 | self.sockets[self.sockets.indexOf(placeholder)] = socket; 1640 | return cb(socket); 1641 | } 1642 | 1643 | function onError(cause) { 1644 | connectReq.removeAllListeners(); 1645 | 1646 | debug('tunneling socket could not be established, cause=%s\n', 1647 | cause.message, cause.stack); 1648 | var error = new Error('tunneling socket could not be established, ' + 1649 | 'cause=' + cause.message); 1650 | error.code = 'ECONNRESET'; 1651 | options.request.emit('error', error); 1652 | self.removeSocket(placeholder); 1653 | } 1654 | }; 1655 | 1656 | TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { 1657 | var pos = this.sockets.indexOf(socket) 1658 | if (pos === -1) { 1659 | return; 1660 | } 1661 | this.sockets.splice(pos, 1); 1662 | 1663 | var pending = this.requests.shift(); 1664 | if (pending) { 1665 | // If we have pending requests and a socket gets closed a new one 1666 | // needs to be created to take over in the pool for the one that closed. 1667 | this.createSocket(pending, function(socket) { 1668 | pending.request.onSocket(socket); 1669 | }); 1670 | } 1671 | }; 1672 | 1673 | function createSecureSocket(options, cb) { 1674 | var self = this; 1675 | TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { 1676 | var hostHeader = options.request.getHeader('host'); 1677 | var tlsOptions = mergeOptions({}, self.options, { 1678 | socket: socket, 1679 | servername: hostHeader ? hostHeader.replace(/:.*$/, '') : options.host 1680 | }); 1681 | 1682 | // 0 is dummy port for v0.6 1683 | var secureSocket = tls.connect(0, tlsOptions); 1684 | self.sockets[self.sockets.indexOf(socket)] = secureSocket; 1685 | cb(secureSocket); 1686 | }); 1687 | } 1688 | 1689 | 1690 | function toOptions(host, port, localAddress) { 1691 | if (typeof host === 'string') { // since v0.10 1692 | return { 1693 | host: host, 1694 | port: port, 1695 | localAddress: localAddress 1696 | }; 1697 | } 1698 | return host; // for v0.11 or later 1699 | } 1700 | 1701 | function mergeOptions(target) { 1702 | for (var i = 1, len = arguments.length; i < len; ++i) { 1703 | var overrides = arguments[i]; 1704 | if (typeof overrides === 'object') { 1705 | var keys = Object.keys(overrides); 1706 | for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { 1707 | var k = keys[j]; 1708 | if (overrides[k] !== undefined) { 1709 | target[k] = overrides[k]; 1710 | } 1711 | } 1712 | } 1713 | } 1714 | return target; 1715 | } 1716 | 1717 | 1718 | var debug; 1719 | if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { 1720 | debug = function() { 1721 | var args = Array.prototype.slice.call(arguments); 1722 | if (typeof args[0] === 'string') { 1723 | args[0] = 'TUNNEL: ' + args[0]; 1724 | } else { 1725 | args.unshift('TUNNEL:'); 1726 | } 1727 | console.error.apply(console, args); 1728 | } 1729 | } else { 1730 | debug = function() {}; 1731 | } 1732 | exports.debug = debug; // for test 1733 | 1734 | 1735 | /***/ }), 1736 | 1737 | /***/ 491: 1738 | /***/ ((module) => { 1739 | 1740 | "use strict"; 1741 | module.exports = require("assert"); 1742 | 1743 | /***/ }), 1744 | 1745 | /***/ 361: 1746 | /***/ ((module) => { 1747 | 1748 | "use strict"; 1749 | module.exports = require("events"); 1750 | 1751 | /***/ }), 1752 | 1753 | /***/ 147: 1754 | /***/ ((module) => { 1755 | 1756 | "use strict"; 1757 | module.exports = require("fs"); 1758 | 1759 | /***/ }), 1760 | 1761 | /***/ 685: 1762 | /***/ ((module) => { 1763 | 1764 | "use strict"; 1765 | module.exports = require("http"); 1766 | 1767 | /***/ }), 1768 | 1769 | /***/ 687: 1770 | /***/ ((module) => { 1771 | 1772 | "use strict"; 1773 | module.exports = require("https"); 1774 | 1775 | /***/ }), 1776 | 1777 | /***/ 808: 1778 | /***/ ((module) => { 1779 | 1780 | "use strict"; 1781 | module.exports = require("net"); 1782 | 1783 | /***/ }), 1784 | 1785 | /***/ 37: 1786 | /***/ ((module) => { 1787 | 1788 | "use strict"; 1789 | module.exports = require("os"); 1790 | 1791 | /***/ }), 1792 | 1793 | /***/ 17: 1794 | /***/ ((module) => { 1795 | 1796 | "use strict"; 1797 | module.exports = require("path"); 1798 | 1799 | /***/ }), 1800 | 1801 | /***/ 781: 1802 | /***/ ((module) => { 1803 | 1804 | "use strict"; 1805 | module.exports = require("stream"); 1806 | 1807 | /***/ }), 1808 | 1809 | /***/ 576: 1810 | /***/ ((module) => { 1811 | 1812 | "use strict"; 1813 | module.exports = require("string_decoder"); 1814 | 1815 | /***/ }), 1816 | 1817 | /***/ 404: 1818 | /***/ ((module) => { 1819 | 1820 | "use strict"; 1821 | module.exports = require("tls"); 1822 | 1823 | /***/ }), 1824 | 1825 | /***/ 837: 1826 | /***/ ((module) => { 1827 | 1828 | "use strict"; 1829 | module.exports = require("util"); 1830 | 1831 | /***/ }) 1832 | 1833 | /******/ }); 1834 | /************************************************************************/ 1835 | /******/ // The module cache 1836 | /******/ var __webpack_module_cache__ = {}; 1837 | /******/ 1838 | /******/ // The require function 1839 | /******/ function __nccwpck_require__(moduleId) { 1840 | /******/ // Check if module is in cache 1841 | /******/ var cachedModule = __webpack_module_cache__[moduleId]; 1842 | /******/ if (cachedModule !== undefined) { 1843 | /******/ return cachedModule.exports; 1844 | /******/ } 1845 | /******/ // Create a new module (and put it into the cache) 1846 | /******/ var module = __webpack_module_cache__[moduleId] = { 1847 | /******/ // no module.id needed 1848 | /******/ // no module.loaded needed 1849 | /******/ exports: {} 1850 | /******/ }; 1851 | /******/ 1852 | /******/ // Execute the module function 1853 | /******/ var threw = true; 1854 | /******/ try { 1855 | /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); 1856 | /******/ threw = false; 1857 | /******/ } finally { 1858 | /******/ if(threw) delete __webpack_module_cache__[moduleId]; 1859 | /******/ } 1860 | /******/ 1861 | /******/ // Return the exports of the module 1862 | /******/ return module.exports; 1863 | /******/ } 1864 | /******/ 1865 | /************************************************************************/ 1866 | /******/ /* webpack/runtime/compat */ 1867 | /******/ 1868 | /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; 1869 | /******/ 1870 | /************************************************************************/ 1871 | var __webpack_exports__ = {}; 1872 | // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. 1873 | (() => { 1874 | const core = __nccwpck_require__(186); 1875 | const lineReader = __nccwpck_require__(752); 1876 | const fs = __nccwpck_require__(147); 1877 | 1878 | 1879 | try { 1880 | const regex = /(\s*[\w\d]+_test.go:\d+:)(.*?)(Test:\s+Test[\w\d]*?\S+)/gu; // Extracts only the failure from the logs (including whitespace) 1881 | 1882 | const testResultsPath = core.getInput('test-results'); 1883 | const customPackageName = core.getInput('package-name'); 1884 | const workingDirectory = core.getInput('working-directory'); 1885 | 1886 | if (!fs.existsSync(testResultsPath)) { 1887 | core.warning( 1888 | `No file was found with the provided path: ${testResultsPath}.` 1889 | ) 1890 | return 1891 | } 1892 | 1893 | let obj = {}; 1894 | let lr = new lineReader(testResultsPath); 1895 | lr.on('line', function (line) { 1896 | const currentLine = JSON.parse(line); 1897 | const testName = currentLine.Test; 1898 | if (typeof testName === "undefined") { 1899 | return; 1900 | } 1901 | 1902 | let output = currentLine.Output; 1903 | if (typeof output === "undefined") { 1904 | return; 1905 | } 1906 | output = output.replace("\n", "%0A").replace("\r", "%0D") 1907 | // Strip github.com/owner/repo package from the path by default 1908 | let packageName = currentLine.Package.split("/").slice(3).join("/"); 1909 | // If custom package is provided, strip custom package name from the path 1910 | if (customPackageName !== "") { 1911 | if (!currentLine.Package.startsWith(customPackageName)) { 1912 | core.warning( 1913 | `Expected ${currentLine.Package} to start with ${customPackageName} since "package-name" was provided.` 1914 | ) 1915 | } else { 1916 | packageName = currentLine.Package.replace(customPackageName + "/", "") 1917 | } 1918 | } 1919 | if (workingDirectory !== "") { 1920 | packageName = workingDirectory + "/" + packageName 1921 | } 1922 | let newEntry = packageName + "/" + testName; 1923 | if (!obj.hasOwnProperty(newEntry)) { 1924 | obj[newEntry] = output; 1925 | } else { 1926 | obj[newEntry] += output; 1927 | } 1928 | }); 1929 | lr.on('end', function () { 1930 | for (const [key, value] of Object.entries(obj)) { 1931 | if (value.includes("FAIL") && value.includes("_test.go")) { 1932 | var result; 1933 | while ((result = regex.exec(value)) !== null) { 1934 | const parts = result[0].split(":"); 1935 | const file = key.split("/").slice(0, -2).join("/") + "/" + parts[0].trimStart(); 1936 | const lineNumber = parts[1]; 1937 | core.info(`::error file=${file},line=${lineNumber}::${result[0]}`); 1938 | } 1939 | } 1940 | } 1941 | }); 1942 | } catch (error) { 1943 | core.setFailed(error.message); 1944 | } 1945 | 1946 | })(); 1947 | 1948 | module.exports = __webpack_exports__; 1949 | /******/ })() 1950 | ; --------------------------------------------------------------------------------