├── .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 |
--------------------------------------------------------------------------------