├── .github └── workflows │ └── dispatch.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── action.yml ├── dist ├── LICENSE ├── index.js ├── index.js.map ├── lib │ └── binding │ │ └── napi-v3-darwin-x64 │ │ └── node_sqlite3.node ├── package.json ├── post │ └── index.js ├── pre │ └── index.js └── sourcemap-register.js ├── docs └── logo.png ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── backends │ ├── http.test.ts │ ├── http.ts │ └── sql.ts ├── config.test.ts ├── config.ts ├── git.ts ├── main.ts └── post.ts └── tsconfig.json /.github/workflows/dispatch.yml: -------------------------------------------------------------------------------- 1 | name: Repo Events Repository Dispatch 2 | 3 | on: 4 | - issues 5 | - issue_comment 6 | - pull_request 7 | 8 | jobs: 9 | preflight-job: 10 | name: Dispatch 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Print Outputs 14 | env: 15 | outputs: ${{ toJSON(github) }} 16 | run: | 17 | echo outputs: $outputs 18 | - name: Repository Dispatch 19 | uses: peter-evans/repository-dispatch@v1 20 | with: 21 | token: ${{ secrets.PAT }} 22 | repository: githubocto/next-devex-workflows # repo to send event to 23 | event-type: repoevents # name of the custom event 24 | client-payload: '{"event": ${{ toJSON(github) }}}' 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .github/workflows 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | lib/* 78 | .DS_Store 79 | 80 | #husky 81 | .husky/.gitignore -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run dist 5 | git add dist/* -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "semi": false, 4 | "singleQuote": true 5 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/dist": true, 4 | "**/lib": true 5 | }, 6 | "editor.formatOnSave": true 7 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 GitHub OCTO 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 |

2 | 3 |

4 | 5 |

6 | 7 | 8 |

9 | 10 | # Flat Data GitHub Action 11 | 12 | 👉🏽 👉🏽 👉🏽 **Full writeup**: [Flat Data Project](https://octo.github.com/projects/flat-data) 👈🏽 👈🏽 👈🏽 13 | 14 | Flat Data is a GitHub action which makes it easy to fetch data and commit it to your repository as flatfiles. The action is intended to be run on a schedule, retrieving data from any supported target and creating a commit if there is any change to the fetched data. Flat Data builds on the [“git scraping” approach pioneered by Simon Willison](https://simonwillison.net/2020/Oct/9/git-scraping/) to offer a simple pattern for bringing working datasets into your repositories and versioning them, because developing against local datasets is faster and easier than working with data over the wire. 15 | 16 | ✨ Best used in tandem with the [Flat Editor VS Code Extension](https://marketplace.visualstudio.com/items?itemName=GitHubOCTO.flat). 17 | 18 | ## Why would I want to use this? 19 | 20 | Flat Data aims to simplify everyday data acquisition and cleanup tasks. It runs on GitHub Actions, so there's no infrastructure to provision and monitor. Each Flat workflow fetches the data you specify, and optionally executes a postprocessing script on the fetched data. The resulting data is committed to your repository if the new data is different, with a commit message summarizing the changes. Flat workflows usually run on a periodic timer, but can be triggered by a variety of stimuli, like changes to your code, or manual triggers. That's it! No complicated job dependency graphs or orchestrators. No dependencies, libraries, or package managers. No new mental model to learn and incorporate. Just evergreen data, right in your repo. 21 | 22 | [Read more in our writeup](https://octo.github.com/projects/flat-data). 23 | 24 | ## Examples 25 | 26 | Check out our [example repositories](https://github.com/githubocto?q=flat-demo&type=&language=&sort=). 27 | 28 | ## Usage 29 | 30 | ### Option 1: Flat Editor VSCode Extension 31 | 32 | The easiest way to get a Flat Data action up and running is with the accompanying [Flat Editor VSCode Extension](https://marketplace.visualstudio.com/items?itemName=GitHubOCTO.flat) which helps you author Flat yml files. 33 | 34 | To use it, [install the extension](https://marketplace.visualstudio.com/items?itemName=GitHubOCTO.flat) and then invoke `Flat Editor` from the command palette within VSCode (Mac: ⌘⇧P, Others:ctrl-shift-P). 35 | 36 | ### Option 2: Manually create a GitHub Actions workflow yml file 37 | 38 | In the repository where you wish to fetch data, create `.github/workflows/flat.yml`. The following example will fetch a URL every thirty minutes and commit the response, but only if the response has changed since the last commit. 39 | 40 | ```yaml 41 | name: Flat 42 | 43 | on: 44 | push: 45 | branches: 46 | - main 47 | workflow_dispatch: 48 | schedule: 49 | - cron: '*/30 * * * *' 50 | 51 | jobs: 52 | scheduled: 53 | runs-on: ubuntu-latest 54 | steps: 55 | # This step installs Deno, which is a new Javascript runtime that improves on Node. Can be used for an optional postprocessing step 56 | - name: Setup deno 57 | uses: denoland/setup-deno@main 58 | with: 59 | deno-version: v1.10.x 60 | # Check out the repository so it can read the files inside of it and do other operations 61 | - name: Check out repo 62 | uses: actions/checkout@v2 63 | # The Flat Action step. We fetch the data in the http_url and save it as downloaded_filename 64 | - name: Fetch data 65 | uses: githubocto/flat@v3 66 | with: 67 | http_url: # THE URL YOU WISH TO FETCH GOES HERE 68 | downloaded_filename: # The http_url gets saved and renamed in our repository. Example: data.json, data.csv, image.png 69 | ``` 70 | 71 | Note that the `schedule` parameter affects the overall workflow, which may contain other jobs and steps beyond Flat. 72 | 73 | The `schedule` parameter uses [crontab format](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#schedule). There's a [library of useful examples](https://crontab.guru/examples.html) and an interactive playground on [Crontab guru](https://crontab.guru). 74 | 75 | ## Inputs 76 | 77 | The action currently has two fetching modes: 78 | 79 | - `http`: GETs a supplied URL 80 | - `sql`: Queries a SQL datastore 81 | 82 | These two modes are exclusive; you cannot mix settings for these two in one Flat step for a workflow job. 83 | 84 | ### HTTP Mode 85 | 86 | #### `http_url` 87 | 88 | A URL from which to fetch data. Specifying this input puts Flat into `http` mode. 89 | 90 | This can be any endpoint: a json, csv, png, zip, xlsx, etc. 91 | 92 | #### `authorization` (optional) 93 | 94 | A string used for authorizing the HTTP request. The value of this field is passed in as a header w/ the `authorization` key. 95 | 96 | For example, if this field is set to `Bearer abc123` then the following header is sent with each request: 97 | 98 | ```json 99 | { 100 | "Authorization": "Bearer abc123" 101 | } 102 | ``` 103 | 104 | #### `axios_config` (optional) 105 | 106 | Under the hood, the `http` backend uses [Axios](https://github.com/axios/axios) for data fetching. By default, Flat assumes you're interested in using the `GET` method to fetch data, but if you'd like to `POST` (e.g., sending a GraphQL query), the `axios_config` option allows you to override this behavior. 107 | 108 | Specifically, the `axios_config` parameter should reflect a relative path to a `.json` file in your repository. This JSON file should mirror the shape of [Axios' request config parameters](https://github.com/axios/axios#request-config), with a few notable exceptions. 109 | 110 | - `url` and `baseURL` will both be ignored, as the `http_url` specified above will take precedence. 111 | - `headers` will be merged in with the authorization header described by the `authorization` parameter above. Please do not put secret keys here, as they will be stored in plain text! 112 | - All `function` parameters will be ignored (e.g., `transformRequest`). 113 | - The response type is always set to `responseType: 'stream'` in the background. 114 | 115 | An example `axios_config` might look thusly if you were interested in hitting GitHub's GraphQL API ([here is a demo](https://github.com/githubocto/flat-demo-graphql)) 👇 116 | 117 | ```json 118 | { 119 | "method": "post", 120 | "data": { 121 | "query": "query { repository(owner:\"octocat\", name:\"Hello-World\") { issues(last:20, states:CLOSED) { edges { node { title url labels(first:5) { edges { node { name } } } } } } } }" 122 | } 123 | } 124 | ``` 125 | 126 | We advise escaping double quotes like `\"` in your JSON file. 127 | 128 | #### `downloaded_filename` 129 | 130 | The name of the file to store data fetched by Flat. 131 | 132 | In `http` mode this can be anything. This can be any endpoint: a json, csv, txt, png, zip, xlsx, etc. file 133 | 134 | #### `postprocess` (optional) 135 | 136 | A path to a local Deno javascript or typescript file for postprocessing the `downloaded_filename` file. Read more in the ["Postprocessing section"](https://github.com/githubocto/flat#postprocessing). 137 | 138 | #### `mask` (optional) 139 | 140 | If your `http_url` string contains secrets, you can choose to mask it from the commit message. You have two options: 141 | 142 | **Option 1**: use a string boolean 143 | 144 | `mask: true # removes the source entirely from the commit message, defaults to false` 145 | 146 | **Option 2**: use a string array with each secret to mask 147 | 148 | `mask: '["${{ secrets.SECRET1 }}", "${{ secrets.SECRET2 }}"]'` 149 | 150 | ### SQL Mode 151 | 152 | #### `sql_connstring` 153 | 154 | A URI-style database connection string. Flat will use this connection string to connect to the database and issue the query. 155 | 156 | > ⚠️ Don't write secrets into your workflow.yml! 157 | > 158 | > Most connection strings contain an authentication secret like a username and password. GitHub provides an encrypted vault for secrets like these which can be used by the action when it runs. [Create a secret](https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository) on the repository where the Flat action will run, and use that secret in your workflow.yaml like so: 159 | > 160 | > ``` 161 | > sql_connstring: ${{secrets.NAME_OF_THE_CREATED_SECRET}} 162 | > ``` 163 | > 164 | > If you're using the [flat-vscode extension](https://github.com/githubocto/flat-vscode), this is handled for you. 165 | 166 | #### `sql_queryfile` 167 | 168 | The pathname of the file containing the SQL query that will be issued to the database. Defaults to `.github/workflows/query.sql`. This path is relative to the root of your repo. 169 | 170 | #### `downloaded_filename` 171 | 172 | The name of the file to store data fetched by Flat. 173 | 174 | In `sql` mode this should be one of `csv` or `json`. SQL query results will be serialized to disk in the specified format. 175 | 176 | > ⚠️ While the JSON is not pretty-printed, CSV is often a more efficient serialization for tabular data. 177 | 178 | #### `typeorm_config` (optional) 179 | 180 | A JSON string representing a configuration passed to [TypeORMs createConnection function](https://orkhan.gitbook.io/typeorm/docs/connection-api#main-api). 181 | 182 | A common use case for this value is connecting your [Flat action to a Heroku database](https://github.com/typeorm/typeorm/issues/278). 183 | 184 | For instance, you can pass the following configuration string to your Flat action in order to connect to a Heroku Postgres database. 185 | 186 | ```yaml 187 | typeorm_config: '{"ssl":true,"extra":{"ssl":{"rejectUnauthorized":false}}}' 188 | ``` 189 | 190 | #### `postprocess` (optional) 191 | 192 | A path to a local Deno javascript or typescript file for postprocessing the `downloaded_filename` file. Read more in the ["Postprocessing section"](https://github.com/githubocto/flat#postprocessing). 193 | 194 | ## Outputs 195 | 196 | ### `delta_bytes` 197 | 198 | A signed number describing the number of bytes that changed in this run. If the new data is smaller than the existing, committed data, this will be a negative number. 199 | 200 | ## Postprocessing 201 | 202 | You can add a `postprocess` input in the Action which is path to a [deno](https://deno.land) Javascript or Typescript script that will be invoked to postprocess your data after it is fetched. This path is relative to the root of your repo. 203 | 204 | The script can use either `Deno.args[0]` or the name of the `downloaded_filename` to access the file fetched by Flat Data. 205 | 206 | ```ts 207 | import { readJSON, writeJSON } from 'https://deno.land/x/flat/mod.ts' 208 | 209 | // The filename is the first invocation argument 210 | const filename = Deno.args[0] // Same name as downloaded_filename 211 | const data = await readJSON(filename) 212 | 213 | // Pluck a specific key off 214 | // and write it out to a different file 215 | // Careful! any uncaught errors and the workflow will fail, committing nothing. 216 | const newfile = `subset_of_${filename}` 217 | await writeJSON(newfile, data.path.to.something) 218 | ``` 219 | 220 | You can use `console.log()` as much as you like within your postprocessing script; the results should show up in your actions log. 221 | 222 | ### Why Deno? 223 | 224 | Deno's import-by-url model makes it easy to author lightweight scripts that can include dependencies without forcing you to set up a bundler. 225 | 226 | ### How is my script invoked? 227 | 228 | The postprocessing script is invoked with `deno run -q -A --unstable {your script} {your fetched data file}`. Note that the `-A` grants your script full permissions to access network, disk — everything! Make sure you trust any dependencies you pull in, as they aren't restricted. We will likely revisit this in the future with another setting that specifies which permissions to grant deno. 229 | 230 | ### How do I do ...? 231 | 232 | The learn more about the possibilities for postprocessing check out our [helper and examples postprocessing repo](https://github.com/githubocto/flat-postprocessing). 233 | 234 | ## Building / Releasing 235 | 236 | 1. `npm run dist` and commit the built output (yes, you read that right) 237 | 2. Bump whatever you want to bump in the `package.json` version field 238 | 3. Merge `main` into `vMAJOR` branch. `git checkout vMAJOR && git merge main` 239 | 240 | - If this is a new major version, create the branch. `git checkout -b vMAJOR` 241 | - Push the branch. `git push --set-upstream origin vMAJOR` 242 | 243 | 4. Create a new tag for the version: `git tag -f vMAJOR.MINOR.PATCH` 244 | 5. Push main `git checkout main && git push` 245 | 6. Navigate to https://github.com/githubocto/flat/tags and cut a new release from the tag you just pushed! 246 | 247 | ## Issues 248 | 249 | If you run into any trouble or have questions, feel free to [open an issue](https://github.com/githubocto/flat/issues). 250 | 251 | ❤️ GitHub OCTO 252 | 253 | ## License 254 | 255 | [MIT](LICENSE) 256 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Flat Data' 2 | description: 'The GitHub action which powers data fetching for Flat' 3 | author: 'GitHub OCTO' 4 | inputs: 5 | axios_config: 6 | description: 'A path (relative to the root of your repo) of a JSON file containing a subset of Axios configuration' 7 | required: false 8 | downloaded_filename: 9 | description: 'The filename to use for writing data.' 10 | required: false 11 | http_url: 12 | description: 'A URL containing data to fetch.' 13 | required: false 14 | authorization: 15 | description: 'A string to send as a header for authorizing API requests.' 16 | required: false 17 | mask: 18 | description: 'A string array of secrets to strip from the http_url or a string boolean' 19 | required: false 20 | sql_connstring: 21 | description: 'A connection string for making a SQL query.' 22 | required: false 23 | sql_queryfile: 24 | description: 'A path (relative to the root of your repo) of a SQL query file to execute for fetching data.' 25 | required: false 26 | default: '.github/workflows/query.sql' 27 | typeorm_config: 28 | description: 'A JSON string representing a configuration passed to TypeORMs createConnection function' 29 | required: false 30 | postprocess: 31 | description: 'A path (relative to the root of your repo) or a URL to a deno postprocessing script.' 32 | required: false 33 | outputs: 34 | delta_bytes: # size of changed data 35 | description: The overall number of bytes changed in the output data this run (current size - previous size) 36 | runs: 37 | using: 'node16' 38 | main: 'dist/index.js' 39 | post: 'dist/post/index.js' 40 | branding: 41 | color: 'purple' 42 | icon: 'download-cloud' 43 | -------------------------------------------------------------------------------- /dist/lib/binding/napi-v3-darwin-x64/node_sqlite3.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/githubocto/flat/cea5ee43fce40ef71501bf5724a00d45db11641d/dist/lib/binding/napi-v3-darwin-x64/node_sqlite3.node -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sqlite3", 3 | "description": "Asynchronous, non-blocking SQLite3 bindings", 4 | "version": "5.1.6", 5 | "homepage": "https://github.com/TryGhost/node-sqlite3", 6 | "author": { 7 | "name": "Mapbox", 8 | "url": "https://mapbox.com/" 9 | }, 10 | "binary": { 11 | "module_name": "node_sqlite3", 12 | "module_path": "./lib/binding/napi-v{napi_build_version}-{platform}-{libc}-{arch}", 13 | "host": "https://github.com/TryGhost/node-sqlite3/releases/download/", 14 | "remote_path": "v{version}", 15 | "package_name": "napi-v{napi_build_version}-{platform}-{libc}-{arch}.tar.gz", 16 | "napi_versions": [ 17 | 3, 18 | 6 19 | ] 20 | }, 21 | "contributors": [ 22 | "Konstantin Käfer ", 23 | "Dane Springmeyer ", 24 | "Will White ", 25 | "Orlando Vazquez ", 26 | "Artem Kustikov ", 27 | "Eric Fredricksen ", 28 | "John Wright ", 29 | "Ryan Dahl ", 30 | "Tom MacWright ", 31 | "Carter Thaxton ", 32 | "Audrius Kažukauskas ", 33 | "Johannes Schauer ", 34 | "Nathan Rajlich ", 35 | "AJ ONeal ", 36 | "Mithgol", 37 | "Ben Noordhuis " 38 | ], 39 | "files": [ 40 | "binding.gyp", 41 | "deps/", 42 | "lib/*.js", 43 | "lib/*.d.ts", 44 | "src/" 45 | ], 46 | "repository": { 47 | "type": "git", 48 | "url": "https://github.com/TryGhost/node-sqlite3.git" 49 | }, 50 | "dependencies": { 51 | "@mapbox/node-pre-gyp": "^1.0.0", 52 | "node-addon-api": "^4.2.0", 53 | "tar": "^6.1.11" 54 | }, 55 | "devDependencies": { 56 | "eslint": "6.8.0", 57 | "mocha": "7.2.0", 58 | "node-pre-gyp-github": "1.4.4" 59 | }, 60 | "peerDependencies": { 61 | "node-gyp": "8.x" 62 | }, 63 | "peerDependenciesMeta": { 64 | "node-gyp": { 65 | "optional": true 66 | } 67 | }, 68 | "optionalDependencies": { 69 | "node-gyp": "8.x" 70 | }, 71 | "scripts": { 72 | "build": "node-pre-gyp build", 73 | "build:debug": "node-pre-gyp build --debug", 74 | "install": "node-pre-gyp install --fallback-to-build", 75 | "pretest": "node test/support/createdb.js", 76 | "test": "mocha -R spec --timeout 480000", 77 | "pack": "node-pre-gyp package" 78 | }, 79 | "license": "BSD-3-Clause", 80 | "keywords": [ 81 | "sql", 82 | "sqlite", 83 | "sqlite3", 84 | "database" 85 | ], 86 | "main": "./lib/sqlite3", 87 | "types": "./lib/sqlite3.d.ts", 88 | "renovate": { 89 | "extends": [ 90 | "@tryghost:base" 91 | ] 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /dist/post/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (() => { // webpackBootstrap 3 | /******/ "use strict"; 4 | /******/ var __webpack_modules__ = ({ 5 | 6 | /***/ 95: 7 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 8 | 9 | 10 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 11 | if (k2 === undefined) k2 = k; 12 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 13 | }) : (function(o, m, k, k2) { 14 | if (k2 === undefined) k2 = k; 15 | o[k2] = m[k]; 16 | })); 17 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 18 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 19 | }) : function(o, v) { 20 | o["default"] = v; 21 | }); 22 | var __importStar = (this && this.__importStar) || function (mod) { 23 | if (mod && mod.__esModule) return mod; 24 | var result = {}; 25 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 26 | __setModuleDefault(result, mod); 27 | return result; 28 | }; 29 | Object.defineProperty(exports, "__esModule", ({ value: true })); 30 | const core = __importStar(__nccwpck_require__(186)); 31 | const exec_1 = __nccwpck_require__(514); 32 | const run = async () => { 33 | core.startGroup('Post cleanup script'); 34 | if (process.env.HAS_RUN_POST_JOB) { 35 | core.info('Files already committed'); 36 | core.endGroup(); 37 | return; 38 | } 39 | const files = JSON.parse(process.env.FILES || '[]'); 40 | const date = new Date().toISOString(); 41 | const meta = JSON.stringify({ 42 | date, 43 | files, 44 | }, undefined, 2); 45 | const msg = `Flat: latest data (${date})`; 46 | // Don't want to commit if there aren't any files changed! 47 | if (!files.length) 48 | return; 49 | // these should already be staged, in main.ts 50 | core.info(`Committing "${msg}"`); 51 | core.debug(meta); 52 | await exec_1.exec('git', ['commit', '-m', msg + '\n' + meta]); 53 | await exec_1.exec('git', ['push']); 54 | core.info(`Pushed!`); 55 | core.exportVariable('HAS_RUN_POST_JOB', 'true'); 56 | core.endGroup(); 57 | }; 58 | run().catch(error => { 59 | core.setFailed('Post script failed! ' + error.message); 60 | }); 61 | 62 | 63 | /***/ }), 64 | 65 | /***/ 351: 66 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 67 | 68 | 69 | var __importStar = (this && this.__importStar) || function (mod) { 70 | if (mod && mod.__esModule) return mod; 71 | var result = {}; 72 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 73 | result["default"] = mod; 74 | return result; 75 | }; 76 | Object.defineProperty(exports, "__esModule", ({ value: true })); 77 | const os = __importStar(__nccwpck_require__(87)); 78 | const utils_1 = __nccwpck_require__(278); 79 | /** 80 | * Commands 81 | * 82 | * Command Format: 83 | * ::name key=value,key=value::message 84 | * 85 | * Examples: 86 | * ::warning::This is the message 87 | * ::set-env name=MY_VAR::some value 88 | */ 89 | function issueCommand(command, properties, message) { 90 | const cmd = new Command(command, properties, message); 91 | process.stdout.write(cmd.toString() + os.EOL); 92 | } 93 | exports.issueCommand = issueCommand; 94 | function issue(name, message = '') { 95 | issueCommand(name, {}, message); 96 | } 97 | exports.issue = issue; 98 | const CMD_STRING = '::'; 99 | class Command { 100 | constructor(command, properties, message) { 101 | if (!command) { 102 | command = 'missing.command'; 103 | } 104 | this.command = command; 105 | this.properties = properties; 106 | this.message = message; 107 | } 108 | toString() { 109 | let cmdStr = CMD_STRING + this.command; 110 | if (this.properties && Object.keys(this.properties).length > 0) { 111 | cmdStr += ' '; 112 | let first = true; 113 | for (const key in this.properties) { 114 | if (this.properties.hasOwnProperty(key)) { 115 | const val = this.properties[key]; 116 | if (val) { 117 | if (first) { 118 | first = false; 119 | } 120 | else { 121 | cmdStr += ','; 122 | } 123 | cmdStr += `${key}=${escapeProperty(val)}`; 124 | } 125 | } 126 | } 127 | } 128 | cmdStr += `${CMD_STRING}${escapeData(this.message)}`; 129 | return cmdStr; 130 | } 131 | } 132 | function escapeData(s) { 133 | return utils_1.toCommandValue(s) 134 | .replace(/%/g, '%25') 135 | .replace(/\r/g, '%0D') 136 | .replace(/\n/g, '%0A'); 137 | } 138 | function escapeProperty(s) { 139 | return utils_1.toCommandValue(s) 140 | .replace(/%/g, '%25') 141 | .replace(/\r/g, '%0D') 142 | .replace(/\n/g, '%0A') 143 | .replace(/:/g, '%3A') 144 | .replace(/,/g, '%2C'); 145 | } 146 | //# sourceMappingURL=command.js.map 147 | 148 | /***/ }), 149 | 150 | /***/ 186: 151 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 152 | 153 | 154 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 155 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 156 | return new (P || (P = Promise))(function (resolve, reject) { 157 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 158 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 159 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 160 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 161 | }); 162 | }; 163 | var __importStar = (this && this.__importStar) || function (mod) { 164 | if (mod && mod.__esModule) return mod; 165 | var result = {}; 166 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 167 | result["default"] = mod; 168 | return result; 169 | }; 170 | Object.defineProperty(exports, "__esModule", ({ value: true })); 171 | const command_1 = __nccwpck_require__(351); 172 | const file_command_1 = __nccwpck_require__(717); 173 | const utils_1 = __nccwpck_require__(278); 174 | const os = __importStar(__nccwpck_require__(87)); 175 | const path = __importStar(__nccwpck_require__(622)); 176 | /** 177 | * The code to exit an action 178 | */ 179 | var ExitCode; 180 | (function (ExitCode) { 181 | /** 182 | * A code indicating that the action was successful 183 | */ 184 | ExitCode[ExitCode["Success"] = 0] = "Success"; 185 | /** 186 | * A code indicating that the action was a failure 187 | */ 188 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 189 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 190 | //----------------------------------------------------------------------- 191 | // Variables 192 | //----------------------------------------------------------------------- 193 | /** 194 | * Sets env variable for this action and future actions in the job 195 | * @param name the name of the variable to set 196 | * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify 197 | */ 198 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 199 | function exportVariable(name, val) { 200 | const convertedVal = utils_1.toCommandValue(val); 201 | process.env[name] = convertedVal; 202 | const filePath = process.env['GITHUB_ENV'] || ''; 203 | if (filePath) { 204 | const delimiter = '_GitHubActionsFileCommandDelimeter_'; 205 | const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; 206 | file_command_1.issueCommand('ENV', commandValue); 207 | } 208 | else { 209 | command_1.issueCommand('set-env', { name }, convertedVal); 210 | } 211 | } 212 | exports.exportVariable = exportVariable; 213 | /** 214 | * Registers a secret which will get masked from logs 215 | * @param secret value of the secret 216 | */ 217 | function setSecret(secret) { 218 | command_1.issueCommand('add-mask', {}, secret); 219 | } 220 | exports.setSecret = setSecret; 221 | /** 222 | * Prepends inputPath to the PATH (for this action and future actions) 223 | * @param inputPath 224 | */ 225 | function addPath(inputPath) { 226 | const filePath = process.env['GITHUB_PATH'] || ''; 227 | if (filePath) { 228 | file_command_1.issueCommand('PATH', inputPath); 229 | } 230 | else { 231 | command_1.issueCommand('add-path', {}, inputPath); 232 | } 233 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 234 | } 235 | exports.addPath = addPath; 236 | /** 237 | * Gets the value of an input. The value is also trimmed. 238 | * 239 | * @param name name of the input to get 240 | * @param options optional. See InputOptions. 241 | * @returns string 242 | */ 243 | function getInput(name, options) { 244 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 245 | if (options && options.required && !val) { 246 | throw new Error(`Input required and not supplied: ${name}`); 247 | } 248 | return val.trim(); 249 | } 250 | exports.getInput = getInput; 251 | /** 252 | * Sets the value of an output. 253 | * 254 | * @param name name of the output to set 255 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 256 | */ 257 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 258 | function setOutput(name, value) { 259 | command_1.issueCommand('set-output', { name }, value); 260 | } 261 | exports.setOutput = setOutput; 262 | /** 263 | * Enables or disables the echoing of commands into stdout for the rest of the step. 264 | * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 265 | * 266 | */ 267 | function setCommandEcho(enabled) { 268 | command_1.issue('echo', enabled ? 'on' : 'off'); 269 | } 270 | exports.setCommandEcho = setCommandEcho; 271 | //----------------------------------------------------------------------- 272 | // Results 273 | //----------------------------------------------------------------------- 274 | /** 275 | * Sets the action status to failed. 276 | * When the action exits it will be with an exit code of 1 277 | * @param message add error issue message 278 | */ 279 | function setFailed(message) { 280 | process.exitCode = ExitCode.Failure; 281 | error(message); 282 | } 283 | exports.setFailed = setFailed; 284 | //----------------------------------------------------------------------- 285 | // Logging Commands 286 | //----------------------------------------------------------------------- 287 | /** 288 | * Gets whether Actions Step Debug is on or not 289 | */ 290 | function isDebug() { 291 | return process.env['RUNNER_DEBUG'] === '1'; 292 | } 293 | exports.isDebug = isDebug; 294 | /** 295 | * Writes debug message to user log 296 | * @param message debug message 297 | */ 298 | function debug(message) { 299 | command_1.issueCommand('debug', {}, message); 300 | } 301 | exports.debug = debug; 302 | /** 303 | * Adds an error issue 304 | * @param message error issue message. Errors will be converted to string via toString() 305 | */ 306 | function error(message) { 307 | command_1.issue('error', message instanceof Error ? message.toString() : message); 308 | } 309 | exports.error = error; 310 | /** 311 | * Adds an warning issue 312 | * @param message warning issue message. Errors will be converted to string via toString() 313 | */ 314 | function warning(message) { 315 | command_1.issue('warning', message instanceof Error ? message.toString() : message); 316 | } 317 | exports.warning = warning; 318 | /** 319 | * Writes info to log with console.log. 320 | * @param message info message 321 | */ 322 | function info(message) { 323 | process.stdout.write(message + os.EOL); 324 | } 325 | exports.info = info; 326 | /** 327 | * Begin an output group. 328 | * 329 | * Output until the next `groupEnd` will be foldable in this group 330 | * 331 | * @param name The name of the output group 332 | */ 333 | function startGroup(name) { 334 | command_1.issue('group', name); 335 | } 336 | exports.startGroup = startGroup; 337 | /** 338 | * End an output group. 339 | */ 340 | function endGroup() { 341 | command_1.issue('endgroup'); 342 | } 343 | exports.endGroup = endGroup; 344 | /** 345 | * Wrap an asynchronous function call in a group. 346 | * 347 | * Returns the same type as the function itself. 348 | * 349 | * @param name The name of the group 350 | * @param fn The function to wrap in the group 351 | */ 352 | function group(name, fn) { 353 | return __awaiter(this, void 0, void 0, function* () { 354 | startGroup(name); 355 | let result; 356 | try { 357 | result = yield fn(); 358 | } 359 | finally { 360 | endGroup(); 361 | } 362 | return result; 363 | }); 364 | } 365 | exports.group = group; 366 | //----------------------------------------------------------------------- 367 | // Wrapper action state 368 | //----------------------------------------------------------------------- 369 | /** 370 | * Saves state for current action, the state can only be retrieved by this action's post job execution. 371 | * 372 | * @param name name of the state to store 373 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 374 | */ 375 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 376 | function saveState(name, value) { 377 | command_1.issueCommand('save-state', { name }, value); 378 | } 379 | exports.saveState = saveState; 380 | /** 381 | * Gets the value of an state set by this action's main execution. 382 | * 383 | * @param name name of the state to get 384 | * @returns string 385 | */ 386 | function getState(name) { 387 | return process.env[`STATE_${name}`] || ''; 388 | } 389 | exports.getState = getState; 390 | //# sourceMappingURL=core.js.map 391 | 392 | /***/ }), 393 | 394 | /***/ 717: 395 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 396 | 397 | 398 | // For internal use, subject to change. 399 | var __importStar = (this && this.__importStar) || function (mod) { 400 | if (mod && mod.__esModule) return mod; 401 | var result = {}; 402 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 403 | result["default"] = mod; 404 | return result; 405 | }; 406 | Object.defineProperty(exports, "__esModule", ({ value: true })); 407 | // We use any as a valid input type 408 | /* eslint-disable @typescript-eslint/no-explicit-any */ 409 | const fs = __importStar(__nccwpck_require__(747)); 410 | const os = __importStar(__nccwpck_require__(87)); 411 | const utils_1 = __nccwpck_require__(278); 412 | function issueCommand(command, message) { 413 | const filePath = process.env[`GITHUB_${command}`]; 414 | if (!filePath) { 415 | throw new Error(`Unable to find environment variable for file command ${command}`); 416 | } 417 | if (!fs.existsSync(filePath)) { 418 | throw new Error(`Missing file at path: ${filePath}`); 419 | } 420 | fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { 421 | encoding: 'utf8' 422 | }); 423 | } 424 | exports.issueCommand = issueCommand; 425 | //# sourceMappingURL=file-command.js.map 426 | 427 | /***/ }), 428 | 429 | /***/ 278: 430 | /***/ ((__unused_webpack_module, exports) => { 431 | 432 | 433 | // We use any as a valid input type 434 | /* eslint-disable @typescript-eslint/no-explicit-any */ 435 | Object.defineProperty(exports, "__esModule", ({ value: true })); 436 | /** 437 | * Sanitizes an input into a string so it can be passed into issueCommand safely 438 | * @param input input to sanitize into a string 439 | */ 440 | function toCommandValue(input) { 441 | if (input === null || input === undefined) { 442 | return ''; 443 | } 444 | else if (typeof input === 'string' || input instanceof String) { 445 | return input; 446 | } 447 | return JSON.stringify(input); 448 | } 449 | exports.toCommandValue = toCommandValue; 450 | //# sourceMappingURL=utils.js.map 451 | 452 | /***/ }), 453 | 454 | /***/ 514: 455 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 456 | 457 | 458 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 459 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 460 | return new (P || (P = Promise))(function (resolve, reject) { 461 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 462 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 463 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 464 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 465 | }); 466 | }; 467 | var __importStar = (this && this.__importStar) || function (mod) { 468 | if (mod && mod.__esModule) return mod; 469 | var result = {}; 470 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 471 | result["default"] = mod; 472 | return result; 473 | }; 474 | Object.defineProperty(exports, "__esModule", ({ value: true })); 475 | const tr = __importStar(__nccwpck_require__(159)); 476 | /** 477 | * Exec a command. 478 | * Output will be streamed to the live console. 479 | * Returns promise with return code 480 | * 481 | * @param commandLine command to execute (can include additional args). Must be correctly escaped. 482 | * @param args optional arguments for tool. Escaping is handled by the lib. 483 | * @param options optional exec options. See ExecOptions 484 | * @returns Promise exit code 485 | */ 486 | function exec(commandLine, args, options) { 487 | return __awaiter(this, void 0, void 0, function* () { 488 | const commandArgs = tr.argStringToArray(commandLine); 489 | if (commandArgs.length === 0) { 490 | throw new Error(`Parameter 'commandLine' cannot be null or empty.`); 491 | } 492 | // Path to tool to execute should be first arg 493 | const toolPath = commandArgs[0]; 494 | args = commandArgs.slice(1).concat(args || []); 495 | const runner = new tr.ToolRunner(toolPath, args, options); 496 | return runner.exec(); 497 | }); 498 | } 499 | exports.exec = exec; 500 | //# sourceMappingURL=exec.js.map 501 | 502 | /***/ }), 503 | 504 | /***/ 159: 505 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 506 | 507 | 508 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 509 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 510 | return new (P || (P = Promise))(function (resolve, reject) { 511 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 512 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 513 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 514 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 515 | }); 516 | }; 517 | var __importStar = (this && this.__importStar) || function (mod) { 518 | if (mod && mod.__esModule) return mod; 519 | var result = {}; 520 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 521 | result["default"] = mod; 522 | return result; 523 | }; 524 | Object.defineProperty(exports, "__esModule", ({ value: true })); 525 | const os = __importStar(__nccwpck_require__(87)); 526 | const events = __importStar(__nccwpck_require__(614)); 527 | const child = __importStar(__nccwpck_require__(129)); 528 | const path = __importStar(__nccwpck_require__(622)); 529 | const io = __importStar(__nccwpck_require__(436)); 530 | const ioUtil = __importStar(__nccwpck_require__(962)); 531 | /* eslint-disable @typescript-eslint/unbound-method */ 532 | const IS_WINDOWS = process.platform === 'win32'; 533 | /* 534 | * Class for running command line tools. Handles quoting and arg parsing in a platform agnostic way. 535 | */ 536 | class ToolRunner extends events.EventEmitter { 537 | constructor(toolPath, args, options) { 538 | super(); 539 | if (!toolPath) { 540 | throw new Error("Parameter 'toolPath' cannot be null or empty."); 541 | } 542 | this.toolPath = toolPath; 543 | this.args = args || []; 544 | this.options = options || {}; 545 | } 546 | _debug(message) { 547 | if (this.options.listeners && this.options.listeners.debug) { 548 | this.options.listeners.debug(message); 549 | } 550 | } 551 | _getCommandString(options, noPrefix) { 552 | const toolPath = this._getSpawnFileName(); 553 | const args = this._getSpawnArgs(options); 554 | let cmd = noPrefix ? '' : '[command]'; // omit prefix when piped to a second tool 555 | if (IS_WINDOWS) { 556 | // Windows + cmd file 557 | if (this._isCmdFile()) { 558 | cmd += toolPath; 559 | for (const a of args) { 560 | cmd += ` ${a}`; 561 | } 562 | } 563 | // Windows + verbatim 564 | else if (options.windowsVerbatimArguments) { 565 | cmd += `"${toolPath}"`; 566 | for (const a of args) { 567 | cmd += ` ${a}`; 568 | } 569 | } 570 | // Windows (regular) 571 | else { 572 | cmd += this._windowsQuoteCmdArg(toolPath); 573 | for (const a of args) { 574 | cmd += ` ${this._windowsQuoteCmdArg(a)}`; 575 | } 576 | } 577 | } 578 | else { 579 | // OSX/Linux - this can likely be improved with some form of quoting. 580 | // creating processes on Unix is fundamentally different than Windows. 581 | // on Unix, execvp() takes an arg array. 582 | cmd += toolPath; 583 | for (const a of args) { 584 | cmd += ` ${a}`; 585 | } 586 | } 587 | return cmd; 588 | } 589 | _processLineBuffer(data, strBuffer, onLine) { 590 | try { 591 | let s = strBuffer + data.toString(); 592 | let n = s.indexOf(os.EOL); 593 | while (n > -1) { 594 | const line = s.substring(0, n); 595 | onLine(line); 596 | // the rest of the string ... 597 | s = s.substring(n + os.EOL.length); 598 | n = s.indexOf(os.EOL); 599 | } 600 | strBuffer = s; 601 | } 602 | catch (err) { 603 | // streaming lines to console is best effort. Don't fail a build. 604 | this._debug(`error processing line. Failed with error ${err}`); 605 | } 606 | } 607 | _getSpawnFileName() { 608 | if (IS_WINDOWS) { 609 | if (this._isCmdFile()) { 610 | return process.env['COMSPEC'] || 'cmd.exe'; 611 | } 612 | } 613 | return this.toolPath; 614 | } 615 | _getSpawnArgs(options) { 616 | if (IS_WINDOWS) { 617 | if (this._isCmdFile()) { 618 | let argline = `/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`; 619 | for (const a of this.args) { 620 | argline += ' '; 621 | argline += options.windowsVerbatimArguments 622 | ? a 623 | : this._windowsQuoteCmdArg(a); 624 | } 625 | argline += '"'; 626 | return [argline]; 627 | } 628 | } 629 | return this.args; 630 | } 631 | _endsWith(str, end) { 632 | return str.endsWith(end); 633 | } 634 | _isCmdFile() { 635 | const upperToolPath = this.toolPath.toUpperCase(); 636 | return (this._endsWith(upperToolPath, '.CMD') || 637 | this._endsWith(upperToolPath, '.BAT')); 638 | } 639 | _windowsQuoteCmdArg(arg) { 640 | // for .exe, apply the normal quoting rules that libuv applies 641 | if (!this._isCmdFile()) { 642 | return this._uvQuoteCmdArg(arg); 643 | } 644 | // otherwise apply quoting rules specific to the cmd.exe command line parser. 645 | // the libuv rules are generic and are not designed specifically for cmd.exe 646 | // command line parser. 647 | // 648 | // for a detailed description of the cmd.exe command line parser, refer to 649 | // http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912 650 | // need quotes for empty arg 651 | if (!arg) { 652 | return '""'; 653 | } 654 | // determine whether the arg needs to be quoted 655 | const cmdSpecialChars = [ 656 | ' ', 657 | '\t', 658 | '&', 659 | '(', 660 | ')', 661 | '[', 662 | ']', 663 | '{', 664 | '}', 665 | '^', 666 | '=', 667 | ';', 668 | '!', 669 | "'", 670 | '+', 671 | ',', 672 | '`', 673 | '~', 674 | '|', 675 | '<', 676 | '>', 677 | '"' 678 | ]; 679 | let needsQuotes = false; 680 | for (const char of arg) { 681 | if (cmdSpecialChars.some(x => x === char)) { 682 | needsQuotes = true; 683 | break; 684 | } 685 | } 686 | // short-circuit if quotes not needed 687 | if (!needsQuotes) { 688 | return arg; 689 | } 690 | // the following quoting rules are very similar to the rules that by libuv applies. 691 | // 692 | // 1) wrap the string in quotes 693 | // 694 | // 2) double-up quotes - i.e. " => "" 695 | // 696 | // this is different from the libuv quoting rules. libuv replaces " with \", which unfortunately 697 | // doesn't work well with a cmd.exe command line. 698 | // 699 | // note, replacing " with "" also works well if the arg is passed to a downstream .NET console app. 700 | // for example, the command line: 701 | // foo.exe "myarg:""my val""" 702 | // is parsed by a .NET console app into an arg array: 703 | // [ "myarg:\"my val\"" ] 704 | // which is the same end result when applying libuv quoting rules. although the actual 705 | // command line from libuv quoting rules would look like: 706 | // foo.exe "myarg:\"my val\"" 707 | // 708 | // 3) double-up slashes that precede a quote, 709 | // e.g. hello \world => "hello \world" 710 | // hello\"world => "hello\\""world" 711 | // hello\\"world => "hello\\\\""world" 712 | // hello world\ => "hello world\\" 713 | // 714 | // technically this is not required for a cmd.exe command line, or the batch argument parser. 715 | // the reasons for including this as a .cmd quoting rule are: 716 | // 717 | // a) this is optimized for the scenario where the argument is passed from the .cmd file to an 718 | // external program. many programs (e.g. .NET console apps) rely on the slash-doubling rule. 719 | // 720 | // b) it's what we've been doing previously (by deferring to node default behavior) and we 721 | // haven't heard any complaints about that aspect. 722 | // 723 | // note, a weakness of the quoting rules chosen here, is that % is not escaped. in fact, % cannot be 724 | // escaped when used on the command line directly - even though within a .cmd file % can be escaped 725 | // by using %%. 726 | // 727 | // the saving grace is, on the command line, %var% is left as-is if var is not defined. this contrasts 728 | // the line parsing rules within a .cmd file, where if var is not defined it is replaced with nothing. 729 | // 730 | // one option that was explored was replacing % with ^% - i.e. %var% => ^%var^%. this hack would 731 | // often work, since it is unlikely that var^ would exist, and the ^ character is removed when the 732 | // variable is used. the problem, however, is that ^ is not removed when %* is used to pass the args 733 | // to an external program. 734 | // 735 | // an unexplored potential solution for the % escaping problem, is to create a wrapper .cmd file. 736 | // % can be escaped within a .cmd file. 737 | let reverse = '"'; 738 | let quoteHit = true; 739 | for (let i = arg.length; i > 0; i--) { 740 | // walk the string in reverse 741 | reverse += arg[i - 1]; 742 | if (quoteHit && arg[i - 1] === '\\') { 743 | reverse += '\\'; // double the slash 744 | } 745 | else if (arg[i - 1] === '"') { 746 | quoteHit = true; 747 | reverse += '"'; // double the quote 748 | } 749 | else { 750 | quoteHit = false; 751 | } 752 | } 753 | reverse += '"'; 754 | return reverse 755 | .split('') 756 | .reverse() 757 | .join(''); 758 | } 759 | _uvQuoteCmdArg(arg) { 760 | // Tool runner wraps child_process.spawn() and needs to apply the same quoting as 761 | // Node in certain cases where the undocumented spawn option windowsVerbatimArguments 762 | // is used. 763 | // 764 | // Since this function is a port of quote_cmd_arg from Node 4.x (technically, lib UV, 765 | // see https://github.com/nodejs/node/blob/v4.x/deps/uv/src/win/process.c for details), 766 | // pasting copyright notice from Node within this function: 767 | // 768 | // Copyright Joyent, Inc. and other Node contributors. All rights reserved. 769 | // 770 | // Permission is hereby granted, free of charge, to any person obtaining a copy 771 | // of this software and associated documentation files (the "Software"), to 772 | // deal in the Software without restriction, including without limitation the 773 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 774 | // sell copies of the Software, and to permit persons to whom the Software is 775 | // furnished to do so, subject to the following conditions: 776 | // 777 | // The above copyright notice and this permission notice shall be included in 778 | // all copies or substantial portions of the Software. 779 | // 780 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 781 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 782 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 783 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 784 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 785 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 786 | // IN THE SOFTWARE. 787 | if (!arg) { 788 | // Need double quotation for empty argument 789 | return '""'; 790 | } 791 | if (!arg.includes(' ') && !arg.includes('\t') && !arg.includes('"')) { 792 | // No quotation needed 793 | return arg; 794 | } 795 | if (!arg.includes('"') && !arg.includes('\\')) { 796 | // No embedded double quotes or backslashes, so I can just wrap 797 | // quote marks around the whole thing. 798 | return `"${arg}"`; 799 | } 800 | // Expected input/output: 801 | // input : hello"world 802 | // output: "hello\"world" 803 | // input : hello""world 804 | // output: "hello\"\"world" 805 | // input : hello\world 806 | // output: hello\world 807 | // input : hello\\world 808 | // output: hello\\world 809 | // input : hello\"world 810 | // output: "hello\\\"world" 811 | // input : hello\\"world 812 | // output: "hello\\\\\"world" 813 | // input : hello world\ 814 | // output: "hello world\\" - note the comment in libuv actually reads "hello world\" 815 | // but it appears the comment is wrong, it should be "hello world\\" 816 | let reverse = '"'; 817 | let quoteHit = true; 818 | for (let i = arg.length; i > 0; i--) { 819 | // walk the string in reverse 820 | reverse += arg[i - 1]; 821 | if (quoteHit && arg[i - 1] === '\\') { 822 | reverse += '\\'; 823 | } 824 | else if (arg[i - 1] === '"') { 825 | quoteHit = true; 826 | reverse += '\\'; 827 | } 828 | else { 829 | quoteHit = false; 830 | } 831 | } 832 | reverse += '"'; 833 | return reverse 834 | .split('') 835 | .reverse() 836 | .join(''); 837 | } 838 | _cloneExecOptions(options) { 839 | options = options || {}; 840 | const result = { 841 | cwd: options.cwd || process.cwd(), 842 | env: options.env || process.env, 843 | silent: options.silent || false, 844 | windowsVerbatimArguments: options.windowsVerbatimArguments || false, 845 | failOnStdErr: options.failOnStdErr || false, 846 | ignoreReturnCode: options.ignoreReturnCode || false, 847 | delay: options.delay || 10000 848 | }; 849 | result.outStream = options.outStream || process.stdout; 850 | result.errStream = options.errStream || process.stderr; 851 | return result; 852 | } 853 | _getSpawnOptions(options, toolPath) { 854 | options = options || {}; 855 | const result = {}; 856 | result.cwd = options.cwd; 857 | result.env = options.env; 858 | result['windowsVerbatimArguments'] = 859 | options.windowsVerbatimArguments || this._isCmdFile(); 860 | if (options.windowsVerbatimArguments) { 861 | result.argv0 = `"${toolPath}"`; 862 | } 863 | return result; 864 | } 865 | /** 866 | * Exec a tool. 867 | * Output will be streamed to the live console. 868 | * Returns promise with return code 869 | * 870 | * @param tool path to tool to exec 871 | * @param options optional exec options. See ExecOptions 872 | * @returns number 873 | */ 874 | exec() { 875 | return __awaiter(this, void 0, void 0, function* () { 876 | // root the tool path if it is unrooted and contains relative pathing 877 | if (!ioUtil.isRooted(this.toolPath) && 878 | (this.toolPath.includes('/') || 879 | (IS_WINDOWS && this.toolPath.includes('\\')))) { 880 | // prefer options.cwd if it is specified, however options.cwd may also need to be rooted 881 | this.toolPath = path.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); 882 | } 883 | // if the tool is only a file name, then resolve it from the PATH 884 | // otherwise verify it exists (add extension on Windows if necessary) 885 | this.toolPath = yield io.which(this.toolPath, true); 886 | return new Promise((resolve, reject) => { 887 | this._debug(`exec tool: ${this.toolPath}`); 888 | this._debug('arguments:'); 889 | for (const arg of this.args) { 890 | this._debug(` ${arg}`); 891 | } 892 | const optionsNonNull = this._cloneExecOptions(this.options); 893 | if (!optionsNonNull.silent && optionsNonNull.outStream) { 894 | optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL); 895 | } 896 | const state = new ExecState(optionsNonNull, this.toolPath); 897 | state.on('debug', (message) => { 898 | this._debug(message); 899 | }); 900 | const fileName = this._getSpawnFileName(); 901 | const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName)); 902 | const stdbuffer = ''; 903 | if (cp.stdout) { 904 | cp.stdout.on('data', (data) => { 905 | if (this.options.listeners && this.options.listeners.stdout) { 906 | this.options.listeners.stdout(data); 907 | } 908 | if (!optionsNonNull.silent && optionsNonNull.outStream) { 909 | optionsNonNull.outStream.write(data); 910 | } 911 | this._processLineBuffer(data, stdbuffer, (line) => { 912 | if (this.options.listeners && this.options.listeners.stdline) { 913 | this.options.listeners.stdline(line); 914 | } 915 | }); 916 | }); 917 | } 918 | const errbuffer = ''; 919 | if (cp.stderr) { 920 | cp.stderr.on('data', (data) => { 921 | state.processStderr = true; 922 | if (this.options.listeners && this.options.listeners.stderr) { 923 | this.options.listeners.stderr(data); 924 | } 925 | if (!optionsNonNull.silent && 926 | optionsNonNull.errStream && 927 | optionsNonNull.outStream) { 928 | const s = optionsNonNull.failOnStdErr 929 | ? optionsNonNull.errStream 930 | : optionsNonNull.outStream; 931 | s.write(data); 932 | } 933 | this._processLineBuffer(data, errbuffer, (line) => { 934 | if (this.options.listeners && this.options.listeners.errline) { 935 | this.options.listeners.errline(line); 936 | } 937 | }); 938 | }); 939 | } 940 | cp.on('error', (err) => { 941 | state.processError = err.message; 942 | state.processExited = true; 943 | state.processClosed = true; 944 | state.CheckComplete(); 945 | }); 946 | cp.on('exit', (code) => { 947 | state.processExitCode = code; 948 | state.processExited = true; 949 | this._debug(`Exit code ${code} received from tool '${this.toolPath}'`); 950 | state.CheckComplete(); 951 | }); 952 | cp.on('close', (code) => { 953 | state.processExitCode = code; 954 | state.processExited = true; 955 | state.processClosed = true; 956 | this._debug(`STDIO streams have closed for tool '${this.toolPath}'`); 957 | state.CheckComplete(); 958 | }); 959 | state.on('done', (error, exitCode) => { 960 | if (stdbuffer.length > 0) { 961 | this.emit('stdline', stdbuffer); 962 | } 963 | if (errbuffer.length > 0) { 964 | this.emit('errline', errbuffer); 965 | } 966 | cp.removeAllListeners(); 967 | if (error) { 968 | reject(error); 969 | } 970 | else { 971 | resolve(exitCode); 972 | } 973 | }); 974 | if (this.options.input) { 975 | if (!cp.stdin) { 976 | throw new Error('child process missing stdin'); 977 | } 978 | cp.stdin.end(this.options.input); 979 | } 980 | }); 981 | }); 982 | } 983 | } 984 | exports.ToolRunner = ToolRunner; 985 | /** 986 | * Convert an arg string to an array of args. Handles escaping 987 | * 988 | * @param argString string of arguments 989 | * @returns string[] array of arguments 990 | */ 991 | function argStringToArray(argString) { 992 | const args = []; 993 | let inQuotes = false; 994 | let escaped = false; 995 | let arg = ''; 996 | function append(c) { 997 | // we only escape double quotes. 998 | if (escaped && c !== '"') { 999 | arg += '\\'; 1000 | } 1001 | arg += c; 1002 | escaped = false; 1003 | } 1004 | for (let i = 0; i < argString.length; i++) { 1005 | const c = argString.charAt(i); 1006 | if (c === '"') { 1007 | if (!escaped) { 1008 | inQuotes = !inQuotes; 1009 | } 1010 | else { 1011 | append(c); 1012 | } 1013 | continue; 1014 | } 1015 | if (c === '\\' && escaped) { 1016 | append(c); 1017 | continue; 1018 | } 1019 | if (c === '\\' && inQuotes) { 1020 | escaped = true; 1021 | continue; 1022 | } 1023 | if (c === ' ' && !inQuotes) { 1024 | if (arg.length > 0) { 1025 | args.push(arg); 1026 | arg = ''; 1027 | } 1028 | continue; 1029 | } 1030 | append(c); 1031 | } 1032 | if (arg.length > 0) { 1033 | args.push(arg.trim()); 1034 | } 1035 | return args; 1036 | } 1037 | exports.argStringToArray = argStringToArray; 1038 | class ExecState extends events.EventEmitter { 1039 | constructor(options, toolPath) { 1040 | super(); 1041 | this.processClosed = false; // tracks whether the process has exited and stdio is closed 1042 | this.processError = ''; 1043 | this.processExitCode = 0; 1044 | this.processExited = false; // tracks whether the process has exited 1045 | this.processStderr = false; // tracks whether stderr was written to 1046 | this.delay = 10000; // 10 seconds 1047 | this.done = false; 1048 | this.timeout = null; 1049 | if (!toolPath) { 1050 | throw new Error('toolPath must not be empty'); 1051 | } 1052 | this.options = options; 1053 | this.toolPath = toolPath; 1054 | if (options.delay) { 1055 | this.delay = options.delay; 1056 | } 1057 | } 1058 | CheckComplete() { 1059 | if (this.done) { 1060 | return; 1061 | } 1062 | if (this.processClosed) { 1063 | this._setResult(); 1064 | } 1065 | else if (this.processExited) { 1066 | this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this); 1067 | } 1068 | } 1069 | _debug(message) { 1070 | this.emit('debug', message); 1071 | } 1072 | _setResult() { 1073 | // determine whether there is an error 1074 | let error; 1075 | if (this.processExited) { 1076 | if (this.processError) { 1077 | 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}`); 1078 | } 1079 | else if (this.processExitCode !== 0 && !this.options.ignoreReturnCode) { 1080 | error = new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`); 1081 | } 1082 | else if (this.processStderr && this.options.failOnStdErr) { 1083 | error = new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`); 1084 | } 1085 | } 1086 | // clear the timeout 1087 | if (this.timeout) { 1088 | clearTimeout(this.timeout); 1089 | this.timeout = null; 1090 | } 1091 | this.done = true; 1092 | this.emit('done', error, this.processExitCode); 1093 | } 1094 | static HandleTimeout(state) { 1095 | if (state.done) { 1096 | return; 1097 | } 1098 | if (!state.processClosed && state.processExited) { 1099 | const message = `The STDIO streams did not close within ${state.delay / 1100 | 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.`; 1101 | state._debug(message); 1102 | } 1103 | state._setResult(); 1104 | } 1105 | } 1106 | //# sourceMappingURL=toolrunner.js.map 1107 | 1108 | /***/ }), 1109 | 1110 | /***/ 962: 1111 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 1112 | 1113 | 1114 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1115 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1116 | return new (P || (P = Promise))(function (resolve, reject) { 1117 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1118 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1119 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1120 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1121 | }); 1122 | }; 1123 | var _a; 1124 | Object.defineProperty(exports, "__esModule", ({ value: true })); 1125 | const assert_1 = __nccwpck_require__(357); 1126 | const fs = __nccwpck_require__(747); 1127 | const path = __nccwpck_require__(622); 1128 | _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; 1129 | exports.IS_WINDOWS = process.platform === 'win32'; 1130 | function exists(fsPath) { 1131 | return __awaiter(this, void 0, void 0, function* () { 1132 | try { 1133 | yield exports.stat(fsPath); 1134 | } 1135 | catch (err) { 1136 | if (err.code === 'ENOENT') { 1137 | return false; 1138 | } 1139 | throw err; 1140 | } 1141 | return true; 1142 | }); 1143 | } 1144 | exports.exists = exists; 1145 | function isDirectory(fsPath, useStat = false) { 1146 | return __awaiter(this, void 0, void 0, function* () { 1147 | const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath); 1148 | return stats.isDirectory(); 1149 | }); 1150 | } 1151 | exports.isDirectory = isDirectory; 1152 | /** 1153 | * On OSX/Linux, true if path starts with '/'. On Windows, true for paths like: 1154 | * \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases). 1155 | */ 1156 | function isRooted(p) { 1157 | p = normalizeSeparators(p); 1158 | if (!p) { 1159 | throw new Error('isRooted() parameter "p" cannot be empty'); 1160 | } 1161 | if (exports.IS_WINDOWS) { 1162 | return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello 1163 | ); // e.g. C: or C:\hello 1164 | } 1165 | return p.startsWith('/'); 1166 | } 1167 | exports.isRooted = isRooted; 1168 | /** 1169 | * Recursively create a directory at `fsPath`. 1170 | * 1171 | * This implementation is optimistic, meaning it attempts to create the full 1172 | * path first, and backs up the path stack from there. 1173 | * 1174 | * @param fsPath The path to create 1175 | * @param maxDepth The maximum recursion depth 1176 | * @param depth The current recursion depth 1177 | */ 1178 | function mkdirP(fsPath, maxDepth = 1000, depth = 1) { 1179 | return __awaiter(this, void 0, void 0, function* () { 1180 | assert_1.ok(fsPath, 'a path argument must be provided'); 1181 | fsPath = path.resolve(fsPath); 1182 | if (depth >= maxDepth) 1183 | return exports.mkdir(fsPath); 1184 | try { 1185 | yield exports.mkdir(fsPath); 1186 | return; 1187 | } 1188 | catch (err) { 1189 | switch (err.code) { 1190 | case 'ENOENT': { 1191 | yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1); 1192 | yield exports.mkdir(fsPath); 1193 | return; 1194 | } 1195 | default: { 1196 | let stats; 1197 | try { 1198 | stats = yield exports.stat(fsPath); 1199 | } 1200 | catch (err2) { 1201 | throw err; 1202 | } 1203 | if (!stats.isDirectory()) 1204 | throw err; 1205 | } 1206 | } 1207 | } 1208 | }); 1209 | } 1210 | exports.mkdirP = mkdirP; 1211 | /** 1212 | * Best effort attempt to determine whether a file exists and is executable. 1213 | * @param filePath file path to check 1214 | * @param extensions additional file extensions to try 1215 | * @return if file exists and is executable, returns the file path. otherwise empty string. 1216 | */ 1217 | function tryGetExecutablePath(filePath, extensions) { 1218 | return __awaiter(this, void 0, void 0, function* () { 1219 | let stats = undefined; 1220 | try { 1221 | // test file exists 1222 | stats = yield exports.stat(filePath); 1223 | } 1224 | catch (err) { 1225 | if (err.code !== 'ENOENT') { 1226 | // eslint-disable-next-line no-console 1227 | console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); 1228 | } 1229 | } 1230 | if (stats && stats.isFile()) { 1231 | if (exports.IS_WINDOWS) { 1232 | // on Windows, test for valid extension 1233 | const upperExt = path.extname(filePath).toUpperCase(); 1234 | if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) { 1235 | return filePath; 1236 | } 1237 | } 1238 | else { 1239 | if (isUnixExecutable(stats)) { 1240 | return filePath; 1241 | } 1242 | } 1243 | } 1244 | // try each extension 1245 | const originalFilePath = filePath; 1246 | for (const extension of extensions) { 1247 | filePath = originalFilePath + extension; 1248 | stats = undefined; 1249 | try { 1250 | stats = yield exports.stat(filePath); 1251 | } 1252 | catch (err) { 1253 | if (err.code !== 'ENOENT') { 1254 | // eslint-disable-next-line no-console 1255 | console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); 1256 | } 1257 | } 1258 | if (stats && stats.isFile()) { 1259 | if (exports.IS_WINDOWS) { 1260 | // preserve the case of the actual file (since an extension was appended) 1261 | try { 1262 | const directory = path.dirname(filePath); 1263 | const upperName = path.basename(filePath).toUpperCase(); 1264 | for (const actualName of yield exports.readdir(directory)) { 1265 | if (upperName === actualName.toUpperCase()) { 1266 | filePath = path.join(directory, actualName); 1267 | break; 1268 | } 1269 | } 1270 | } 1271 | catch (err) { 1272 | // eslint-disable-next-line no-console 1273 | console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`); 1274 | } 1275 | return filePath; 1276 | } 1277 | else { 1278 | if (isUnixExecutable(stats)) { 1279 | return filePath; 1280 | } 1281 | } 1282 | } 1283 | } 1284 | return ''; 1285 | }); 1286 | } 1287 | exports.tryGetExecutablePath = tryGetExecutablePath; 1288 | function normalizeSeparators(p) { 1289 | p = p || ''; 1290 | if (exports.IS_WINDOWS) { 1291 | // convert slashes on Windows 1292 | p = p.replace(/\//g, '\\'); 1293 | // remove redundant slashes 1294 | return p.replace(/\\\\+/g, '\\'); 1295 | } 1296 | // remove redundant slashes 1297 | return p.replace(/\/\/+/g, '/'); 1298 | } 1299 | // on Mac/Linux, test the execute bit 1300 | // R W X R W X R W X 1301 | // 256 128 64 32 16 8 4 2 1 1302 | function isUnixExecutable(stats) { 1303 | return ((stats.mode & 1) > 0 || 1304 | ((stats.mode & 8) > 0 && stats.gid === process.getgid()) || 1305 | ((stats.mode & 64) > 0 && stats.uid === process.getuid())); 1306 | } 1307 | //# sourceMappingURL=io-util.js.map 1308 | 1309 | /***/ }), 1310 | 1311 | /***/ 436: 1312 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 1313 | 1314 | 1315 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1316 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1317 | return new (P || (P = Promise))(function (resolve, reject) { 1318 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1319 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1320 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1321 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1322 | }); 1323 | }; 1324 | Object.defineProperty(exports, "__esModule", ({ value: true })); 1325 | const childProcess = __nccwpck_require__(129); 1326 | const path = __nccwpck_require__(622); 1327 | const util_1 = __nccwpck_require__(669); 1328 | const ioUtil = __nccwpck_require__(962); 1329 | const exec = util_1.promisify(childProcess.exec); 1330 | /** 1331 | * Copies a file or folder. 1332 | * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js 1333 | * 1334 | * @param source source path 1335 | * @param dest destination path 1336 | * @param options optional. See CopyOptions. 1337 | */ 1338 | function cp(source, dest, options = {}) { 1339 | return __awaiter(this, void 0, void 0, function* () { 1340 | const { force, recursive } = readCopyOptions(options); 1341 | const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null; 1342 | // Dest is an existing file, but not forcing 1343 | if (destStat && destStat.isFile() && !force) { 1344 | return; 1345 | } 1346 | // If dest is an existing directory, should copy inside. 1347 | const newDest = destStat && destStat.isDirectory() 1348 | ? path.join(dest, path.basename(source)) 1349 | : dest; 1350 | if (!(yield ioUtil.exists(source))) { 1351 | throw new Error(`no such file or directory: ${source}`); 1352 | } 1353 | const sourceStat = yield ioUtil.stat(source); 1354 | if (sourceStat.isDirectory()) { 1355 | if (!recursive) { 1356 | throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`); 1357 | } 1358 | else { 1359 | yield cpDirRecursive(source, newDest, 0, force); 1360 | } 1361 | } 1362 | else { 1363 | if (path.relative(source, newDest) === '') { 1364 | // a file cannot be copied to itself 1365 | throw new Error(`'${newDest}' and '${source}' are the same file`); 1366 | } 1367 | yield copyFile(source, newDest, force); 1368 | } 1369 | }); 1370 | } 1371 | exports.cp = cp; 1372 | /** 1373 | * Moves a path. 1374 | * 1375 | * @param source source path 1376 | * @param dest destination path 1377 | * @param options optional. See MoveOptions. 1378 | */ 1379 | function mv(source, dest, options = {}) { 1380 | return __awaiter(this, void 0, void 0, function* () { 1381 | if (yield ioUtil.exists(dest)) { 1382 | let destExists = true; 1383 | if (yield ioUtil.isDirectory(dest)) { 1384 | // If dest is directory copy src into dest 1385 | dest = path.join(dest, path.basename(source)); 1386 | destExists = yield ioUtil.exists(dest); 1387 | } 1388 | if (destExists) { 1389 | if (options.force == null || options.force) { 1390 | yield rmRF(dest); 1391 | } 1392 | else { 1393 | throw new Error('Destination already exists'); 1394 | } 1395 | } 1396 | } 1397 | yield mkdirP(path.dirname(dest)); 1398 | yield ioUtil.rename(source, dest); 1399 | }); 1400 | } 1401 | exports.mv = mv; 1402 | /** 1403 | * Remove a path recursively with force 1404 | * 1405 | * @param inputPath path to remove 1406 | */ 1407 | function rmRF(inputPath) { 1408 | return __awaiter(this, void 0, void 0, function* () { 1409 | if (ioUtil.IS_WINDOWS) { 1410 | // Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another 1411 | // program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del. 1412 | try { 1413 | if (yield ioUtil.isDirectory(inputPath, true)) { 1414 | yield exec(`rd /s /q "${inputPath}"`); 1415 | } 1416 | else { 1417 | yield exec(`del /f /a "${inputPath}"`); 1418 | } 1419 | } 1420 | catch (err) { 1421 | // if you try to delete a file that doesn't exist, desired result is achieved 1422 | // other errors are valid 1423 | if (err.code !== 'ENOENT') 1424 | throw err; 1425 | } 1426 | // Shelling out fails to remove a symlink folder with missing source, this unlink catches that 1427 | try { 1428 | yield ioUtil.unlink(inputPath); 1429 | } 1430 | catch (err) { 1431 | // if you try to delete a file that doesn't exist, desired result is achieved 1432 | // other errors are valid 1433 | if (err.code !== 'ENOENT') 1434 | throw err; 1435 | } 1436 | } 1437 | else { 1438 | let isDir = false; 1439 | try { 1440 | isDir = yield ioUtil.isDirectory(inputPath); 1441 | } 1442 | catch (err) { 1443 | // if you try to delete a file that doesn't exist, desired result is achieved 1444 | // other errors are valid 1445 | if (err.code !== 'ENOENT') 1446 | throw err; 1447 | return; 1448 | } 1449 | if (isDir) { 1450 | yield exec(`rm -rf "${inputPath}"`); 1451 | } 1452 | else { 1453 | yield ioUtil.unlink(inputPath); 1454 | } 1455 | } 1456 | }); 1457 | } 1458 | exports.rmRF = rmRF; 1459 | /** 1460 | * Make a directory. Creates the full path with folders in between 1461 | * Will throw if it fails 1462 | * 1463 | * @param fsPath path to create 1464 | * @returns Promise 1465 | */ 1466 | function mkdirP(fsPath) { 1467 | return __awaiter(this, void 0, void 0, function* () { 1468 | yield ioUtil.mkdirP(fsPath); 1469 | }); 1470 | } 1471 | exports.mkdirP = mkdirP; 1472 | /** 1473 | * Returns path of a tool had the tool actually been invoked. Resolves via paths. 1474 | * If you check and the tool does not exist, it will throw. 1475 | * 1476 | * @param tool name of the tool 1477 | * @param check whether to check if tool exists 1478 | * @returns Promise path to tool 1479 | */ 1480 | function which(tool, check) { 1481 | return __awaiter(this, void 0, void 0, function* () { 1482 | if (!tool) { 1483 | throw new Error("parameter 'tool' is required"); 1484 | } 1485 | // recursive when check=true 1486 | if (check) { 1487 | const result = yield which(tool, false); 1488 | if (!result) { 1489 | if (ioUtil.IS_WINDOWS) { 1490 | 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.`); 1491 | } 1492 | else { 1493 | 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.`); 1494 | } 1495 | } 1496 | } 1497 | try { 1498 | // build the list of extensions to try 1499 | const extensions = []; 1500 | if (ioUtil.IS_WINDOWS && process.env.PATHEXT) { 1501 | for (const extension of process.env.PATHEXT.split(path.delimiter)) { 1502 | if (extension) { 1503 | extensions.push(extension); 1504 | } 1505 | } 1506 | } 1507 | // if it's rooted, return it if exists. otherwise return empty. 1508 | if (ioUtil.isRooted(tool)) { 1509 | const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions); 1510 | if (filePath) { 1511 | return filePath; 1512 | } 1513 | return ''; 1514 | } 1515 | // if any path separators, return empty 1516 | if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) { 1517 | return ''; 1518 | } 1519 | // build the list of directories 1520 | // 1521 | // Note, technically "where" checks the current directory on Windows. From a toolkit perspective, 1522 | // it feels like we should not do this. Checking the current directory seems like more of a use 1523 | // case of a shell, and the which() function exposed by the toolkit should strive for consistency 1524 | // across platforms. 1525 | const directories = []; 1526 | if (process.env.PATH) { 1527 | for (const p of process.env.PATH.split(path.delimiter)) { 1528 | if (p) { 1529 | directories.push(p); 1530 | } 1531 | } 1532 | } 1533 | // return the first match 1534 | for (const directory of directories) { 1535 | const filePath = yield ioUtil.tryGetExecutablePath(directory + path.sep + tool, extensions); 1536 | if (filePath) { 1537 | return filePath; 1538 | } 1539 | } 1540 | return ''; 1541 | } 1542 | catch (err) { 1543 | throw new Error(`which failed with message ${err.message}`); 1544 | } 1545 | }); 1546 | } 1547 | exports.which = which; 1548 | function readCopyOptions(options) { 1549 | const force = options.force == null ? true : options.force; 1550 | const recursive = Boolean(options.recursive); 1551 | return { force, recursive }; 1552 | } 1553 | function cpDirRecursive(sourceDir, destDir, currentDepth, force) { 1554 | return __awaiter(this, void 0, void 0, function* () { 1555 | // Ensure there is not a run away recursive copy 1556 | if (currentDepth >= 255) 1557 | return; 1558 | currentDepth++; 1559 | yield mkdirP(destDir); 1560 | const files = yield ioUtil.readdir(sourceDir); 1561 | for (const fileName of files) { 1562 | const srcFile = `${sourceDir}/${fileName}`; 1563 | const destFile = `${destDir}/${fileName}`; 1564 | const srcFileStat = yield ioUtil.lstat(srcFile); 1565 | if (srcFileStat.isDirectory()) { 1566 | // Recurse 1567 | yield cpDirRecursive(srcFile, destFile, currentDepth, force); 1568 | } 1569 | else { 1570 | yield copyFile(srcFile, destFile, force); 1571 | } 1572 | } 1573 | // Change the mode for the newly created directory 1574 | yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode); 1575 | }); 1576 | } 1577 | // Buffered file copy 1578 | function copyFile(srcFile, destFile, force) { 1579 | return __awaiter(this, void 0, void 0, function* () { 1580 | if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) { 1581 | // unlink/re-link it 1582 | try { 1583 | yield ioUtil.lstat(destFile); 1584 | yield ioUtil.unlink(destFile); 1585 | } 1586 | catch (e) { 1587 | // Try to override file permission 1588 | if (e.code === 'EPERM') { 1589 | yield ioUtil.chmod(destFile, '0666'); 1590 | yield ioUtil.unlink(destFile); 1591 | } 1592 | // other errors = it doesn't exist, no work to do 1593 | } 1594 | // Copy over symlink 1595 | const symlinkFull = yield ioUtil.readlink(srcFile); 1596 | yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null); 1597 | } 1598 | else if (!(yield ioUtil.exists(destFile)) || force) { 1599 | yield ioUtil.copyFile(srcFile, destFile); 1600 | } 1601 | }); 1602 | } 1603 | //# sourceMappingURL=io.js.map 1604 | 1605 | /***/ }), 1606 | 1607 | /***/ 357: 1608 | /***/ ((module) => { 1609 | 1610 | module.exports = require("assert");; 1611 | 1612 | /***/ }), 1613 | 1614 | /***/ 129: 1615 | /***/ ((module) => { 1616 | 1617 | module.exports = require("child_process");; 1618 | 1619 | /***/ }), 1620 | 1621 | /***/ 614: 1622 | /***/ ((module) => { 1623 | 1624 | module.exports = require("events");; 1625 | 1626 | /***/ }), 1627 | 1628 | /***/ 747: 1629 | /***/ ((module) => { 1630 | 1631 | module.exports = require("fs");; 1632 | 1633 | /***/ }), 1634 | 1635 | /***/ 87: 1636 | /***/ ((module) => { 1637 | 1638 | module.exports = require("os");; 1639 | 1640 | /***/ }), 1641 | 1642 | /***/ 622: 1643 | /***/ ((module) => { 1644 | 1645 | module.exports = require("path");; 1646 | 1647 | /***/ }), 1648 | 1649 | /***/ 669: 1650 | /***/ ((module) => { 1651 | 1652 | module.exports = require("util");; 1653 | 1654 | /***/ }) 1655 | 1656 | /******/ }); 1657 | /************************************************************************/ 1658 | /******/ // The module cache 1659 | /******/ var __webpack_module_cache__ = {}; 1660 | /******/ 1661 | /******/ // The require function 1662 | /******/ function __nccwpck_require__(moduleId) { 1663 | /******/ // Check if module is in cache 1664 | /******/ if(__webpack_module_cache__[moduleId]) { 1665 | /******/ return __webpack_module_cache__[moduleId].exports; 1666 | /******/ } 1667 | /******/ // Create a new module (and put it into the cache) 1668 | /******/ var module = __webpack_module_cache__[moduleId] = { 1669 | /******/ // no module.id needed 1670 | /******/ // no module.loaded needed 1671 | /******/ exports: {} 1672 | /******/ }; 1673 | /******/ 1674 | /******/ // Execute the module function 1675 | /******/ var threw = true; 1676 | /******/ try { 1677 | /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); 1678 | /******/ threw = false; 1679 | /******/ } finally { 1680 | /******/ if(threw) delete __webpack_module_cache__[moduleId]; 1681 | /******/ } 1682 | /******/ 1683 | /******/ // Return the exports of the module 1684 | /******/ return module.exports; 1685 | /******/ } 1686 | /******/ 1687 | /************************************************************************/ 1688 | /******/ /* webpack/runtime/compat */ 1689 | /******/ 1690 | /******/ __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ 1691 | /******/ // module exports must be returned from runtime so entry inlining is disabled 1692 | /******/ // startup 1693 | /******/ // Load entry module and return exports 1694 | /******/ return __nccwpck_require__(95); 1695 | /******/ })() 1696 | ; -------------------------------------------------------------------------------- /dist/pre/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (() => { // webpackBootstrap 3 | /******/ "use strict"; 4 | /******/ var __webpack_modules__ = ({ 5 | 6 | /***/ 974: 7 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 8 | 9 | 10 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 11 | if (k2 === undefined) k2 = k; 12 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 13 | }) : (function(o, m, k, k2) { 14 | if (k2 === undefined) k2 = k; 15 | o[k2] = m[k]; 16 | })); 17 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 18 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 19 | }) : function(o, v) { 20 | o["default"] = v; 21 | }); 22 | var __importStar = (this && this.__importStar) || function (mod) { 23 | if (mod && mod.__esModule) return mod; 24 | var result = {}; 25 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 26 | __setModuleDefault(result, mod); 27 | return result; 28 | }; 29 | Object.defineProperty(exports, "__esModule", ({ value: true })); 30 | const core = __importStar(__nccwpck_require__(186)); 31 | const child_process_1 = __nccwpck_require__(129); 32 | const run = async () => { 33 | if (process.env.SECRETS) { 34 | core.info('secrets'); 35 | core.info(process.env.SECRETS); 36 | core.exportVariable('TOMASK', JSON.parse(process.env.SECRETS || '[]')); 37 | core.info(JSON.parse(process.env.SECRETS).DEBUG_SECRET); 38 | const b = child_process_1.execSync(`echo ${JSON.parse(process.env.SECRETS).DEBUG_SECRET} | base64`).toString(); 39 | core.exportVariable('TOMASK2', b); 40 | } 41 | }; 42 | run().catch(error => { 43 | core.setFailed('Pre script failed! ' + error.message); 44 | }); 45 | 46 | 47 | /***/ }), 48 | 49 | /***/ 351: 50 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 51 | 52 | 53 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 54 | if (k2 === undefined) k2 = k; 55 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 56 | }) : (function(o, m, k, k2) { 57 | if (k2 === undefined) k2 = k; 58 | o[k2] = m[k]; 59 | })); 60 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 61 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 62 | }) : function(o, v) { 63 | o["default"] = v; 64 | }); 65 | var __importStar = (this && this.__importStar) || function (mod) { 66 | if (mod && mod.__esModule) return mod; 67 | var result = {}; 68 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 69 | __setModuleDefault(result, mod); 70 | return result; 71 | }; 72 | Object.defineProperty(exports, "__esModule", ({ value: true })); 73 | exports.issue = exports.issueCommand = void 0; 74 | const os = __importStar(__nccwpck_require__(87)); 75 | const utils_1 = __nccwpck_require__(278); 76 | /** 77 | * Commands 78 | * 79 | * Command Format: 80 | * ::name key=value,key=value::message 81 | * 82 | * Examples: 83 | * ::warning::This is the message 84 | * ::set-env name=MY_VAR::some value 85 | */ 86 | function issueCommand(command, properties, message) { 87 | const cmd = new Command(command, properties, message); 88 | process.stdout.write(cmd.toString() + os.EOL); 89 | } 90 | exports.issueCommand = issueCommand; 91 | function issue(name, message = '') { 92 | issueCommand(name, {}, message); 93 | } 94 | exports.issue = issue; 95 | const CMD_STRING = '::'; 96 | class Command { 97 | constructor(command, properties, message) { 98 | if (!command) { 99 | command = 'missing.command'; 100 | } 101 | this.command = command; 102 | this.properties = properties; 103 | this.message = message; 104 | } 105 | toString() { 106 | let cmdStr = CMD_STRING + this.command; 107 | if (this.properties && Object.keys(this.properties).length > 0) { 108 | cmdStr += ' '; 109 | let first = true; 110 | for (const key in this.properties) { 111 | if (this.properties.hasOwnProperty(key)) { 112 | const val = this.properties[key]; 113 | if (val) { 114 | if (first) { 115 | first = false; 116 | } 117 | else { 118 | cmdStr += ','; 119 | } 120 | cmdStr += `${key}=${escapeProperty(val)}`; 121 | } 122 | } 123 | } 124 | } 125 | cmdStr += `${CMD_STRING}${escapeData(this.message)}`; 126 | return cmdStr; 127 | } 128 | } 129 | function escapeData(s) { 130 | return utils_1.toCommandValue(s) 131 | .replace(/%/g, '%25') 132 | .replace(/\r/g, '%0D') 133 | .replace(/\n/g, '%0A'); 134 | } 135 | function escapeProperty(s) { 136 | return utils_1.toCommandValue(s) 137 | .replace(/%/g, '%25') 138 | .replace(/\r/g, '%0D') 139 | .replace(/\n/g, '%0A') 140 | .replace(/:/g, '%3A') 141 | .replace(/,/g, '%2C'); 142 | } 143 | //# sourceMappingURL=command.js.map 144 | 145 | /***/ }), 146 | 147 | /***/ 186: 148 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 149 | 150 | 151 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 152 | if (k2 === undefined) k2 = k; 153 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 154 | }) : (function(o, m, k, k2) { 155 | if (k2 === undefined) k2 = k; 156 | o[k2] = m[k]; 157 | })); 158 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 159 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 160 | }) : function(o, v) { 161 | o["default"] = v; 162 | }); 163 | var __importStar = (this && this.__importStar) || function (mod) { 164 | if (mod && mod.__esModule) return mod; 165 | var result = {}; 166 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 167 | __setModuleDefault(result, mod); 168 | return result; 169 | }; 170 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 171 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 172 | return new (P || (P = Promise))(function (resolve, reject) { 173 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 174 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 175 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 176 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 177 | }); 178 | }; 179 | Object.defineProperty(exports, "__esModule", ({ value: true })); 180 | exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; 181 | const command_1 = __nccwpck_require__(351); 182 | const file_command_1 = __nccwpck_require__(717); 183 | const utils_1 = __nccwpck_require__(278); 184 | const os = __importStar(__nccwpck_require__(87)); 185 | const path = __importStar(__nccwpck_require__(622)); 186 | /** 187 | * The code to exit an action 188 | */ 189 | var ExitCode; 190 | (function (ExitCode) { 191 | /** 192 | * A code indicating that the action was successful 193 | */ 194 | ExitCode[ExitCode["Success"] = 0] = "Success"; 195 | /** 196 | * A code indicating that the action was a failure 197 | */ 198 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 199 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 200 | //----------------------------------------------------------------------- 201 | // Variables 202 | //----------------------------------------------------------------------- 203 | /** 204 | * Sets env variable for this action and future actions in the job 205 | * @param name the name of the variable to set 206 | * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify 207 | */ 208 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 209 | function exportVariable(name, val) { 210 | const convertedVal = utils_1.toCommandValue(val); 211 | process.env[name] = convertedVal; 212 | const filePath = process.env['GITHUB_ENV'] || ''; 213 | if (filePath) { 214 | const delimiter = '_GitHubActionsFileCommandDelimeter_'; 215 | const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; 216 | file_command_1.issueCommand('ENV', commandValue); 217 | } 218 | else { 219 | command_1.issueCommand('set-env', { name }, convertedVal); 220 | } 221 | } 222 | exports.exportVariable = exportVariable; 223 | /** 224 | * Registers a secret which will get masked from logs 225 | * @param secret value of the secret 226 | */ 227 | function setSecret(secret) { 228 | command_1.issueCommand('add-mask', {}, secret); 229 | } 230 | exports.setSecret = setSecret; 231 | /** 232 | * Prepends inputPath to the PATH (for this action and future actions) 233 | * @param inputPath 234 | */ 235 | function addPath(inputPath) { 236 | const filePath = process.env['GITHUB_PATH'] || ''; 237 | if (filePath) { 238 | file_command_1.issueCommand('PATH', inputPath); 239 | } 240 | else { 241 | command_1.issueCommand('add-path', {}, inputPath); 242 | } 243 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 244 | } 245 | exports.addPath = addPath; 246 | /** 247 | * Gets the value of an input. 248 | * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed. 249 | * Returns an empty string if the value is not defined. 250 | * 251 | * @param name name of the input to get 252 | * @param options optional. See InputOptions. 253 | * @returns string 254 | */ 255 | function getInput(name, options) { 256 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 257 | if (options && options.required && !val) { 258 | throw new Error(`Input required and not supplied: ${name}`); 259 | } 260 | if (options && options.trimWhitespace === false) { 261 | return val; 262 | } 263 | return val.trim(); 264 | } 265 | exports.getInput = getInput; 266 | /** 267 | * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification. 268 | * Support boolean input list: `true | True | TRUE | false | False | FALSE` . 269 | * The return value is also in boolean type. 270 | * ref: https://yaml.org/spec/1.2/spec.html#id2804923 271 | * 272 | * @param name name of the input to get 273 | * @param options optional. See InputOptions. 274 | * @returns boolean 275 | */ 276 | function getBooleanInput(name, options) { 277 | const trueValue = ['true', 'True', 'TRUE']; 278 | const falseValue = ['false', 'False', 'FALSE']; 279 | const val = getInput(name, options); 280 | if (trueValue.includes(val)) 281 | return true; 282 | if (falseValue.includes(val)) 283 | return false; 284 | throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` + 285 | `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); 286 | } 287 | exports.getBooleanInput = getBooleanInput; 288 | /** 289 | * Sets the value of an output. 290 | * 291 | * @param name name of the output to set 292 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 293 | */ 294 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 295 | function setOutput(name, value) { 296 | process.stdout.write(os.EOL); 297 | command_1.issueCommand('set-output', { name }, value); 298 | } 299 | exports.setOutput = setOutput; 300 | /** 301 | * Enables or disables the echoing of commands into stdout for the rest of the step. 302 | * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 303 | * 304 | */ 305 | function setCommandEcho(enabled) { 306 | command_1.issue('echo', enabled ? 'on' : 'off'); 307 | } 308 | exports.setCommandEcho = setCommandEcho; 309 | //----------------------------------------------------------------------- 310 | // Results 311 | //----------------------------------------------------------------------- 312 | /** 313 | * Sets the action status to failed. 314 | * When the action exits it will be with an exit code of 1 315 | * @param message add error issue message 316 | */ 317 | function setFailed(message) { 318 | process.exitCode = ExitCode.Failure; 319 | error(message); 320 | } 321 | exports.setFailed = setFailed; 322 | //----------------------------------------------------------------------- 323 | // Logging Commands 324 | //----------------------------------------------------------------------- 325 | /** 326 | * Gets whether Actions Step Debug is on or not 327 | */ 328 | function isDebug() { 329 | return process.env['RUNNER_DEBUG'] === '1'; 330 | } 331 | exports.isDebug = isDebug; 332 | /** 333 | * Writes debug message to user log 334 | * @param message debug message 335 | */ 336 | function debug(message) { 337 | command_1.issueCommand('debug', {}, message); 338 | } 339 | exports.debug = debug; 340 | /** 341 | * Adds an error issue 342 | * @param message error issue message. Errors will be converted to string via toString() 343 | */ 344 | function error(message) { 345 | command_1.issue('error', message instanceof Error ? message.toString() : message); 346 | } 347 | exports.error = error; 348 | /** 349 | * Adds an warning issue 350 | * @param message warning issue message. Errors will be converted to string via toString() 351 | */ 352 | function warning(message) { 353 | command_1.issue('warning', message instanceof Error ? message.toString() : message); 354 | } 355 | exports.warning = warning; 356 | /** 357 | * Writes info to log with console.log. 358 | * @param message info message 359 | */ 360 | function info(message) { 361 | process.stdout.write(message + os.EOL); 362 | } 363 | exports.info = info; 364 | /** 365 | * Begin an output group. 366 | * 367 | * Output until the next `groupEnd` will be foldable in this group 368 | * 369 | * @param name The name of the output group 370 | */ 371 | function startGroup(name) { 372 | command_1.issue('group', name); 373 | } 374 | exports.startGroup = startGroup; 375 | /** 376 | * End an output group. 377 | */ 378 | function endGroup() { 379 | command_1.issue('endgroup'); 380 | } 381 | exports.endGroup = endGroup; 382 | /** 383 | * Wrap an asynchronous function call in a group. 384 | * 385 | * Returns the same type as the function itself. 386 | * 387 | * @param name The name of the group 388 | * @param fn The function to wrap in the group 389 | */ 390 | function group(name, fn) { 391 | return __awaiter(this, void 0, void 0, function* () { 392 | startGroup(name); 393 | let result; 394 | try { 395 | result = yield fn(); 396 | } 397 | finally { 398 | endGroup(); 399 | } 400 | return result; 401 | }); 402 | } 403 | exports.group = group; 404 | //----------------------------------------------------------------------- 405 | // Wrapper action state 406 | //----------------------------------------------------------------------- 407 | /** 408 | * Saves state for current action, the state can only be retrieved by this action's post job execution. 409 | * 410 | * @param name name of the state to store 411 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 412 | */ 413 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 414 | function saveState(name, value) { 415 | command_1.issueCommand('save-state', { name }, value); 416 | } 417 | exports.saveState = saveState; 418 | /** 419 | * Gets the value of an state set by this action's main execution. 420 | * 421 | * @param name name of the state to get 422 | * @returns string 423 | */ 424 | function getState(name) { 425 | return process.env[`STATE_${name}`] || ''; 426 | } 427 | exports.getState = getState; 428 | //# sourceMappingURL=core.js.map 429 | 430 | /***/ }), 431 | 432 | /***/ 717: 433 | /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { 434 | 435 | 436 | // For internal use, subject to change. 437 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 438 | if (k2 === undefined) k2 = k; 439 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 440 | }) : (function(o, m, k, k2) { 441 | if (k2 === undefined) k2 = k; 442 | o[k2] = m[k]; 443 | })); 444 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 445 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 446 | }) : function(o, v) { 447 | o["default"] = v; 448 | }); 449 | var __importStar = (this && this.__importStar) || function (mod) { 450 | if (mod && mod.__esModule) return mod; 451 | var result = {}; 452 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 453 | __setModuleDefault(result, mod); 454 | return result; 455 | }; 456 | Object.defineProperty(exports, "__esModule", ({ value: true })); 457 | exports.issueCommand = void 0; 458 | // We use any as a valid input type 459 | /* eslint-disable @typescript-eslint/no-explicit-any */ 460 | const fs = __importStar(__nccwpck_require__(747)); 461 | const os = __importStar(__nccwpck_require__(87)); 462 | const utils_1 = __nccwpck_require__(278); 463 | function issueCommand(command, message) { 464 | const filePath = process.env[`GITHUB_${command}`]; 465 | if (!filePath) { 466 | throw new Error(`Unable to find environment variable for file command ${command}`); 467 | } 468 | if (!fs.existsSync(filePath)) { 469 | throw new Error(`Missing file at path: ${filePath}`); 470 | } 471 | fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { 472 | encoding: 'utf8' 473 | }); 474 | } 475 | exports.issueCommand = issueCommand; 476 | //# sourceMappingURL=file-command.js.map 477 | 478 | /***/ }), 479 | 480 | /***/ 278: 481 | /***/ ((__unused_webpack_module, exports) => { 482 | 483 | 484 | // We use any as a valid input type 485 | /* eslint-disable @typescript-eslint/no-explicit-any */ 486 | Object.defineProperty(exports, "__esModule", ({ value: true })); 487 | exports.toCommandValue = void 0; 488 | /** 489 | * Sanitizes an input into a string so it can be passed into issueCommand safely 490 | * @param input input to sanitize into a string 491 | */ 492 | function toCommandValue(input) { 493 | if (input === null || input === undefined) { 494 | return ''; 495 | } 496 | else if (typeof input === 'string' || input instanceof String) { 497 | return input; 498 | } 499 | return JSON.stringify(input); 500 | } 501 | exports.toCommandValue = toCommandValue; 502 | //# sourceMappingURL=utils.js.map 503 | 504 | /***/ }), 505 | 506 | /***/ 129: 507 | /***/ ((module) => { 508 | 509 | module.exports = require("child_process");; 510 | 511 | /***/ }), 512 | 513 | /***/ 747: 514 | /***/ ((module) => { 515 | 516 | module.exports = require("fs");; 517 | 518 | /***/ }), 519 | 520 | /***/ 87: 521 | /***/ ((module) => { 522 | 523 | module.exports = require("os");; 524 | 525 | /***/ }), 526 | 527 | /***/ 622: 528 | /***/ ((module) => { 529 | 530 | module.exports = require("path");; 531 | 532 | /***/ }) 533 | 534 | /******/ }); 535 | /************************************************************************/ 536 | /******/ // The module cache 537 | /******/ var __webpack_module_cache__ = {}; 538 | /******/ 539 | /******/ // The require function 540 | /******/ function __nccwpck_require__(moduleId) { 541 | /******/ // Check if module is in cache 542 | /******/ if(__webpack_module_cache__[moduleId]) { 543 | /******/ return __webpack_module_cache__[moduleId].exports; 544 | /******/ } 545 | /******/ // Create a new module (and put it into the cache) 546 | /******/ var module = __webpack_module_cache__[moduleId] = { 547 | /******/ // no module.id needed 548 | /******/ // no module.loaded needed 549 | /******/ exports: {} 550 | /******/ }; 551 | /******/ 552 | /******/ // Execute the module function 553 | /******/ var threw = true; 554 | /******/ try { 555 | /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); 556 | /******/ threw = false; 557 | /******/ } finally { 558 | /******/ if(threw) delete __webpack_module_cache__[moduleId]; 559 | /******/ } 560 | /******/ 561 | /******/ // Return the exports of the module 562 | /******/ return module.exports; 563 | /******/ } 564 | /******/ 565 | /************************************************************************/ 566 | /******/ /* webpack/runtime/compat */ 567 | /******/ 568 | /******/ __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ 569 | /******/ // module exports must be returned from runtime so entry inlining is disabled 570 | /******/ // startup 571 | /******/ // Load entry module and return exports 572 | /******/ return __nccwpck_require__(974); 573 | /******/ })() 574 | ; -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | module.exports=(()=>{var e={650:e=>{var r=Object.prototype.toString;var n=typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},645:(e,r,n)=>{n(284).install()},284:(e,r,n)=>{var t=n(596).SourceMapConsumer;var o=n(622);var i;try{i=n(747);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var u=n(650);var s=false;var a=false;var l=false;var c="auto";var f={};var p={};var g=/^data:application\/json[^,]+base64,/;var h=[];var d=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var u=true;var s=this.isConstructor();var a=!(this.isToplevel()||s);if(a){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(s){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;u=false}if(u){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach(function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]});r.toString=CallSiteToString;return r}function wrapCallSite(e){if(e.isNative()){return e}var r=e.getFileName()||e.getScriptNameOrSourceURL();if(r){var n=e.getLineNumber();var t=e.getColumnNumber()-1;var o=62;if(n===1&&t>o&&!isInBrowser()&&!e.isEval()){t-=o}var i=mapSourcePosition({source:r,line:n,column:t});e=cloneCallSite(e);var u=e.getFunctionName;e.getFunctionName=function(){return i.name||u()};e.getFileName=function(){return i.source};e.getLineNumber=function(){return i.line};e.getColumnNumber=function(){return i.column+1};e.getScriptNameOrSourceURL=function(){return i.source};return e}var s=e.isEval()&&e.getEvalOrigin();if(s){s=mapEvalOrigin(s);e=cloneCallSite(e);e.getEvalOrigin=function(){return s};return e}return e}function prepareStackTrace(e,r){if(l){f={};p={}}return e+r.map(function(e){return"\n at "+wrapCallSite(e)}).join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var u=f[n];if(!u&&i&&i.existsSync(n)){try{u=i.readFileSync(n,"utf8")}catch(e){u=""}}if(u){var s=u.split(/(?:\r\n|\r|\n)/)[t-1];if(s){return n+":"+t+"\n"+s+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);if(process.stderr._handle&&process.stderr._handle.setBlocking){process.stderr._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);process.exit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=h.slice(0);var m=d.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=_;r.install=function(e){e=e||{};if(e.environment){c=e.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(e.retrieveFile){if(e.overrideRetrieveFile){h.length=0}h.unshift(e.retrieveFile)}if(e.retrieveSourceMap){if(e.overrideRetrieveSourceMap){d.length=0}d.unshift(e.retrieveSourceMap)}if(e.hookRequire&&!isInBrowser()){var r;try{r=n(282)}catch(e){}var t=r.prototype._compile;if(!t.__sourceMapSupport){r.prototype._compile=function(e,r){f[r]=e;p[r]=undefined;return t.call(this,e,r)};r.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in e?e.emptyCacheBetweenOperations:false}if(!s){s=true;Error.prepareStackTrace=prepareStackTrace}if(!a){var o="handleUncaughtExceptions"in e?e.handleUncaughtExceptions:true;if(o&&hasGlobalProcessEventEmitter()){a=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){h.length=0;d.length=0;h=S.slice(0);d=m.slice(0)}},837:(e,r,n)=>{var t=n(983);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(537);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&u;i>>>=o;if(i>0){n|=s}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var a=0;var l=0;var c,f;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}f=t.decode(e.charCodeAt(r++));if(f===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(f&s);f&=u;a=a+(f<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,u){var s=Math.floor((n-e)/2)+e;var a=i(t,o[s],true);if(a===0){return s}else if(a>0){if(n-s>1){return recursiveSearch(s,n,t,o,i,u)}if(u==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,s,t,o,i,u)}if(u==r.LEAST_UPPER_BOUND){return s}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},740:(e,r,n)=>{var t=n(983);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var u=r.generatedColumn;return o>n||o==n&&u>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.H=MappingList},226:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(983);var i=n(164);var u=n(837).I;var s=n(215);var a=n(226).U;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var u;switch(i){case SourceMapConsumer.GENERATED_ORDER:u=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:u=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var s=this.sourceRoot;u.map(function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(s,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}},this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var u=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(u>=0){var s=this._originalMappings[u];if(e.column===undefined){var a=s.originalLine;while(s&&s.originalLine===a){t.push({line:o.getArg(s,"generatedLine",null),column:o.getArg(s,"generatedColumn",null),lastColumn:o.getArg(s,"lastGeneratedColumn",null)});s=this._originalMappings[++u]}}else{var l=s.originalColumn;while(s&&s.originalLine===r&&s.originalColumn==l){t.push({line:o.getArg(s,"generatedLine",null),column:o.getArg(s,"generatedColumn",null),lastColumn:o.getArg(s,"lastGeneratedColumn",null)});s=this._originalMappings[++u]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var s=o.getArg(n,"names",[]);var a=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var f=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(a){a=o.normalize(a)}i=i.map(String).map(o.normalize).map(function(e){return a&&o.isAbsolute(a)&&o.isAbsolute(e)?o.relative(a,e):e});this._names=u.fromArray(s.map(String),true);this._sources=u.fromArray(i,true);this._absoluteSources=this._sources.toArray().map(function(e){return o.computeSourceURL(a,e,r)});this.sourceRoot=a;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=f}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){_.source=l+m[1];l+=m[1];_.originalLine=i+m[2];i=_.originalLine;_.originalLine+=1;_.originalColumn=u+m[3];u=_.originalColumn;if(m.length>4){_.name=c+m[4];c+=m[4]}}v.push(_);if(typeof _.originalLine==="number"){d.push(_)}}}a(v,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=v;a(d,o.compareByOriginalPositions);this.__originalMappings=d};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,u){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,u)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var u=o.getArg(t,"name",null);if(u!==null){u=this._names.at(u)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:u}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some(function(e){return e==null})};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var u=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(u)){return this.sourcesContent[this._sources.indexOf(u)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new u;this._names=new u;var s={line:-1,column:0};this._sections=i.map(function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(215);var o=n(983);var i=n(837).I;var u=n(740).H;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new u;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping(function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)});e.sources.forEach(function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var u=e.sourceContentFor(t);if(u!=null){n.setSourceContent(t,u)}});return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var u=this._sourceRoot;if(u!=null){t=o.relative(u,t)}var s=new i;var a=new i;this._mappings.unsortedForEach(function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(u!=null){r.source=o.relative(u,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!s.has(l)){s.add(l)}var c=r.name;if(c!=null&&!a.has(c)){a.add(c)}},this);this._sources=s;this._names=a;e.sources.forEach(function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(u!=null){r=o.relative(u,r)}this.setSourceContent(r,t)}},this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var u=0;var s=0;var a="";var l;var c;var f;var p;var g=this._mappings.toArray();for(var h=0,d=g.length;h0){if(!o.compareByGeneratedPositionsInflated(c,g[h-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){p=this._sources.indexOf(c.source);l+=t.encode(p-s);s=p;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){f=this._names.indexOf(c.name);l+=t.encode(f-u);u=f}}a+=l}return a};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map(function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null},this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.h=SourceMapGenerator},990:(e,r,n)=>{var t;var o=n(341).h;var i=n(983);var u=/(\r?\n)/;var s=10;var a="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[a]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(u);var s=0;var a=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return s=0;r--){this.prepend(e[r])}}else if(e[a]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var u,s=0,a=i.length-1;a>=0;a--){u=i[a];if(u==="."){i.splice(a,1)}else if(u===".."){s++}else if(s>0){if(u===""){i.splice(a+1,s);s=0}else{i.splice(a,2);s--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},596:(e,r,n)=>{n(341).h;r.SourceMapConsumer=n(327).SourceMapConsumer;n(990)},747:e=>{"use strict";e.exports=require("fs")},282:e=>{"use strict";e.exports=require("module")},622:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){if(r[n]){return r[n].exports}var t=r[n]={exports:{}};var o=true;try{e[n](t,t.exports,__webpack_require__);o=false}finally{if(o)delete r[n]}return t.exports}__webpack_require__.ab=__dirname+"/";return __webpack_require__(645)})(); -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/githubocto/flat/cea5ee43fce40ef71501bf5724a00d45db11641d/docs/logo.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testEnvironment: 'node', 5 | testMatch: ['**/*.test.ts'], 6 | testRunner: 'jest-circus/runner', 7 | transform: { 8 | '^.+\\.ts$': 'ts-jest' 9 | }, 10 | verbose: true 11 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flat", 3 | "version": "3.4.0", 4 | "description": "The GitHub action which powers data fetching for Flat", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "package": "ncc build --source-map --license LICENSE --target es2020 lib/main.js", 9 | "package-post": "ncc build --target es2020 lib/post.js -o dist/post", 10 | "dist": "npm run build && npm run package && npm run package-post", 11 | "format": "prettier --write **/*.ts", 12 | "test": "jest", 13 | "prepare": "husky install" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/githubocto/flat.git" 18 | }, 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/githubocto/flat/issues" 22 | }, 23 | "homepage": "https://github.com/githubocto/flat#readme", 24 | "dependencies": { 25 | "@actions/core": "^1.2.6", 26 | "@actions/exec": "^1.0.4", 27 | "@actions/github": "^4.0.0", 28 | "@tinyhttp/content-disposition": "^1.2.0", 29 | "axios": "^0.21.1", 30 | "connection-string": "^4.3.2", 31 | "csv-stringify": "^5.6.2", 32 | "es-mime-types": "^0.0.16", 33 | "mssql": "^6.3.1", 34 | "mysql": "^2.18.1", 35 | "pg": "^8.5.1", 36 | "reflect-metadata": "^0.1.13", 37 | "sqlite3": "^5.1.6", 38 | "typeorm": "^0.2.31", 39 | "zod": "^3.0.0-alpha.4" 40 | }, 41 | "devDependencies": { 42 | "@types/jest": "^26.0.20", 43 | "@types/node": "^14.14.37", 44 | "@vercel/ncc": "^0.27.0", 45 | "husky": "^6.0.0", 46 | "jest": "^26.6.3", 47 | "jest-circus": "^26.6.3", 48 | "prettier": "^2.2.1", 49 | "ts-jest": "^26.5.2", 50 | "typescript": "^4.1.5" 51 | }, 52 | "volta": { 53 | "node": "16.20.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/backends/http.test.ts: -------------------------------------------------------------------------------- 1 | import { AxiosResponse } from 'axios' 2 | import { HTTPConfig } from '../config' 3 | import fetchHTTP from './http' 4 | import * as core from '@actions/core' 5 | import axios from 'axios' 6 | import fs from 'fs' 7 | import { PassThrough } from 'stream' 8 | 9 | jest.mock('@actions/core') 10 | jest.mock('axios') 11 | jest.mock('fs') 12 | 13 | /* 14 | test('uses filename from content-disposition', () => { 15 | const response = { 16 | headers: { 17 | 'content-disposition': 'attachment; filename="filename.jpg"', 18 | 'content-type': 'text/html; charset=UTF-8', 19 | }, 20 | } 21 | const config = { 22 | outfile_basename: 'data', 23 | } 24 | expect( 25 | determineFilename(response as AxiosResponse, config as HTTPConfig) 26 | ).toEqual('filename.jpg') 27 | }) 28 | 29 | test('uses filename* from content-disposition', () => { 30 | const response = { 31 | headers: { 32 | 'content-disposition': 33 | 'attachment; filename="filename.jpg"; filename*=UTF-8\'\'f%C3%AEl%E2%82%ACname.jpg', 34 | 'content-type': 'text/html; charset=UTF-8', 35 | }, 36 | } 37 | const config = { 38 | outfile_basename: 'data', 39 | } 40 | expect( 41 | determineFilename(response as AxiosResponse, config as HTTPConfig) 42 | ).toEqual('fîl€name.jpg') 43 | }) 44 | 45 | test('uses content-type if content-disposition is not supplied', () => { 46 | const response = { 47 | headers: { 48 | 'content-type': 'text/html; charset=UTF-8', 49 | }, 50 | } 51 | const config = { 52 | outfile_basename: 'data', 53 | } 54 | expect( 55 | determineFilename(response as AxiosResponse, config as HTTPConfig) 56 | ).toEqual('data.html') 57 | }) 58 | 59 | test('ignores content-type if it is unrecognized', () => { 60 | const response = { 61 | headers: { 62 | 'content-type': 'foo/bar', 63 | }, 64 | } 65 | const config = { 66 | outfile_basename: 'data', 67 | } 68 | expect( 69 | determineFilename(response as AxiosResponse, config as HTTPConfig) 70 | ).toEqual('data') 71 | }) 72 | 73 | test('Uses outfile_basename when neither content-type or content-disposition is available', () => { 74 | const response = { 75 | headers: {}, 76 | } 77 | const config = { 78 | outfile_basename: 'data', 79 | } 80 | const coreMock = jest.spyOn(core, 'warning') 81 | expect( 82 | determineFilename(response as AxiosResponse, config as HTTPConfig) 83 | ).toEqual('data') 84 | expect(coreMock).toBeCalledTimes(1) 85 | }) 86 | 87 | it('fetches data over HTTP', async () => { 88 | const config = { 89 | outfile_basename: 'data', 90 | http_url: 'https://foo.bar', 91 | } 92 | 93 | const mockWritable = new PassThrough() 94 | const mockReadable = new PassThrough() 95 | const response = { 96 | headers: { 97 | 'content-disposition': 'attachment; filename="lala.txt"', 98 | 'content-type': 'text/plain; charset=UTF-8', 99 | }, 100 | data: mockReadable, 101 | } 102 | //@ts-ignore 103 | axios.get.mockResolvedValue(response) 104 | //@ts-ignore 105 | fs.createWriteStream.mockReturnValueOnce(mockWritable) 106 | mockWritable.end() 107 | 108 | expect(await fetchHTTP(config)).toBe('lala.txt') 109 | }) 110 | 111 | it('throws an error if HTTP request fails', async () => { 112 | const config = { 113 | outfile_basename: 'data', 114 | http_url: 'https://foo.bar', 115 | } 116 | 117 | const err = new Error('oh snap') 118 | //@ts-ignore 119 | axios.get.mockRejectedValue(err) 120 | 121 | await expect(fetchHTTP(config)).rejects.toEqual(err) 122 | }) 123 | */ -------------------------------------------------------------------------------- /src/backends/http.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import { HTTPConfig } from '../config' 3 | import fs from 'fs' 4 | import axios, { AxiosResponse } from 'axios' 5 | 6 | export default async function fetchHTTP(config: HTTPConfig): Promise { 7 | core.info('Fetching: HTTP') 8 | 9 | // Authorization headers 10 | const auth = { 11 | authorization: config.authorization, 12 | } 13 | const authHeader = config.authorization ? auth : {} 14 | 15 | let response: AxiosResponse 16 | 17 | try { 18 | if (config.axios_config) { 19 | const axiosConfig = fs.readFileSync(config.axios_config, { 20 | encoding: 'utf8', 21 | }) 22 | 23 | const parsed = JSON.parse(axiosConfig) 24 | 25 | const combinedWithOtherConfigValues = { 26 | ...parsed, 27 | url: config.http_url, 28 | headers: { 29 | ...parsed.headers, 30 | ...authHeader, 31 | }, 32 | responseType: 'stream', 33 | } 34 | 35 | response = await axios(combinedWithOtherConfigValues) 36 | } else { 37 | response = await axios.get(config.http_url, { 38 | method: 'get', 39 | responseType: 'stream', 40 | headers: { 41 | ...authHeader, 42 | }, 43 | }) 44 | } 45 | const filename = config.downloaded_filename 46 | const writer = fs.createWriteStream(filename) 47 | 48 | response.data.pipe(writer) 49 | await new Promise((resolve, reject) => { 50 | writer.on('finish', resolve) 51 | writer.on('error', reject) 52 | }) 53 | return filename 54 | } catch (error) { 55 | core.setFailed(error) 56 | throw error 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/backends/sql.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import { ConnectionString } from 'connection-string' 3 | import { createWriteStream, readFileSync, writeFileSync } from 'fs' 4 | import { createConnection, DatabaseType } from 'typeorm' 5 | import { SQLConfig } from '../config' 6 | import stringify from 'csv-stringify' 7 | 8 | // TODO: wish there was a dynamic way to import this for runtime usage from the DatabaseType type 9 | const TYPEORM_PROTOCOLS = [ 10 | 'mysql', 11 | 'postgres', 12 | 'cockroachdb', 13 | 'sap', 14 | 'mariadb', 15 | 'sqlite', 16 | 'cordova', 17 | 'react-native', 18 | 'nativescript', 19 | 'sqljs', 20 | 'oracle', 21 | 'mssql', 22 | 'mongodb', 23 | 'aurora-data-api', 24 | 'aurora-data-api-pg', 25 | 'expo', 26 | 'better-sqlite3', 27 | ] 28 | 29 | function isValidDatabaseType(protocol: string): protocol is DatabaseType { 30 | return TYPEORM_PROTOCOLS.includes(protocol) 31 | } 32 | 33 | export default async function fetchSQL(config: SQLConfig): Promise { 34 | core.info('Fetching: SQL') 35 | let connection 36 | let query 37 | 38 | core.debug('Reading query file') 39 | try { 40 | core.debug(`SQL Query file path: ${config.sql_queryfile}`) 41 | query = readFileSync(config.sql_queryfile, { encoding: 'utf8' }) 42 | } catch (error) { 43 | core.setFailed( 44 | `Unable to read queryfile ${config.sql_queryfile}: ${error.message}` 45 | ) 46 | throw error 47 | } 48 | 49 | core.debug('Connecting to database') 50 | const parsed = new ConnectionString(config.sql_connstring) 51 | try { 52 | const protocol = parsed.protocol 53 | if (!protocol) { 54 | throw new Error( 55 | 'Unable to determine the database protocol from the connection string' 56 | ) 57 | } 58 | if (!isValidDatabaseType(protocol)) { 59 | throw new Error( 60 | `The '${protocol}' protocol is not supported. Please choose one of: ${TYPEORM_PROTOCOLS.join( 61 | ', ' 62 | )}` 63 | ) 64 | } 65 | 66 | let userProvidedConfiguration = {} 67 | 68 | try { 69 | userProvidedConfiguration = config.typeorm_config 70 | ? JSON.parse(config.typeorm_config) 71 | : {} 72 | } catch (error) { 73 | core.setFailed( 74 | 'Failed to parse JSON string containing TypeORM configuration for createConnection function' 75 | ) 76 | } 77 | 78 | // @ts-ignore 79 | connection = await createConnection({ 80 | type: protocol, 81 | url: config.sql_connstring, 82 | ...userProvidedConfiguration, 83 | }) 84 | } catch (error) { 85 | core.setFailed(`Unable to connect to database: ${error.message}`) 86 | throw error 87 | } 88 | 89 | core.info('Querying database') 90 | let result 91 | try { 92 | result = await connection.query(query) 93 | } catch (error) { 94 | core.setFailed(`Unable to query database: ${error.message}`) 95 | throw error 96 | } 97 | 98 | core.info('Closing database') 99 | try { 100 | await connection.close() 101 | } catch (error) { 102 | core.setFailed(`Unable to close database: ${error.message}`) 103 | throw error 104 | } 105 | 106 | const outfile = `${config.downloaded_filename}` 107 | const sqlFormat = outfile.split('.').pop() // should be csv or json 108 | try { 109 | switch (sqlFormat) { 110 | case 'csv': 111 | core.info('Writing CSV') 112 | const writer = createWriteStream(outfile, { encoding: 'utf8' }) 113 | stringify(result, { 114 | header: true, 115 | }).pipe(writer) 116 | await new Promise((resolve, reject) => { 117 | writer.on('finish', resolve) 118 | writer.on('error', reject) 119 | }) 120 | break 121 | 122 | default: 123 | core.info('Writing JSON') 124 | await writeFileSync(outfile, JSON.stringify(result)) 125 | } 126 | return outfile 127 | } catch (error) { 128 | core.setFailed(`Unable to write results to ${outfile}: ${error.message}`) 129 | throw error 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/config.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Config, 3 | getConfig, 4 | HTTPConfig, 5 | isHTTPConfig, 6 | isSQLConfig, 7 | } from './config' 8 | import * as core from '@actions/core' 9 | jest.mock('@actions/core') 10 | 11 | it('returns an HTTP config', () => { 12 | const config = { 13 | http_url: 'https://google.com', 14 | outfile_basename: 'data', 15 | sql_queryfile: 'query.sql', 16 | sql_format: 'json', 17 | } 18 | const coreMock = jest.spyOn(core, 'getInput') 19 | // @ts-ignore 20 | coreMock.mockImplementation(k => config[k]) 21 | expect(getConfig()).toEqual({ 22 | http_url: 'https://google.com', 23 | outfile_basename: 'data', 24 | }) 25 | }) 26 | 27 | it('returns a SQL config', () => { 28 | const config = { 29 | sql_connstring: 'SECRETDATAHERE', 30 | outfile_basename: 'data', 31 | sql_queryfile: 'query.sql', 32 | sql_format: 'json', 33 | } 34 | const coreMock = jest.spyOn(core, 'getInput') 35 | // @ts-ignore 36 | coreMock.mockImplementation(k => config[k]) 37 | expect(getConfig()).toEqual({ 38 | sql_connstring: 'SECRETDATAHERE', 39 | outfile_basename: 'data', 40 | sql_queryfile: 'query.sql', 41 | sql_format: 'json', 42 | }) 43 | }) 44 | 45 | it('throws an error for a faulty HTTP config', () => { 46 | const config = { 47 | http_url: 'https://google.com', 48 | sql_queryfile: 'query.sql', 49 | sql_format: 'json', 50 | } 51 | const coreMock = jest.spyOn(core, 'getInput') 52 | // @ts-ignore 53 | coreMock.mockImplementation(k => config[k]) 54 | expect(getConfig).toThrowError(/^Invalid configuration!/) 55 | }) 56 | 57 | it('throws an error for a faulty SQL config', () => { 58 | const config = { 59 | sql_connstring: 'SECRETDATAHERE', 60 | outfile_basename: 'data', 61 | sql_queryfile: 'query.sql', 62 | } 63 | const coreMock = jest.spyOn(core, 'getInput') 64 | // @ts-ignore 65 | coreMock.mockImplementation(k => config[k]) 66 | expect(getConfig).toThrowError(/^Invalid configuration!/) 67 | }) 68 | 69 | it('throws an error if neither HTTP nor SQL is configured', () => { 70 | const config = { 71 | outfile_basename: 'data', 72 | sql_queryfile: 'query.sql', 73 | sql_format: 'json', 74 | } 75 | const coreMock = jest.spyOn(core, 'getInput') 76 | // @ts-ignore 77 | coreMock.mockImplementation(k => config[k]) 78 | expect(getConfig).toThrowError( 79 | 'One of `http_url` or `sql_connstring` inputs are required.' 80 | ) 81 | }) 82 | 83 | it('prefers HTTP configs', () => { 84 | const config = { 85 | http_url: 'https://google.com', 86 | sql_connstring: 'SECRETDATAHERE', 87 | outfile_basename: 'data', 88 | sql_queryfile: 'query.sql', 89 | sql_format: 'json', 90 | } 91 | const coreMock = jest.spyOn(core, 'getInput') 92 | // @ts-ignore 93 | coreMock.mockImplementation(k => config[k]) 94 | expect(getConfig()).toEqual({ 95 | http_url: 'https://google.com', 96 | outfile_basename: 'data', 97 | }) 98 | }) 99 | 100 | it('accepts a postprocess string', () => { 101 | const config = { 102 | http_url: 'https://google.com', 103 | outfile_basename: 'data', 104 | sql_queryfile: 'query.sql', 105 | sql_format: 'json', 106 | postprocess: 'path/to/script.ts', 107 | } 108 | const coreMock = jest.spyOn(core, 'getInput') 109 | // @ts-ignore 110 | coreMock.mockImplementation(k => config[k]) 111 | expect(getConfig()).toEqual({ 112 | http_url: config.http_url, 113 | outfile_basename: config.outfile_basename, 114 | postprocess: config.postprocess, 115 | }) 116 | }) 117 | 118 | /* 119 | it('correctly identifies configs', () => { 120 | const http: Config = { 121 | http_url: 'https://google.com', 122 | outfile_basename: 'data', 123 | sql_queryfile: 'query.sql', 124 | sql_format: 'json', 125 | postprocess: 'path/to/script.ts', 126 | } 127 | const sql: Config = { 128 | sql_connstring: 'SECRETDATAHERE', 129 | outfile_basename: 'data', 130 | sql_queryfile: 'query.sql', 131 | sql_format: 'json', 132 | } 133 | expect(isHTTPConfig(http)).toEqual(true) 134 | expect(isHTTPConfig(sql)).toEqual(false) 135 | expect(isSQLConfig(sql)).toEqual(true) 136 | expect(isSQLConfig(http)).toEqual(false) 137 | }) 138 | */ 139 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import * as z from 'zod' 3 | 4 | const FormatEnum = z.enum(['csv', 'json']) 5 | export type FormatEnum = z.infer 6 | 7 | const CommonConfigSchema = z.object({ 8 | downloaded_filename: z.string(), 9 | postprocess: z.string().optional(), 10 | }) 11 | export type CommonConfig = z.infer 12 | 13 | const HTTPConfigSchema = z 14 | .object({ 15 | axios_config: z.string().optional(), 16 | http_url: z.string(), 17 | authorization: z.string().optional(), 18 | mask: z.string().optional(), // string array of secrets or boolean 19 | }) 20 | .merge(CommonConfigSchema) 21 | export type HTTPConfig = z.infer 22 | 23 | const SQLConfigSchema = z 24 | .object({ 25 | sql_connstring: z.string(), 26 | sql_queryfile: z.string(), 27 | typeorm_config: z.string().optional(), 28 | }) 29 | .merge(CommonConfigSchema) 30 | export type SQLConfig = z.infer 31 | 32 | const ConfigSchema = z.union([HTTPConfigSchema, SQLConfigSchema]) 33 | export type Config = z.infer 34 | 35 | export function getConfig(): Config { 36 | const raw: { [k: string]: string } = {} 37 | const keys = [ 38 | 'axios_config', 39 | 'downloaded_filename', 40 | 'http_url', 41 | 'authorization', 42 | 'mask', 43 | 'sql_connstring', 44 | 'sql_queryfile', 45 | 'postprocess', 46 | 'typeorm_config', 47 | ] 48 | keys.forEach(k => { 49 | const v = core.getInput(k) // getInput always returns a string 50 | if (v) { 51 | raw[k] = v 52 | } 53 | }) 54 | core.debug(`Raw config: ${JSON.stringify(raw)}`) 55 | try { 56 | if ('http_url' in raw) { 57 | return HTTPConfigSchema.parse(raw) 58 | } else if ('sql_connstring' in raw) { 59 | return SQLConfigSchema.parse(raw) 60 | } else { 61 | throw new Error( 62 | 'One of `http_url` or `sql_connstring` inputs are required.' 63 | ) 64 | } 65 | } catch (error) { 66 | throw new Error( 67 | `Invalid configuration!\nReceived: ${JSON.stringify(raw)}\nFailure:${ 68 | error.message 69 | }` 70 | ) 71 | } 72 | } 73 | 74 | export function isHTTPConfig(config: Config): config is HTTPConfig { 75 | return 'http_url' in config 76 | } 77 | 78 | export function isSQLConfig(config: Config): config is SQLConfig { 79 | return 'sql_connstring' in config && 'sql_queryfile' in config 80 | } 81 | -------------------------------------------------------------------------------- /src/git.ts: -------------------------------------------------------------------------------- 1 | import { exec, ExecOptions } from '@actions/exec' 2 | import { statSync } from 'fs' 3 | import path from 'path' 4 | import * as core from '@actions/core' 5 | 6 | export type GitStatus = { 7 | flag: string 8 | path: string 9 | } 10 | 11 | export async function gitStatus(): Promise { 12 | core.debug('Getting gitStatus()') 13 | let output = '' 14 | await exec('git', ['status', '-s'], { 15 | listeners: { 16 | stdout: (data: Buffer) => { 17 | output += data.toString() 18 | }, 19 | }, 20 | }) 21 | core.debug(`=== output was:\n${output}`) 22 | return output 23 | .split('\n') 24 | .filter(l => l != '') 25 | .map(l => { 26 | const chunks = l.trim().split(/\s+/) 27 | return { 28 | flag: chunks[0], 29 | path: chunks[1], 30 | } as GitStatus 31 | }) 32 | } 33 | 34 | async function getHeadSize(path: string): Promise { 35 | let raw = '' 36 | const exitcode = await exec('git', ['cat-file', '-s', `HEAD:${path}`], { 37 | listeners: { 38 | stdline: (data: string) => { 39 | raw += data 40 | }, 41 | }, 42 | }) 43 | core.debug(`raw cat-file output: ${exitcode} '${raw}'`) 44 | if (exitcode === 0) { 45 | return parseInt(raw, 10) 46 | } 47 | } 48 | 49 | async function diffSize(file: GitStatus): Promise { 50 | switch (file.flag) { 51 | case 'M': { 52 | const stat = statSync(file.path) 53 | core.debug( 54 | `Calculating diff for ${JSON.stringify(file)}, with size ${stat.size}b` 55 | ) 56 | 57 | // get old size and compare 58 | const oldSize = await getHeadSize(file.path) 59 | const delta = oldSize === undefined ? stat.size : stat.size - oldSize 60 | core.debug( 61 | ` ==> ${file.path} modified: old ${oldSize}, new ${stat.size}, delta ${delta}b ` 62 | ) 63 | return delta 64 | } 65 | case 'A': { 66 | const stat = statSync(file.path) 67 | core.debug( 68 | `Calculating diff for ${JSON.stringify(file)}, with size ${stat.size}b` 69 | ) 70 | 71 | core.debug(` ==> ${file.path} added: delta ${stat.size}b`) 72 | return stat.size 73 | } 74 | case 'D': { 75 | const oldSize = await getHeadSize(file.path) 76 | const delta = oldSize === undefined ? 0 : oldSize 77 | core.debug(` ==> ${file.path} deleted: delta ${delta}b`) 78 | return delta 79 | } 80 | default: { 81 | throw new Error( 82 | `Encountered an unexpected file status in git: ${file.flag} ${file.path}` 83 | ) 84 | } 85 | } 86 | } 87 | 88 | export async function diff(filename: string): Promise { 89 | const statuses = await gitStatus() 90 | core.debug( 91 | `Parsed statuses: ${statuses.map(s => JSON.stringify(s)).join(', ')}` 92 | ) 93 | const status = statuses.find(s => path.relative(s.path, filename) === '') 94 | if (typeof status === 'undefined') { 95 | core.info(`No status found for ${filename}, aborting.`) 96 | return 0 // there's no change to the specified file 97 | } 98 | return await diffSize(status) 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import { exec } from '@actions/exec' 3 | import { execSync } from 'child_process' 4 | import fetchHTTP from './backends/http' 5 | import fetchSQL from './backends/sql' 6 | import { getConfig, isHTTPConfig, isSQLConfig } from './config' 7 | import { diff } from './git' 8 | 9 | async function run(): Promise { 10 | core.info('[INFO] Usage https://github.com/githubocto/flat#readme') 11 | core.startGroup('Configuration') 12 | const config = getConfig() 13 | const username = 'flat-data' 14 | await exec('git', ['config', 'user.name', username]) 15 | await exec('git', [ 16 | 'config', 17 | 'user.email', 18 | `${username}@users.noreply.github.com`, 19 | ]) 20 | core.endGroup() 21 | 22 | core.startGroup('Fetch data') 23 | let filename = '' 24 | let source 25 | let shouldMask = false // by default we don't mask the source 26 | let sourceMasked = '' 27 | if (isHTTPConfig(config)) { 28 | filename = await fetchHTTP(config) 29 | source = config.http_url 30 | 31 | // if including a mask config then we can strip out secrets from the http_url 32 | sourceMasked = source // if no secrets to mask then this is just source 33 | if (config.mask) { 34 | if (config.mask === 'true' || config.mask === 'false') { 35 | // mask param is a string 36 | shouldMask = JSON.parse(config.mask) // convert to boolean 37 | } else { 38 | try { 39 | const maskArray: string[] = JSON.parse(config.mask) 40 | maskArray.forEach((secretToMask: string) => { 41 | const regex = new RegExp(secretToMask, 'g') 42 | sourceMasked = sourceMasked.replace(regex, '***') 43 | }) 44 | } catch (error) { 45 | core.setFailed( 46 | 'Mask param formatted incorrectly. It should be a string array OR a "true" or "false" string.' 47 | ) 48 | } 49 | } 50 | } 51 | } else if (isSQLConfig(config)) { 52 | filename = await fetchSQL(config) 53 | } else { 54 | // typescript should preclude us from ever being here 55 | // because config is HTTPConfig | SQLConfig 56 | // But to be on the safe side, blow up if execution 57 | // has reached this point. 58 | core.setFailed('Unable to read a coherent action configuration') 59 | } 60 | core.endGroup() 61 | 62 | if (config.postprocess) { 63 | core.startGroup('Postprocess') 64 | core.debug(`Invoking ${config.postprocess} with ${filename}...`) 65 | try { 66 | const raw = execSync( 67 | `NO_COLOR=true deno run -q --allow-read --allow-write --allow-run --allow-net --allow-env --unstable ${config.postprocess} ${filename}` 68 | ).toString() 69 | 70 | core.info('Deno output:') 71 | core.info(raw) 72 | } catch (error) { 73 | core.setFailed(error) 74 | } 75 | core.endGroup() 76 | } 77 | 78 | core.startGroup('File changes') 79 | 80 | const newUnstagedFiles = await execSync( 81 | 'git ls-files --others --exclude-standard' 82 | ).toString() 83 | const modifiedUnstagedFiles = await execSync('git ls-files -m').toString() 84 | const editedFilenames = [ 85 | ...newUnstagedFiles.split('\n'), 86 | ...modifiedUnstagedFiles.split('\n'), 87 | ].filter(Boolean) 88 | 89 | core.info('newUnstagedFiles') 90 | core.info(newUnstagedFiles + '') 91 | core.info('modifiedUnstagedFiles') 92 | core.info(modifiedUnstagedFiles + '') 93 | core.info('editedFilenames') 94 | core.info(JSON.stringify(editedFilenames)) 95 | 96 | core.endGroup() 97 | 98 | core.startGroup('Calculating diffstat') 99 | 100 | const editedFiles = [] 101 | for (const filename of editedFilenames) { 102 | core.debug(`git adding ${filename}…`) 103 | await exec('git', ['add', filename]) 104 | const bytes = await diff(filename) 105 | 106 | const source = shouldMask ? {} : { source: sourceMasked } 107 | editedFiles.push({ name: filename, deltaBytes: bytes, ...source }) 108 | } 109 | core.endGroup() 110 | 111 | core.startGroup('Committing new data') 112 | 113 | const alreadyEditedFiles = JSON.parse(process.env.FILES || '[]') 114 | core.info('alreadyEditedFiles') 115 | core.info(JSON.stringify(alreadyEditedFiles)) 116 | 117 | core.info('editedFiles') 118 | core.info(JSON.stringify(editedFiles)) 119 | 120 | const files = [...alreadyEditedFiles, ...editedFiles] 121 | core.exportVariable('FILES', files) 122 | 123 | core.endGroup() 124 | } 125 | 126 | run().catch(error => { 127 | core.setFailed('Workflow failed! ' + error.message) 128 | }) 129 | -------------------------------------------------------------------------------- /src/post.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import { exec } from '@actions/exec' 3 | 4 | const run = async () => { 5 | core.startGroup('Post cleanup script') 6 | 7 | if (process.env.HAS_RUN_POST_JOB) { 8 | core.info('Files already committed') 9 | core.endGroup() 10 | return 11 | } 12 | 13 | const files = JSON.parse(process.env.FILES || '[]') 14 | 15 | const date = new Date().toISOString() 16 | const meta = JSON.stringify( 17 | { 18 | date, 19 | files, 20 | }, 21 | undefined, 22 | 2 23 | ) 24 | const msg = `Flat: latest data (${date})` 25 | 26 | // Don't want to commit if there aren't any files changed! 27 | if (!files.length) return 28 | 29 | // these should already be staged, in main.ts 30 | core.info(`Committing "${msg}"`) 31 | core.debug(meta) 32 | await exec('git', ['commit', '-m', msg + '\n' + meta]) 33 | await exec('git', ['push']) 34 | core.info(`Pushed!`) 35 | core.exportVariable('HAS_RUN_POST_JOB', 'true') 36 | 37 | core.endGroup() 38 | } 39 | 40 | run().catch(error => { 41 | core.setFailed('Post script failed! ' + error.message) 42 | }) 43 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "outDir": "./lib", 7 | "rootDir": "./src", 8 | "lib": ["es2020"], 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "esModuleInterop": true, 12 | "strictNullChecks": true, 13 | "emitDecoratorMetadata": true, 14 | "experimentalDecorators": true, 15 | "skipLibCheck": true, 16 | "forceConsistentCasingInFileNames": true 17 | }, 18 | "exclude": ["node_modules", "postprocess"] 19 | } 20 | --------------------------------------------------------------------------------