├── .eslintrc.yml ├── .github ├── dependabot.yml └── workflows │ ├── action-ci.yaml │ ├── codeql-analysis.yml │ └── eslint.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── action.yml ├── dist └── index.js ├── package-lock.json ├── package.json ├── src └── index.js └── tests ├── LICENSE_OFL.txt ├── NotoSans-Regular.ttf ├── NotoSans-Regular2.ttf ├── README.md └── check-test.py /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | - wesbos 3 | 4 | parser: "babel-eslint" 5 | 6 | rules: 7 | no-console: 8 | - off 9 | quotes: 0 10 | prettier/prettier: 11 | - singleQuote: false 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.github/workflows/action-ci.yaml: -------------------------------------------------------------------------------- 1 | name: Action CI 2 | 3 | on: 4 | schedule: 5 | - cron: "0 6 * * *" 6 | push: 7 | pull_request: 8 | 9 | jobs: 10 | ci-tests: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | python-version: [3.7, 3.8, 3.9] 15 | name: Action CI 16 | steps: 17 | - name: Check out source repository 18 | uses: actions/checkout@v2 19 | - name: Set up Python ${{ matrix.python-version }} environment 20 | uses: actions/setup-python@v1 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | - name: Python environment report 24 | run: python -c "import sys; print(sys.version)" 25 | - name: Action CI - default 26 | uses: wcys-co/fontbakery@master 27 | with: 28 | subcmd: "--help" 29 | - name: Action CI - default with single file 30 | uses: wcys-co/fontbakery@master 31 | with: 32 | subcmd: "check-profile" 33 | args: "tests/check-test.py" 34 | path: "tests/NotoSans-Regular.ttf" 35 | - name: Action CI - default with wildcard path 36 | uses: wcys-co/fontbakery@master 37 | with: 38 | subcmd: "check-profile" 39 | args: "tests/check-test.py" 40 | path: "tests/*.ttf" 41 | - name: Action CI - fontbakery master branch version 42 | uses: wcys-co/fontbakery@master 43 | with: 44 | subcmd: "check-profile" 45 | args: "tests/check-test.py" 46 | path: "tests/*.ttf" 47 | version: "master" 48 | - name: Action CI - fontbakery pinned release version 49 | uses: wcys-co/fontbakery@master 50 | with: 51 | subcmd: "check-profile" 52 | args: "tests/check-test.py" 53 | path: "tests/*.ttf" 54 | version: "0.7.31" 55 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 17 * * 4' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['javascript', 'python'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.github/workflows/eslint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node: ["12"] 11 | name: Node ${{ matrix.node }} eslint run 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Setup node 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node }} 18 | - name: Install eslint 19 | run: npm install eslint 20 | - name: Lint 21 | run: make lint 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.pyc 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # `@wcys-co/fontbakery` 4 | 5 | ## v1.0.0 6 | 7 | - install fontbakery script change to constant v0.7.31 8 | - rename dir to point to `wcys-co/fontbakery` 9 | - fork f-actions/font-bakery @ [`2c72f0a`](https://github.com/f-actions/font-bakery/tree/2c72f0a16da75a29beb080f0641ba6301d694cdf) 10 | 11 | # `@f-actions/font-bakery` 12 | 13 | ## v1.0.2 14 | 15 | - documentation updates 16 | - update eslint-plugin-react dependency to v7.20.5 17 | - update jest dependency to v26.3.0 18 | 19 | ## v1.0.1 20 | 21 | - update lodash dependency to v4.17.19 ([minor security vulnerability](https://github.com/f-actions/font-bakery/pull/17#event-3567011284)) 22 | 23 | ## v1.0.0 24 | 25 | - initial release 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dist: src/*.js package*.json 2 | npm i && npm run package 3 | 4 | update: 5 | npm update 6 | 7 | dev-update: 8 | npm update --dev 9 | 10 | lint: 11 | npm run lint 12 | 13 | .PHONY: dev-update update lint -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wcys-co/fontbakery GitHub Action 2 | 3 | ![Version](https://img.shields.io/github/v/release/wcys-co/fontbakery?sort=semver) 4 | [![Action CI](https://github.com/wcys-co/fontbakery/workflows/Action%20CI/badge.svg)](https://github.com/wcys-co/fontbakery/actions?query=workflow%3A%22Action+CI%22) 5 | [![Lint](https://github.com/wcys-co/fontbakery/workflows/Lint/badge.svg)](https://github.com/wcys-co/fontbakery/actions?query=workflow%3ALint) 6 | 7 | This GitHub Action installs the [`googlefonts/fontbakery@0.7.31`](https://github.com/googlefonts/fontbakery/) typeface project quality assurance tool and executes the tool on a user-specified filepath as part of a remote continuous integration testing pipeline. The Action requires a Python v3.6+ runner environment. 8 | 9 | ## Quick Start 10 | 11 | Create a yaml formatted GitHub Actions configuration file on the directory path `.github/workflows` in your source repository. Please review the GitHub Actions documentation for detailed instructions on the configuation file syntax. 12 | 13 | **Please note**: These steps require that the fonts are built in your CI workflow before the fontbakery testing steps are executed *or* are under git version control and pushed to a remote source repository directory path. The example below assumes a Makefile based build that uses the default make target. Customize the build command with the approach that you use in your project. 14 | 15 | ### Example workflow 16 | 17 | ```yaml 18 | name: Font Bakery QA Tests 19 | 20 | on: [push, pull_request] 21 | 22 | jobs: 23 | fontbakery: 24 | runs-on: ubuntu-latest 25 | name: Font Bakery QA tests # Customize to edit the string in your GitHub CI UI 26 | steps: 27 | - name: Check out source repository 28 | uses: actions/checkout@v2 29 | - name: Set up Python environment 30 | uses: actions/setup-python@v1 31 | with: 32 | python-version: "3.8" # supports any Py3.6+ version available in Actions 33 | - name: Build fonts 34 | run: make # enter your build shell commands here 35 | - name: fontbakery TTF checks 36 | uses: wcys-co/fontbakery@v1 37 | with: 38 | subcmd: "check-universal" # fontbakery sub-command 39 | args: "--loglevel WARN" # optional arguments to fontbakery 40 | path: "path/to/*.ttf" # font path relative to root of repository 41 | version: "latest" # optional, latest PyPI release is default 42 | - name: fontbakery OTF checks 43 | uses: wcys-co/fontbakery@v1 44 | with: 45 | subcmd: "check-universal" # fontbakery sub-command 46 | args: "--loglevel WARN" # optional arguments to fontbakery 47 | path: "path/to/*.otf" # font path relative to root of repository 48 | version: "latest" # optional, latest PyPI release is default 49 | ``` 50 | 51 | See the Inputs section below for details on default inputs and optional configuration settings. 52 | 53 | ## Inputs 54 | 55 | Configure the Action with the following settings: 56 | 57 | ### `args` 58 | 59 | **Optional** The non-path arguments to the fontbakery executable sub-command. For example, this is a location where the log level may be set. The setting below limits reporting to log levels of WARN and higher: 60 | 61 | ``` 62 | args: "--loglevel WARN" 63 | ``` 64 | 65 | See the fontbakery help menus for details on available options. 66 | 67 | ### `path` 68 | 69 | **Optional** The path to the font file(s). You may use wildcards in this path definition. Default: `build` directory 70 | 71 | ``` 72 | path: "path/to/*.ttf" 73 | ``` 74 | 75 | ### `subcmd` 76 | 77 | **Mandatory** The fontbakery sub-command. This specifies the test profile that is executed on your fonts. 78 | 79 | ``` 80 | subcmd: "check-universal" 81 | ``` 82 | 83 | See `fontbakery --help` or the [fontbakery documentation](https://font-bakery.readthedocs.io/en/stable/) for additional details. 84 | 85 | ### `version` 86 | 87 | **Optional** The fontbakery version that should be used for testing. This supports PyPI releases and direct source repository master branch installations. 88 | 89 | Default: "latest" = latest PyPI release version. 90 | 91 | Options: 92 | 93 | - "latest" = [latest PyPI release version](https://pypi.org/project/fontbakery/) (this approach will automatically bump the fontbakery version with new releases) 94 | - "master" = master branch HEAD commit (this approach will automatically bump the fontbakery version with new commits that are pushed to the master branch of the fontbakery source repository) 95 | - "[VERSION NUMBER]" = PyPI release version number, e.g. `"0.7.28"` (this approach pins the fontbakery package at a release version number) 96 | 97 | ## Outputs 98 | 99 | None 100 | 101 | ## License 102 | 103 | [Apache License, v2.0](LICENSE) 104 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Font Bakery CI" 2 | description: "Font Bakery QA testing" 3 | inputs: 4 | path: # id 5 | description: "Path to build artifact testing directory" 6 | required: false 7 | default: "build" 8 | subcmd: # id 9 | description: "Font Bakery subcommand" 10 | required: true 11 | args: 12 | description: "Font Bakery command line arguments" 13 | required: false 14 | default: "none" 15 | version: 16 | description: "Font Bakery version" 17 | required: false 18 | default: "latest" 19 | 20 | runs: 21 | using: "node12" 22 | main: "dist/index.js" 23 | 24 | branding: 25 | icon: "type" 26 | color: "purple" 27 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules, runtime) { // webpackBootstrap 3 | /******/ "use strict"; 4 | /******/ // The module cache 5 | /******/ var installedModules = {}; 6 | /******/ 7 | /******/ // The require function 8 | /******/ function __webpack_require__(moduleId) { 9 | /******/ 10 | /******/ // Check if module is in cache 11 | /******/ if(installedModules[moduleId]) { 12 | /******/ return installedModules[moduleId].exports; 13 | /******/ } 14 | /******/ // Create a new module (and put it into the cache) 15 | /******/ var module = installedModules[moduleId] = { 16 | /******/ i: moduleId, 17 | /******/ l: false, 18 | /******/ exports: {} 19 | /******/ }; 20 | /******/ 21 | /******/ // Execute the module function 22 | /******/ var threw = true; 23 | /******/ try { 24 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 25 | /******/ threw = false; 26 | /******/ } finally { 27 | /******/ if(threw) delete installedModules[moduleId]; 28 | /******/ } 29 | /******/ 30 | /******/ // Flag the module as loaded 31 | /******/ module.l = true; 32 | /******/ 33 | /******/ // Return the exports of the module 34 | /******/ return module.exports; 35 | /******/ } 36 | /******/ 37 | /******/ 38 | /******/ __webpack_require__.ab = __dirname + "/"; 39 | /******/ 40 | /******/ // the startup function 41 | /******/ function startup() { 42 | /******/ // Load entry module and return exports 43 | /******/ return __webpack_require__(676); 44 | /******/ }; 45 | /******/ 46 | /******/ // run startup 47 | /******/ return startup(); 48 | /******/ }) 49 | /************************************************************************/ 50 | /******/ ({ 51 | 52 | /***/ 1: 53 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 54 | 55 | "use strict"; 56 | 57 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 58 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 59 | return new (P || (P = Promise))(function (resolve, reject) { 60 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 61 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 62 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 63 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 64 | }); 65 | }; 66 | Object.defineProperty(exports, "__esModule", { value: true }); 67 | const childProcess = __webpack_require__(129); 68 | const path = __webpack_require__(622); 69 | const util_1 = __webpack_require__(669); 70 | const ioUtil = __webpack_require__(672); 71 | const exec = util_1.promisify(childProcess.exec); 72 | /** 73 | * Copies a file or folder. 74 | * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js 75 | * 76 | * @param source source path 77 | * @param dest destination path 78 | * @param options optional. See CopyOptions. 79 | */ 80 | function cp(source, dest, options = {}) { 81 | return __awaiter(this, void 0, void 0, function* () { 82 | const { force, recursive } = readCopyOptions(options); 83 | const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null; 84 | // Dest is an existing file, but not forcing 85 | if (destStat && destStat.isFile() && !force) { 86 | return; 87 | } 88 | // If dest is an existing directory, should copy inside. 89 | const newDest = destStat && destStat.isDirectory() 90 | ? path.join(dest, path.basename(source)) 91 | : dest; 92 | if (!(yield ioUtil.exists(source))) { 93 | throw new Error(`no such file or directory: ${source}`); 94 | } 95 | const sourceStat = yield ioUtil.stat(source); 96 | if (sourceStat.isDirectory()) { 97 | if (!recursive) { 98 | throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`); 99 | } 100 | else { 101 | yield cpDirRecursive(source, newDest, 0, force); 102 | } 103 | } 104 | else { 105 | if (path.relative(source, newDest) === '') { 106 | // a file cannot be copied to itself 107 | throw new Error(`'${newDest}' and '${source}' are the same file`); 108 | } 109 | yield copyFile(source, newDest, force); 110 | } 111 | }); 112 | } 113 | exports.cp = cp; 114 | /** 115 | * Moves a path. 116 | * 117 | * @param source source path 118 | * @param dest destination path 119 | * @param options optional. See MoveOptions. 120 | */ 121 | function mv(source, dest, options = {}) { 122 | return __awaiter(this, void 0, void 0, function* () { 123 | if (yield ioUtil.exists(dest)) { 124 | let destExists = true; 125 | if (yield ioUtil.isDirectory(dest)) { 126 | // If dest is directory copy src into dest 127 | dest = path.join(dest, path.basename(source)); 128 | destExists = yield ioUtil.exists(dest); 129 | } 130 | if (destExists) { 131 | if (options.force == null || options.force) { 132 | yield rmRF(dest); 133 | } 134 | else { 135 | throw new Error('Destination already exists'); 136 | } 137 | } 138 | } 139 | yield mkdirP(path.dirname(dest)); 140 | yield ioUtil.rename(source, dest); 141 | }); 142 | } 143 | exports.mv = mv; 144 | /** 145 | * Remove a path recursively with force 146 | * 147 | * @param inputPath path to remove 148 | */ 149 | function rmRF(inputPath) { 150 | return __awaiter(this, void 0, void 0, function* () { 151 | if (ioUtil.IS_WINDOWS) { 152 | // Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another 153 | // program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del. 154 | try { 155 | if (yield ioUtil.isDirectory(inputPath, true)) { 156 | yield exec(`rd /s /q "${inputPath}"`); 157 | } 158 | else { 159 | yield exec(`del /f /a "${inputPath}"`); 160 | } 161 | } 162 | catch (err) { 163 | // if you try to delete a file that doesn't exist, desired result is achieved 164 | // other errors are valid 165 | if (err.code !== 'ENOENT') 166 | throw err; 167 | } 168 | // Shelling out fails to remove a symlink folder with missing source, this unlink catches that 169 | try { 170 | yield ioUtil.unlink(inputPath); 171 | } 172 | catch (err) { 173 | // if you try to delete a file that doesn't exist, desired result is achieved 174 | // other errors are valid 175 | if (err.code !== 'ENOENT') 176 | throw err; 177 | } 178 | } 179 | else { 180 | let isDir = false; 181 | try { 182 | isDir = yield ioUtil.isDirectory(inputPath); 183 | } 184 | catch (err) { 185 | // if you try to delete a file that doesn't exist, desired result is achieved 186 | // other errors are valid 187 | if (err.code !== 'ENOENT') 188 | throw err; 189 | return; 190 | } 191 | if (isDir) { 192 | yield exec(`rm -rf "${inputPath}"`); 193 | } 194 | else { 195 | yield ioUtil.unlink(inputPath); 196 | } 197 | } 198 | }); 199 | } 200 | exports.rmRF = rmRF; 201 | /** 202 | * Make a directory. Creates the full path with folders in between 203 | * Will throw if it fails 204 | * 205 | * @param fsPath path to create 206 | * @returns Promise 207 | */ 208 | function mkdirP(fsPath) { 209 | return __awaiter(this, void 0, void 0, function* () { 210 | yield ioUtil.mkdirP(fsPath); 211 | }); 212 | } 213 | exports.mkdirP = mkdirP; 214 | /** 215 | * Returns path of a tool had the tool actually been invoked. Resolves via paths. 216 | * If you check and the tool does not exist, it will throw. 217 | * 218 | * @param tool name of the tool 219 | * @param check whether to check if tool exists 220 | * @returns Promise path to tool 221 | */ 222 | function which(tool, check) { 223 | return __awaiter(this, void 0, void 0, function* () { 224 | if (!tool) { 225 | throw new Error("parameter 'tool' is required"); 226 | } 227 | // recursive when check=true 228 | if (check) { 229 | const result = yield which(tool, false); 230 | if (!result) { 231 | if (ioUtil.IS_WINDOWS) { 232 | 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.`); 233 | } 234 | else { 235 | 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.`); 236 | } 237 | } 238 | } 239 | try { 240 | // build the list of extensions to try 241 | const extensions = []; 242 | if (ioUtil.IS_WINDOWS && process.env.PATHEXT) { 243 | for (const extension of process.env.PATHEXT.split(path.delimiter)) { 244 | if (extension) { 245 | extensions.push(extension); 246 | } 247 | } 248 | } 249 | // if it's rooted, return it if exists. otherwise return empty. 250 | if (ioUtil.isRooted(tool)) { 251 | const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions); 252 | if (filePath) { 253 | return filePath; 254 | } 255 | return ''; 256 | } 257 | // if any path separators, return empty 258 | if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) { 259 | return ''; 260 | } 261 | // build the list of directories 262 | // 263 | // Note, technically "where" checks the current directory on Windows. From a toolkit perspective, 264 | // it feels like we should not do this. Checking the current directory seems like more of a use 265 | // case of a shell, and the which() function exposed by the toolkit should strive for consistency 266 | // across platforms. 267 | const directories = []; 268 | if (process.env.PATH) { 269 | for (const p of process.env.PATH.split(path.delimiter)) { 270 | if (p) { 271 | directories.push(p); 272 | } 273 | } 274 | } 275 | // return the first match 276 | for (const directory of directories) { 277 | const filePath = yield ioUtil.tryGetExecutablePath(directory + path.sep + tool, extensions); 278 | if (filePath) { 279 | return filePath; 280 | } 281 | } 282 | return ''; 283 | } 284 | catch (err) { 285 | throw new Error(`which failed with message ${err.message}`); 286 | } 287 | }); 288 | } 289 | exports.which = which; 290 | function readCopyOptions(options) { 291 | const force = options.force == null ? true : options.force; 292 | const recursive = Boolean(options.recursive); 293 | return { force, recursive }; 294 | } 295 | function cpDirRecursive(sourceDir, destDir, currentDepth, force) { 296 | return __awaiter(this, void 0, void 0, function* () { 297 | // Ensure there is not a run away recursive copy 298 | if (currentDepth >= 255) 299 | return; 300 | currentDepth++; 301 | yield mkdirP(destDir); 302 | const files = yield ioUtil.readdir(sourceDir); 303 | for (const fileName of files) { 304 | const srcFile = `${sourceDir}/${fileName}`; 305 | const destFile = `${destDir}/${fileName}`; 306 | const srcFileStat = yield ioUtil.lstat(srcFile); 307 | if (srcFileStat.isDirectory()) { 308 | // Recurse 309 | yield cpDirRecursive(srcFile, destFile, currentDepth, force); 310 | } 311 | else { 312 | yield copyFile(srcFile, destFile, force); 313 | } 314 | } 315 | // Change the mode for the newly created directory 316 | yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode); 317 | }); 318 | } 319 | // Buffered file copy 320 | function copyFile(srcFile, destFile, force) { 321 | return __awaiter(this, void 0, void 0, function* () { 322 | if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) { 323 | // unlink/re-link it 324 | try { 325 | yield ioUtil.lstat(destFile); 326 | yield ioUtil.unlink(destFile); 327 | } 328 | catch (e) { 329 | // Try to override file permission 330 | if (e.code === 'EPERM') { 331 | yield ioUtil.chmod(destFile, '0666'); 332 | yield ioUtil.unlink(destFile); 333 | } 334 | // other errors = it doesn't exist, no work to do 335 | } 336 | // Copy over symlink 337 | const symlinkFull = yield ioUtil.readlink(srcFile); 338 | yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null); 339 | } 340 | else if (!(yield ioUtil.exists(destFile)) || force) { 341 | yield ioUtil.copyFile(srcFile, destFile); 342 | } 343 | }); 344 | } 345 | //# sourceMappingURL=io.js.map 346 | 347 | /***/ }), 348 | 349 | /***/ 9: 350 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 351 | 352 | "use strict"; 353 | 354 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 355 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 356 | return new (P || (P = Promise))(function (resolve, reject) { 357 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 358 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 359 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 360 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 361 | }); 362 | }; 363 | var __importStar = (this && this.__importStar) || function (mod) { 364 | if (mod && mod.__esModule) return mod; 365 | var result = {}; 366 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 367 | result["default"] = mod; 368 | return result; 369 | }; 370 | Object.defineProperty(exports, "__esModule", { value: true }); 371 | const os = __importStar(__webpack_require__(87)); 372 | const events = __importStar(__webpack_require__(614)); 373 | const child = __importStar(__webpack_require__(129)); 374 | const path = __importStar(__webpack_require__(622)); 375 | const io = __importStar(__webpack_require__(1)); 376 | const ioUtil = __importStar(__webpack_require__(672)); 377 | /* eslint-disable @typescript-eslint/unbound-method */ 378 | const IS_WINDOWS = process.platform === 'win32'; 379 | /* 380 | * Class for running command line tools. Handles quoting and arg parsing in a platform agnostic way. 381 | */ 382 | class ToolRunner extends events.EventEmitter { 383 | constructor(toolPath, args, options) { 384 | super(); 385 | if (!toolPath) { 386 | throw new Error("Parameter 'toolPath' cannot be null or empty."); 387 | } 388 | this.toolPath = toolPath; 389 | this.args = args || []; 390 | this.options = options || {}; 391 | } 392 | _debug(message) { 393 | if (this.options.listeners && this.options.listeners.debug) { 394 | this.options.listeners.debug(message); 395 | } 396 | } 397 | _getCommandString(options, noPrefix) { 398 | const toolPath = this._getSpawnFileName(); 399 | const args = this._getSpawnArgs(options); 400 | let cmd = noPrefix ? '' : '[command]'; // omit prefix when piped to a second tool 401 | if (IS_WINDOWS) { 402 | // Windows + cmd file 403 | if (this._isCmdFile()) { 404 | cmd += toolPath; 405 | for (const a of args) { 406 | cmd += ` ${a}`; 407 | } 408 | } 409 | // Windows + verbatim 410 | else if (options.windowsVerbatimArguments) { 411 | cmd += `"${toolPath}"`; 412 | for (const a of args) { 413 | cmd += ` ${a}`; 414 | } 415 | } 416 | // Windows (regular) 417 | else { 418 | cmd += this._windowsQuoteCmdArg(toolPath); 419 | for (const a of args) { 420 | cmd += ` ${this._windowsQuoteCmdArg(a)}`; 421 | } 422 | } 423 | } 424 | else { 425 | // OSX/Linux - this can likely be improved with some form of quoting. 426 | // creating processes on Unix is fundamentally different than Windows. 427 | // on Unix, execvp() takes an arg array. 428 | cmd += toolPath; 429 | for (const a of args) { 430 | cmd += ` ${a}`; 431 | } 432 | } 433 | return cmd; 434 | } 435 | _processLineBuffer(data, strBuffer, onLine) { 436 | try { 437 | let s = strBuffer + data.toString(); 438 | let n = s.indexOf(os.EOL); 439 | while (n > -1) { 440 | const line = s.substring(0, n); 441 | onLine(line); 442 | // the rest of the string ... 443 | s = s.substring(n + os.EOL.length); 444 | n = s.indexOf(os.EOL); 445 | } 446 | strBuffer = s; 447 | } 448 | catch (err) { 449 | // streaming lines to console is best effort. Don't fail a build. 450 | this._debug(`error processing line. Failed with error ${err}`); 451 | } 452 | } 453 | _getSpawnFileName() { 454 | if (IS_WINDOWS) { 455 | if (this._isCmdFile()) { 456 | return process.env['COMSPEC'] || 'cmd.exe'; 457 | } 458 | } 459 | return this.toolPath; 460 | } 461 | _getSpawnArgs(options) { 462 | if (IS_WINDOWS) { 463 | if (this._isCmdFile()) { 464 | let argline = `/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`; 465 | for (const a of this.args) { 466 | argline += ' '; 467 | argline += options.windowsVerbatimArguments 468 | ? a 469 | : this._windowsQuoteCmdArg(a); 470 | } 471 | argline += '"'; 472 | return [argline]; 473 | } 474 | } 475 | return this.args; 476 | } 477 | _endsWith(str, end) { 478 | return str.endsWith(end); 479 | } 480 | _isCmdFile() { 481 | const upperToolPath = this.toolPath.toUpperCase(); 482 | return (this._endsWith(upperToolPath, '.CMD') || 483 | this._endsWith(upperToolPath, '.BAT')); 484 | } 485 | _windowsQuoteCmdArg(arg) { 486 | // for .exe, apply the normal quoting rules that libuv applies 487 | if (!this._isCmdFile()) { 488 | return this._uvQuoteCmdArg(arg); 489 | } 490 | // otherwise apply quoting rules specific to the cmd.exe command line parser. 491 | // the libuv rules are generic and are not designed specifically for cmd.exe 492 | // command line parser. 493 | // 494 | // for a detailed description of the cmd.exe command line parser, refer to 495 | // http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912 496 | // need quotes for empty arg 497 | if (!arg) { 498 | return '""'; 499 | } 500 | // determine whether the arg needs to be quoted 501 | const cmdSpecialChars = [ 502 | ' ', 503 | '\t', 504 | '&', 505 | '(', 506 | ')', 507 | '[', 508 | ']', 509 | '{', 510 | '}', 511 | '^', 512 | '=', 513 | ';', 514 | '!', 515 | "'", 516 | '+', 517 | ',', 518 | '`', 519 | '~', 520 | '|', 521 | '<', 522 | '>', 523 | '"' 524 | ]; 525 | let needsQuotes = false; 526 | for (const char of arg) { 527 | if (cmdSpecialChars.some(x => x === char)) { 528 | needsQuotes = true; 529 | break; 530 | } 531 | } 532 | // short-circuit if quotes not needed 533 | if (!needsQuotes) { 534 | return arg; 535 | } 536 | // the following quoting rules are very similar to the rules that by libuv applies. 537 | // 538 | // 1) wrap the string in quotes 539 | // 540 | // 2) double-up quotes - i.e. " => "" 541 | // 542 | // this is different from the libuv quoting rules. libuv replaces " with \", which unfortunately 543 | // doesn't work well with a cmd.exe command line. 544 | // 545 | // note, replacing " with "" also works well if the arg is passed to a downstream .NET console app. 546 | // for example, the command line: 547 | // foo.exe "myarg:""my val""" 548 | // is parsed by a .NET console app into an arg array: 549 | // [ "myarg:\"my val\"" ] 550 | // which is the same end result when applying libuv quoting rules. although the actual 551 | // command line from libuv quoting rules would look like: 552 | // foo.exe "myarg:\"my val\"" 553 | // 554 | // 3) double-up slashes that precede a quote, 555 | // e.g. hello \world => "hello \world" 556 | // hello\"world => "hello\\""world" 557 | // hello\\"world => "hello\\\\""world" 558 | // hello world\ => "hello world\\" 559 | // 560 | // technically this is not required for a cmd.exe command line, or the batch argument parser. 561 | // the reasons for including this as a .cmd quoting rule are: 562 | // 563 | // a) this is optimized for the scenario where the argument is passed from the .cmd file to an 564 | // external program. many programs (e.g. .NET console apps) rely on the slash-doubling rule. 565 | // 566 | // b) it's what we've been doing previously (by deferring to node default behavior) and we 567 | // haven't heard any complaints about that aspect. 568 | // 569 | // note, a weakness of the quoting rules chosen here, is that % is not escaped. in fact, % cannot be 570 | // escaped when used on the command line directly - even though within a .cmd file % can be escaped 571 | // by using %%. 572 | // 573 | // the saving grace is, on the command line, %var% is left as-is if var is not defined. this contrasts 574 | // the line parsing rules within a .cmd file, where if var is not defined it is replaced with nothing. 575 | // 576 | // one option that was explored was replacing % with ^% - i.e. %var% => ^%var^%. this hack would 577 | // often work, since it is unlikely that var^ would exist, and the ^ character is removed when the 578 | // variable is used. the problem, however, is that ^ is not removed when %* is used to pass the args 579 | // to an external program. 580 | // 581 | // an unexplored potential solution for the % escaping problem, is to create a wrapper .cmd file. 582 | // % can be escaped within a .cmd file. 583 | let reverse = '"'; 584 | let quoteHit = true; 585 | for (let i = arg.length; i > 0; i--) { 586 | // walk the string in reverse 587 | reverse += arg[i - 1]; 588 | if (quoteHit && arg[i - 1] === '\\') { 589 | reverse += '\\'; // double the slash 590 | } 591 | else if (arg[i - 1] === '"') { 592 | quoteHit = true; 593 | reverse += '"'; // double the quote 594 | } 595 | else { 596 | quoteHit = false; 597 | } 598 | } 599 | reverse += '"'; 600 | return reverse 601 | .split('') 602 | .reverse() 603 | .join(''); 604 | } 605 | _uvQuoteCmdArg(arg) { 606 | // Tool runner wraps child_process.spawn() and needs to apply the same quoting as 607 | // Node in certain cases where the undocumented spawn option windowsVerbatimArguments 608 | // is used. 609 | // 610 | // Since this function is a port of quote_cmd_arg from Node 4.x (technically, lib UV, 611 | // see https://github.com/nodejs/node/blob/v4.x/deps/uv/src/win/process.c for details), 612 | // pasting copyright notice from Node within this function: 613 | // 614 | // Copyright Joyent, Inc. and other Node contributors. All rights reserved. 615 | // 616 | // Permission is hereby granted, free of charge, to any person obtaining a copy 617 | // of this software and associated documentation files (the "Software"), to 618 | // deal in the Software without restriction, including without limitation the 619 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 620 | // sell copies of the Software, and to permit persons to whom the Software is 621 | // furnished to do so, subject to the following conditions: 622 | // 623 | // The above copyright notice and this permission notice shall be included in 624 | // all copies or substantial portions of the Software. 625 | // 626 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 627 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 628 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 629 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 630 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 631 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 632 | // IN THE SOFTWARE. 633 | if (!arg) { 634 | // Need double quotation for empty argument 635 | return '""'; 636 | } 637 | if (!arg.includes(' ') && !arg.includes('\t') && !arg.includes('"')) { 638 | // No quotation needed 639 | return arg; 640 | } 641 | if (!arg.includes('"') && !arg.includes('\\')) { 642 | // No embedded double quotes or backslashes, so I can just wrap 643 | // quote marks around the whole thing. 644 | return `"${arg}"`; 645 | } 646 | // Expected input/output: 647 | // input : hello"world 648 | // output: "hello\"world" 649 | // input : hello""world 650 | // output: "hello\"\"world" 651 | // input : hello\world 652 | // output: hello\world 653 | // input : hello\\world 654 | // output: hello\\world 655 | // input : hello\"world 656 | // output: "hello\\\"world" 657 | // input : hello\\"world 658 | // output: "hello\\\\\"world" 659 | // input : hello world\ 660 | // output: "hello world\\" - note the comment in libuv actually reads "hello world\" 661 | // but it appears the comment is wrong, it should be "hello world\\" 662 | let reverse = '"'; 663 | let quoteHit = true; 664 | for (let i = arg.length; i > 0; i--) { 665 | // walk the string in reverse 666 | reverse += arg[i - 1]; 667 | if (quoteHit && arg[i - 1] === '\\') { 668 | reverse += '\\'; 669 | } 670 | else if (arg[i - 1] === '"') { 671 | quoteHit = true; 672 | reverse += '\\'; 673 | } 674 | else { 675 | quoteHit = false; 676 | } 677 | } 678 | reverse += '"'; 679 | return reverse 680 | .split('') 681 | .reverse() 682 | .join(''); 683 | } 684 | _cloneExecOptions(options) { 685 | options = options || {}; 686 | const result = { 687 | cwd: options.cwd || process.cwd(), 688 | env: options.env || process.env, 689 | silent: options.silent || false, 690 | windowsVerbatimArguments: options.windowsVerbatimArguments || false, 691 | failOnStdErr: options.failOnStdErr || false, 692 | ignoreReturnCode: options.ignoreReturnCode || false, 693 | delay: options.delay || 10000 694 | }; 695 | result.outStream = options.outStream || process.stdout; 696 | result.errStream = options.errStream || process.stderr; 697 | return result; 698 | } 699 | _getSpawnOptions(options, toolPath) { 700 | options = options || {}; 701 | const result = {}; 702 | result.cwd = options.cwd; 703 | result.env = options.env; 704 | result['windowsVerbatimArguments'] = 705 | options.windowsVerbatimArguments || this._isCmdFile(); 706 | if (options.windowsVerbatimArguments) { 707 | result.argv0 = `"${toolPath}"`; 708 | } 709 | return result; 710 | } 711 | /** 712 | * Exec a tool. 713 | * Output will be streamed to the live console. 714 | * Returns promise with return code 715 | * 716 | * @param tool path to tool to exec 717 | * @param options optional exec options. See ExecOptions 718 | * @returns number 719 | */ 720 | exec() { 721 | return __awaiter(this, void 0, void 0, function* () { 722 | // root the tool path if it is unrooted and contains relative pathing 723 | if (!ioUtil.isRooted(this.toolPath) && 724 | (this.toolPath.includes('/') || 725 | (IS_WINDOWS && this.toolPath.includes('\\')))) { 726 | // prefer options.cwd if it is specified, however options.cwd may also need to be rooted 727 | this.toolPath = path.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); 728 | } 729 | // if the tool is only a file name, then resolve it from the PATH 730 | // otherwise verify it exists (add extension on Windows if necessary) 731 | this.toolPath = yield io.which(this.toolPath, true); 732 | return new Promise((resolve, reject) => { 733 | this._debug(`exec tool: ${this.toolPath}`); 734 | this._debug('arguments:'); 735 | for (const arg of this.args) { 736 | this._debug(` ${arg}`); 737 | } 738 | const optionsNonNull = this._cloneExecOptions(this.options); 739 | if (!optionsNonNull.silent && optionsNonNull.outStream) { 740 | optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL); 741 | } 742 | const state = new ExecState(optionsNonNull, this.toolPath); 743 | state.on('debug', (message) => { 744 | this._debug(message); 745 | }); 746 | const fileName = this._getSpawnFileName(); 747 | const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName)); 748 | const stdbuffer = ''; 749 | if (cp.stdout) { 750 | cp.stdout.on('data', (data) => { 751 | if (this.options.listeners && this.options.listeners.stdout) { 752 | this.options.listeners.stdout(data); 753 | } 754 | if (!optionsNonNull.silent && optionsNonNull.outStream) { 755 | optionsNonNull.outStream.write(data); 756 | } 757 | this._processLineBuffer(data, stdbuffer, (line) => { 758 | if (this.options.listeners && this.options.listeners.stdline) { 759 | this.options.listeners.stdline(line); 760 | } 761 | }); 762 | }); 763 | } 764 | const errbuffer = ''; 765 | if (cp.stderr) { 766 | cp.stderr.on('data', (data) => { 767 | state.processStderr = true; 768 | if (this.options.listeners && this.options.listeners.stderr) { 769 | this.options.listeners.stderr(data); 770 | } 771 | if (!optionsNonNull.silent && 772 | optionsNonNull.errStream && 773 | optionsNonNull.outStream) { 774 | const s = optionsNonNull.failOnStdErr 775 | ? optionsNonNull.errStream 776 | : optionsNonNull.outStream; 777 | s.write(data); 778 | } 779 | this._processLineBuffer(data, errbuffer, (line) => { 780 | if (this.options.listeners && this.options.listeners.errline) { 781 | this.options.listeners.errline(line); 782 | } 783 | }); 784 | }); 785 | } 786 | cp.on('error', (err) => { 787 | state.processError = err.message; 788 | state.processExited = true; 789 | state.processClosed = true; 790 | state.CheckComplete(); 791 | }); 792 | cp.on('exit', (code) => { 793 | state.processExitCode = code; 794 | state.processExited = true; 795 | this._debug(`Exit code ${code} received from tool '${this.toolPath}'`); 796 | state.CheckComplete(); 797 | }); 798 | cp.on('close', (code) => { 799 | state.processExitCode = code; 800 | state.processExited = true; 801 | state.processClosed = true; 802 | this._debug(`STDIO streams have closed for tool '${this.toolPath}'`); 803 | state.CheckComplete(); 804 | }); 805 | state.on('done', (error, exitCode) => { 806 | if (stdbuffer.length > 0) { 807 | this.emit('stdline', stdbuffer); 808 | } 809 | if (errbuffer.length > 0) { 810 | this.emit('errline', errbuffer); 811 | } 812 | cp.removeAllListeners(); 813 | if (error) { 814 | reject(error); 815 | } 816 | else { 817 | resolve(exitCode); 818 | } 819 | }); 820 | if (this.options.input) { 821 | if (!cp.stdin) { 822 | throw new Error('child process missing stdin'); 823 | } 824 | cp.stdin.end(this.options.input); 825 | } 826 | }); 827 | }); 828 | } 829 | } 830 | exports.ToolRunner = ToolRunner; 831 | /** 832 | * Convert an arg string to an array of args. Handles escaping 833 | * 834 | * @param argString string of arguments 835 | * @returns string[] array of arguments 836 | */ 837 | function argStringToArray(argString) { 838 | const args = []; 839 | let inQuotes = false; 840 | let escaped = false; 841 | let arg = ''; 842 | function append(c) { 843 | // we only escape double quotes. 844 | if (escaped && c !== '"') { 845 | arg += '\\'; 846 | } 847 | arg += c; 848 | escaped = false; 849 | } 850 | for (let i = 0; i < argString.length; i++) { 851 | const c = argString.charAt(i); 852 | if (c === '"') { 853 | if (!escaped) { 854 | inQuotes = !inQuotes; 855 | } 856 | else { 857 | append(c); 858 | } 859 | continue; 860 | } 861 | if (c === '\\' && escaped) { 862 | append(c); 863 | continue; 864 | } 865 | if (c === '\\' && inQuotes) { 866 | escaped = true; 867 | continue; 868 | } 869 | if (c === ' ' && !inQuotes) { 870 | if (arg.length > 0) { 871 | args.push(arg); 872 | arg = ''; 873 | } 874 | continue; 875 | } 876 | append(c); 877 | } 878 | if (arg.length > 0) { 879 | args.push(arg.trim()); 880 | } 881 | return args; 882 | } 883 | exports.argStringToArray = argStringToArray; 884 | class ExecState extends events.EventEmitter { 885 | constructor(options, toolPath) { 886 | super(); 887 | this.processClosed = false; // tracks whether the process has exited and stdio is closed 888 | this.processError = ''; 889 | this.processExitCode = 0; 890 | this.processExited = false; // tracks whether the process has exited 891 | this.processStderr = false; // tracks whether stderr was written to 892 | this.delay = 10000; // 10 seconds 893 | this.done = false; 894 | this.timeout = null; 895 | if (!toolPath) { 896 | throw new Error('toolPath must not be empty'); 897 | } 898 | this.options = options; 899 | this.toolPath = toolPath; 900 | if (options.delay) { 901 | this.delay = options.delay; 902 | } 903 | } 904 | CheckComplete() { 905 | if (this.done) { 906 | return; 907 | } 908 | if (this.processClosed) { 909 | this._setResult(); 910 | } 911 | else if (this.processExited) { 912 | this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this); 913 | } 914 | } 915 | _debug(message) { 916 | this.emit('debug', message); 917 | } 918 | _setResult() { 919 | // determine whether there is an error 920 | let error; 921 | if (this.processExited) { 922 | if (this.processError) { 923 | 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}`); 924 | } 925 | else if (this.processExitCode !== 0 && !this.options.ignoreReturnCode) { 926 | error = new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`); 927 | } 928 | else if (this.processStderr && this.options.failOnStdErr) { 929 | error = new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`); 930 | } 931 | } 932 | // clear the timeout 933 | if (this.timeout) { 934 | clearTimeout(this.timeout); 935 | this.timeout = null; 936 | } 937 | this.done = true; 938 | this.emit('done', error, this.processExitCode); 939 | } 940 | static HandleTimeout(state) { 941 | if (state.done) { 942 | return; 943 | } 944 | if (!state.processClosed && state.processExited) { 945 | const message = `The STDIO streams did not close within ${state.delay / 946 | 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.`; 947 | state._debug(message); 948 | } 949 | state._setResult(); 950 | } 951 | } 952 | //# sourceMappingURL=toolrunner.js.map 953 | 954 | /***/ }), 955 | 956 | /***/ 87: 957 | /***/ (function(module) { 958 | 959 | module.exports = require("os"); 960 | 961 | /***/ }), 962 | 963 | /***/ 93: 964 | /***/ (function(module, __unusedexports, __webpack_require__) { 965 | 966 | module.exports = minimatch 967 | minimatch.Minimatch = Minimatch 968 | 969 | var path = { sep: '/' } 970 | try { 971 | path = __webpack_require__(622) 972 | } catch (er) {} 973 | 974 | var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} 975 | var expand = __webpack_require__(306) 976 | 977 | var plTypes = { 978 | '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, 979 | '?': { open: '(?:', close: ')?' }, 980 | '+': { open: '(?:', close: ')+' }, 981 | '*': { open: '(?:', close: ')*' }, 982 | '@': { open: '(?:', close: ')' } 983 | } 984 | 985 | // any single thing other than / 986 | // don't need to escape / when using new RegExp() 987 | var qmark = '[^/]' 988 | 989 | // * => any number of characters 990 | var star = qmark + '*?' 991 | 992 | // ** when dots are allowed. Anything goes, except .. and . 993 | // not (^ or / followed by one or two dots followed by $ or /), 994 | // followed by anything, any number of times. 995 | var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' 996 | 997 | // not a ^ or / followed by a dot, 998 | // followed by anything, any number of times. 999 | var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' 1000 | 1001 | // characters that need to be escaped in RegExp. 1002 | var reSpecials = charSet('().*{}+?[]^$\\!') 1003 | 1004 | // "abc" -> { a:true, b:true, c:true } 1005 | function charSet (s) { 1006 | return s.split('').reduce(function (set, c) { 1007 | set[c] = true 1008 | return set 1009 | }, {}) 1010 | } 1011 | 1012 | // normalizes slashes. 1013 | var slashSplit = /\/+/ 1014 | 1015 | minimatch.filter = filter 1016 | function filter (pattern, options) { 1017 | options = options || {} 1018 | return function (p, i, list) { 1019 | return minimatch(p, pattern, options) 1020 | } 1021 | } 1022 | 1023 | function ext (a, b) { 1024 | a = a || {} 1025 | b = b || {} 1026 | var t = {} 1027 | Object.keys(b).forEach(function (k) { 1028 | t[k] = b[k] 1029 | }) 1030 | Object.keys(a).forEach(function (k) { 1031 | t[k] = a[k] 1032 | }) 1033 | return t 1034 | } 1035 | 1036 | minimatch.defaults = function (def) { 1037 | if (!def || !Object.keys(def).length) return minimatch 1038 | 1039 | var orig = minimatch 1040 | 1041 | var m = function minimatch (p, pattern, options) { 1042 | return orig.minimatch(p, pattern, ext(def, options)) 1043 | } 1044 | 1045 | m.Minimatch = function Minimatch (pattern, options) { 1046 | return new orig.Minimatch(pattern, ext(def, options)) 1047 | } 1048 | 1049 | return m 1050 | } 1051 | 1052 | Minimatch.defaults = function (def) { 1053 | if (!def || !Object.keys(def).length) return Minimatch 1054 | return minimatch.defaults(def).Minimatch 1055 | } 1056 | 1057 | function minimatch (p, pattern, options) { 1058 | if (typeof pattern !== 'string') { 1059 | throw new TypeError('glob pattern string required') 1060 | } 1061 | 1062 | if (!options) options = {} 1063 | 1064 | // shortcut: comments match nothing. 1065 | if (!options.nocomment && pattern.charAt(0) === '#') { 1066 | return false 1067 | } 1068 | 1069 | // "" only matches "" 1070 | if (pattern.trim() === '') return p === '' 1071 | 1072 | return new Minimatch(pattern, options).match(p) 1073 | } 1074 | 1075 | function Minimatch (pattern, options) { 1076 | if (!(this instanceof Minimatch)) { 1077 | return new Minimatch(pattern, options) 1078 | } 1079 | 1080 | if (typeof pattern !== 'string') { 1081 | throw new TypeError('glob pattern string required') 1082 | } 1083 | 1084 | if (!options) options = {} 1085 | pattern = pattern.trim() 1086 | 1087 | // windows support: need to use /, not \ 1088 | if (path.sep !== '/') { 1089 | pattern = pattern.split(path.sep).join('/') 1090 | } 1091 | 1092 | this.options = options 1093 | this.set = [] 1094 | this.pattern = pattern 1095 | this.regexp = null 1096 | this.negate = false 1097 | this.comment = false 1098 | this.empty = false 1099 | 1100 | // make the set of regexps etc. 1101 | this.make() 1102 | } 1103 | 1104 | Minimatch.prototype.debug = function () {} 1105 | 1106 | Minimatch.prototype.make = make 1107 | function make () { 1108 | // don't do it more than once. 1109 | if (this._made) return 1110 | 1111 | var pattern = this.pattern 1112 | var options = this.options 1113 | 1114 | // empty patterns and comments match nothing. 1115 | if (!options.nocomment && pattern.charAt(0) === '#') { 1116 | this.comment = true 1117 | return 1118 | } 1119 | if (!pattern) { 1120 | this.empty = true 1121 | return 1122 | } 1123 | 1124 | // step 1: figure out negation, etc. 1125 | this.parseNegate() 1126 | 1127 | // step 2: expand braces 1128 | var set = this.globSet = this.braceExpand() 1129 | 1130 | if (options.debug) this.debug = console.error 1131 | 1132 | this.debug(this.pattern, set) 1133 | 1134 | // step 3: now we have a set, so turn each one into a series of path-portion 1135 | // matching patterns. 1136 | // These will be regexps, except in the case of "**", which is 1137 | // set to the GLOBSTAR object for globstar behavior, 1138 | // and will not contain any / characters 1139 | set = this.globParts = set.map(function (s) { 1140 | return s.split(slashSplit) 1141 | }) 1142 | 1143 | this.debug(this.pattern, set) 1144 | 1145 | // glob --> regexps 1146 | set = set.map(function (s, si, set) { 1147 | return s.map(this.parse, this) 1148 | }, this) 1149 | 1150 | this.debug(this.pattern, set) 1151 | 1152 | // filter out everything that didn't compile properly. 1153 | set = set.filter(function (s) { 1154 | return s.indexOf(false) === -1 1155 | }) 1156 | 1157 | this.debug(this.pattern, set) 1158 | 1159 | this.set = set 1160 | } 1161 | 1162 | Minimatch.prototype.parseNegate = parseNegate 1163 | function parseNegate () { 1164 | var pattern = this.pattern 1165 | var negate = false 1166 | var options = this.options 1167 | var negateOffset = 0 1168 | 1169 | if (options.nonegate) return 1170 | 1171 | for (var i = 0, l = pattern.length 1172 | ; i < l && pattern.charAt(i) === '!' 1173 | ; i++) { 1174 | negate = !negate 1175 | negateOffset++ 1176 | } 1177 | 1178 | if (negateOffset) this.pattern = pattern.substr(negateOffset) 1179 | this.negate = negate 1180 | } 1181 | 1182 | // Brace expansion: 1183 | // a{b,c}d -> abd acd 1184 | // a{b,}c -> abc ac 1185 | // a{0..3}d -> a0d a1d a2d a3d 1186 | // a{b,c{d,e}f}g -> abg acdfg acefg 1187 | // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg 1188 | // 1189 | // Invalid sets are not expanded. 1190 | // a{2..}b -> a{2..}b 1191 | // a{b}c -> a{b}c 1192 | minimatch.braceExpand = function (pattern, options) { 1193 | return braceExpand(pattern, options) 1194 | } 1195 | 1196 | Minimatch.prototype.braceExpand = braceExpand 1197 | 1198 | function braceExpand (pattern, options) { 1199 | if (!options) { 1200 | if (this instanceof Minimatch) { 1201 | options = this.options 1202 | } else { 1203 | options = {} 1204 | } 1205 | } 1206 | 1207 | pattern = typeof pattern === 'undefined' 1208 | ? this.pattern : pattern 1209 | 1210 | if (typeof pattern === 'undefined') { 1211 | throw new TypeError('undefined pattern') 1212 | } 1213 | 1214 | if (options.nobrace || 1215 | !pattern.match(/\{.*\}/)) { 1216 | // shortcut. no need to expand. 1217 | return [pattern] 1218 | } 1219 | 1220 | return expand(pattern) 1221 | } 1222 | 1223 | // parse a component of the expanded set. 1224 | // At this point, no pattern may contain "/" in it 1225 | // so we're going to return a 2d array, where each entry is the full 1226 | // pattern, split on '/', and then turned into a regular expression. 1227 | // A regexp is made at the end which joins each array with an 1228 | // escaped /, and another full one which joins each regexp with |. 1229 | // 1230 | // Following the lead of Bash 4.1, note that "**" only has special meaning 1231 | // when it is the *only* thing in a path portion. Otherwise, any series 1232 | // of * is equivalent to a single *. Globstar behavior is enabled by 1233 | // default, and can be disabled by setting options.noglobstar. 1234 | Minimatch.prototype.parse = parse 1235 | var SUBPARSE = {} 1236 | function parse (pattern, isSub) { 1237 | if (pattern.length > 1024 * 64) { 1238 | throw new TypeError('pattern is too long') 1239 | } 1240 | 1241 | var options = this.options 1242 | 1243 | // shortcuts 1244 | if (!options.noglobstar && pattern === '**') return GLOBSTAR 1245 | if (pattern === '') return '' 1246 | 1247 | var re = '' 1248 | var hasMagic = !!options.nocase 1249 | var escaping = false 1250 | // ? => one single character 1251 | var patternListStack = [] 1252 | var negativeLists = [] 1253 | var stateChar 1254 | var inClass = false 1255 | var reClassStart = -1 1256 | var classStart = -1 1257 | // . and .. never match anything that doesn't start with ., 1258 | // even when options.dot is set. 1259 | var patternStart = pattern.charAt(0) === '.' ? '' // anything 1260 | // not (start or / followed by . or .. followed by / or end) 1261 | : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' 1262 | : '(?!\\.)' 1263 | var self = this 1264 | 1265 | function clearStateChar () { 1266 | if (stateChar) { 1267 | // we had some state-tracking character 1268 | // that wasn't consumed by this pass. 1269 | switch (stateChar) { 1270 | case '*': 1271 | re += star 1272 | hasMagic = true 1273 | break 1274 | case '?': 1275 | re += qmark 1276 | hasMagic = true 1277 | break 1278 | default: 1279 | re += '\\' + stateChar 1280 | break 1281 | } 1282 | self.debug('clearStateChar %j %j', stateChar, re) 1283 | stateChar = false 1284 | } 1285 | } 1286 | 1287 | for (var i = 0, len = pattern.length, c 1288 | ; (i < len) && (c = pattern.charAt(i)) 1289 | ; i++) { 1290 | this.debug('%s\t%s %s %j', pattern, i, re, c) 1291 | 1292 | // skip over any that are escaped. 1293 | if (escaping && reSpecials[c]) { 1294 | re += '\\' + c 1295 | escaping = false 1296 | continue 1297 | } 1298 | 1299 | switch (c) { 1300 | case '/': 1301 | // completely not allowed, even escaped. 1302 | // Should already be path-split by now. 1303 | return false 1304 | 1305 | case '\\': 1306 | clearStateChar() 1307 | escaping = true 1308 | continue 1309 | 1310 | // the various stateChar values 1311 | // for the "extglob" stuff. 1312 | case '?': 1313 | case '*': 1314 | case '+': 1315 | case '@': 1316 | case '!': 1317 | this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) 1318 | 1319 | // all of those are literals inside a class, except that 1320 | // the glob [!a] means [^a] in regexp 1321 | if (inClass) { 1322 | this.debug(' in class') 1323 | if (c === '!' && i === classStart + 1) c = '^' 1324 | re += c 1325 | continue 1326 | } 1327 | 1328 | // if we already have a stateChar, then it means 1329 | // that there was something like ** or +? in there. 1330 | // Handle the stateChar, then proceed with this one. 1331 | self.debug('call clearStateChar %j', stateChar) 1332 | clearStateChar() 1333 | stateChar = c 1334 | // if extglob is disabled, then +(asdf|foo) isn't a thing. 1335 | // just clear the statechar *now*, rather than even diving into 1336 | // the patternList stuff. 1337 | if (options.noext) clearStateChar() 1338 | continue 1339 | 1340 | case '(': 1341 | if (inClass) { 1342 | re += '(' 1343 | continue 1344 | } 1345 | 1346 | if (!stateChar) { 1347 | re += '\\(' 1348 | continue 1349 | } 1350 | 1351 | patternListStack.push({ 1352 | type: stateChar, 1353 | start: i - 1, 1354 | reStart: re.length, 1355 | open: plTypes[stateChar].open, 1356 | close: plTypes[stateChar].close 1357 | }) 1358 | // negation is (?:(?!js)[^/]*) 1359 | re += stateChar === '!' ? '(?:(?!(?:' : '(?:' 1360 | this.debug('plType %j %j', stateChar, re) 1361 | stateChar = false 1362 | continue 1363 | 1364 | case ')': 1365 | if (inClass || !patternListStack.length) { 1366 | re += '\\)' 1367 | continue 1368 | } 1369 | 1370 | clearStateChar() 1371 | hasMagic = true 1372 | var pl = patternListStack.pop() 1373 | // negation is (?:(?!js)[^/]*) 1374 | // The others are (?:) 1375 | re += pl.close 1376 | if (pl.type === '!') { 1377 | negativeLists.push(pl) 1378 | } 1379 | pl.reEnd = re.length 1380 | continue 1381 | 1382 | case '|': 1383 | if (inClass || !patternListStack.length || escaping) { 1384 | re += '\\|' 1385 | escaping = false 1386 | continue 1387 | } 1388 | 1389 | clearStateChar() 1390 | re += '|' 1391 | continue 1392 | 1393 | // these are mostly the same in regexp and glob 1394 | case '[': 1395 | // swallow any state-tracking char before the [ 1396 | clearStateChar() 1397 | 1398 | if (inClass) { 1399 | re += '\\' + c 1400 | continue 1401 | } 1402 | 1403 | inClass = true 1404 | classStart = i 1405 | reClassStart = re.length 1406 | re += c 1407 | continue 1408 | 1409 | case ']': 1410 | // a right bracket shall lose its special 1411 | // meaning and represent itself in 1412 | // a bracket expression if it occurs 1413 | // first in the list. -- POSIX.2 2.8.3.2 1414 | if (i === classStart + 1 || !inClass) { 1415 | re += '\\' + c 1416 | escaping = false 1417 | continue 1418 | } 1419 | 1420 | // handle the case where we left a class open. 1421 | // "[z-a]" is valid, equivalent to "\[z-a\]" 1422 | if (inClass) { 1423 | // split where the last [ was, make sure we don't have 1424 | // an invalid re. if so, re-walk the contents of the 1425 | // would-be class to re-translate any characters that 1426 | // were passed through as-is 1427 | // TODO: It would probably be faster to determine this 1428 | // without a try/catch and a new RegExp, but it's tricky 1429 | // to do safely. For now, this is safe and works. 1430 | var cs = pattern.substring(classStart + 1, i) 1431 | try { 1432 | RegExp('[' + cs + ']') 1433 | } catch (er) { 1434 | // not a valid class! 1435 | var sp = this.parse(cs, SUBPARSE) 1436 | re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' 1437 | hasMagic = hasMagic || sp[1] 1438 | inClass = false 1439 | continue 1440 | } 1441 | } 1442 | 1443 | // finish up the class. 1444 | hasMagic = true 1445 | inClass = false 1446 | re += c 1447 | continue 1448 | 1449 | default: 1450 | // swallow any state char that wasn't consumed 1451 | clearStateChar() 1452 | 1453 | if (escaping) { 1454 | // no need 1455 | escaping = false 1456 | } else if (reSpecials[c] 1457 | && !(c === '^' && inClass)) { 1458 | re += '\\' 1459 | } 1460 | 1461 | re += c 1462 | 1463 | } // switch 1464 | } // for 1465 | 1466 | // handle the case where we left a class open. 1467 | // "[abc" is valid, equivalent to "\[abc" 1468 | if (inClass) { 1469 | // split where the last [ was, and escape it 1470 | // this is a huge pita. We now have to re-walk 1471 | // the contents of the would-be class to re-translate 1472 | // any characters that were passed through as-is 1473 | cs = pattern.substr(classStart + 1) 1474 | sp = this.parse(cs, SUBPARSE) 1475 | re = re.substr(0, reClassStart) + '\\[' + sp[0] 1476 | hasMagic = hasMagic || sp[1] 1477 | } 1478 | 1479 | // handle the case where we had a +( thing at the *end* 1480 | // of the pattern. 1481 | // each pattern list stack adds 3 chars, and we need to go through 1482 | // and escape any | chars that were passed through as-is for the regexp. 1483 | // Go through and escape them, taking care not to double-escape any 1484 | // | chars that were already escaped. 1485 | for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { 1486 | var tail = re.slice(pl.reStart + pl.open.length) 1487 | this.debug('setting tail', re, pl) 1488 | // maybe some even number of \, then maybe 1 \, followed by a | 1489 | tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { 1490 | if (!$2) { 1491 | // the | isn't already escaped, so escape it. 1492 | $2 = '\\' 1493 | } 1494 | 1495 | // need to escape all those slashes *again*, without escaping the 1496 | // one that we need for escaping the | character. As it works out, 1497 | // escaping an even number of slashes can be done by simply repeating 1498 | // it exactly after itself. That's why this trick works. 1499 | // 1500 | // I am sorry that you have to see this. 1501 | return $1 + $1 + $2 + '|' 1502 | }) 1503 | 1504 | this.debug('tail=%j\n %s', tail, tail, pl, re) 1505 | var t = pl.type === '*' ? star 1506 | : pl.type === '?' ? qmark 1507 | : '\\' + pl.type 1508 | 1509 | hasMagic = true 1510 | re = re.slice(0, pl.reStart) + t + '\\(' + tail 1511 | } 1512 | 1513 | // handle trailing things that only matter at the very end. 1514 | clearStateChar() 1515 | if (escaping) { 1516 | // trailing \\ 1517 | re += '\\\\' 1518 | } 1519 | 1520 | // only need to apply the nodot start if the re starts with 1521 | // something that could conceivably capture a dot 1522 | var addPatternStart = false 1523 | switch (re.charAt(0)) { 1524 | case '.': 1525 | case '[': 1526 | case '(': addPatternStart = true 1527 | } 1528 | 1529 | // Hack to work around lack of negative lookbehind in JS 1530 | // A pattern like: *.!(x).!(y|z) needs to ensure that a name 1531 | // like 'a.xyz.yz' doesn't match. So, the first negative 1532 | // lookahead, has to look ALL the way ahead, to the end of 1533 | // the pattern. 1534 | for (var n = negativeLists.length - 1; n > -1; n--) { 1535 | var nl = negativeLists[n] 1536 | 1537 | var nlBefore = re.slice(0, nl.reStart) 1538 | var nlFirst = re.slice(nl.reStart, nl.reEnd - 8) 1539 | var nlLast = re.slice(nl.reEnd - 8, nl.reEnd) 1540 | var nlAfter = re.slice(nl.reEnd) 1541 | 1542 | nlLast += nlAfter 1543 | 1544 | // Handle nested stuff like *(*.js|!(*.json)), where open parens 1545 | // mean that we should *not* include the ) in the bit that is considered 1546 | // "after" the negated section. 1547 | var openParensBefore = nlBefore.split('(').length - 1 1548 | var cleanAfter = nlAfter 1549 | for (i = 0; i < openParensBefore; i++) { 1550 | cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') 1551 | } 1552 | nlAfter = cleanAfter 1553 | 1554 | var dollar = '' 1555 | if (nlAfter === '' && isSub !== SUBPARSE) { 1556 | dollar = '$' 1557 | } 1558 | var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast 1559 | re = newRe 1560 | } 1561 | 1562 | // if the re is not "" at this point, then we need to make sure 1563 | // it doesn't match against an empty path part. 1564 | // Otherwise a/* will match a/, which it should not. 1565 | if (re !== '' && hasMagic) { 1566 | re = '(?=.)' + re 1567 | } 1568 | 1569 | if (addPatternStart) { 1570 | re = patternStart + re 1571 | } 1572 | 1573 | // parsing just a piece of a larger pattern. 1574 | if (isSub === SUBPARSE) { 1575 | return [re, hasMagic] 1576 | } 1577 | 1578 | // skip the regexp for non-magical patterns 1579 | // unescape anything in it, though, so that it'll be 1580 | // an exact match against a file etc. 1581 | if (!hasMagic) { 1582 | return globUnescape(pattern) 1583 | } 1584 | 1585 | var flags = options.nocase ? 'i' : '' 1586 | try { 1587 | var regExp = new RegExp('^' + re + '$', flags) 1588 | } catch (er) { 1589 | // If it was an invalid regular expression, then it can't match 1590 | // anything. This trick looks for a character after the end of 1591 | // the string, which is of course impossible, except in multi-line 1592 | // mode, but it's not a /m regex. 1593 | return new RegExp('$.') 1594 | } 1595 | 1596 | regExp._glob = pattern 1597 | regExp._src = re 1598 | 1599 | return regExp 1600 | } 1601 | 1602 | minimatch.makeRe = function (pattern, options) { 1603 | return new Minimatch(pattern, options || {}).makeRe() 1604 | } 1605 | 1606 | Minimatch.prototype.makeRe = makeRe 1607 | function makeRe () { 1608 | if (this.regexp || this.regexp === false) return this.regexp 1609 | 1610 | // at this point, this.set is a 2d array of partial 1611 | // pattern strings, or "**". 1612 | // 1613 | // It's better to use .match(). This function shouldn't 1614 | // be used, really, but it's pretty convenient sometimes, 1615 | // when you just want to work with a regex. 1616 | var set = this.set 1617 | 1618 | if (!set.length) { 1619 | this.regexp = false 1620 | return this.regexp 1621 | } 1622 | var options = this.options 1623 | 1624 | var twoStar = options.noglobstar ? star 1625 | : options.dot ? twoStarDot 1626 | : twoStarNoDot 1627 | var flags = options.nocase ? 'i' : '' 1628 | 1629 | var re = set.map(function (pattern) { 1630 | return pattern.map(function (p) { 1631 | return (p === GLOBSTAR) ? twoStar 1632 | : (typeof p === 'string') ? regExpEscape(p) 1633 | : p._src 1634 | }).join('\\\/') 1635 | }).join('|') 1636 | 1637 | // must match entire pattern 1638 | // ending in a * or ** will make it less strict. 1639 | re = '^(?:' + re + ')$' 1640 | 1641 | // can match anything, as long as it's not this. 1642 | if (this.negate) re = '^(?!' + re + ').*$' 1643 | 1644 | try { 1645 | this.regexp = new RegExp(re, flags) 1646 | } catch (ex) { 1647 | this.regexp = false 1648 | } 1649 | return this.regexp 1650 | } 1651 | 1652 | minimatch.match = function (list, pattern, options) { 1653 | options = options || {} 1654 | var mm = new Minimatch(pattern, options) 1655 | list = list.filter(function (f) { 1656 | return mm.match(f) 1657 | }) 1658 | if (mm.options.nonull && !list.length) { 1659 | list.push(pattern) 1660 | } 1661 | return list 1662 | } 1663 | 1664 | Minimatch.prototype.match = match 1665 | function match (f, partial) { 1666 | this.debug('match', f, this.pattern) 1667 | // short-circuit in the case of busted things. 1668 | // comments, etc. 1669 | if (this.comment) return false 1670 | if (this.empty) return f === '' 1671 | 1672 | if (f === '/' && partial) return true 1673 | 1674 | var options = this.options 1675 | 1676 | // windows: need to use /, not \ 1677 | if (path.sep !== '/') { 1678 | f = f.split(path.sep).join('/') 1679 | } 1680 | 1681 | // treat the test path as a set of pathparts. 1682 | f = f.split(slashSplit) 1683 | this.debug(this.pattern, 'split', f) 1684 | 1685 | // just ONE of the pattern sets in this.set needs to match 1686 | // in order for it to be valid. If negating, then just one 1687 | // match means that we have failed. 1688 | // Either way, return on the first hit. 1689 | 1690 | var set = this.set 1691 | this.debug(this.pattern, 'set', set) 1692 | 1693 | // Find the basename of the path by looking for the last non-empty segment 1694 | var filename 1695 | var i 1696 | for (i = f.length - 1; i >= 0; i--) { 1697 | filename = f[i] 1698 | if (filename) break 1699 | } 1700 | 1701 | for (i = 0; i < set.length; i++) { 1702 | var pattern = set[i] 1703 | var file = f 1704 | if (options.matchBase && pattern.length === 1) { 1705 | file = [filename] 1706 | } 1707 | var hit = this.matchOne(file, pattern, partial) 1708 | if (hit) { 1709 | if (options.flipNegate) return true 1710 | return !this.negate 1711 | } 1712 | } 1713 | 1714 | // didn't get any hits. this is success if it's a negative 1715 | // pattern, failure otherwise. 1716 | if (options.flipNegate) return false 1717 | return this.negate 1718 | } 1719 | 1720 | // set partial to true to test if, for example, 1721 | // "/a/b" matches the start of "/*/b/*/d" 1722 | // Partial means, if you run out of file before you run 1723 | // out of pattern, then that's fine, as long as all 1724 | // the parts match. 1725 | Minimatch.prototype.matchOne = function (file, pattern, partial) { 1726 | var options = this.options 1727 | 1728 | this.debug('matchOne', 1729 | { 'this': this, file: file, pattern: pattern }) 1730 | 1731 | this.debug('matchOne', file.length, pattern.length) 1732 | 1733 | for (var fi = 0, 1734 | pi = 0, 1735 | fl = file.length, 1736 | pl = pattern.length 1737 | ; (fi < fl) && (pi < pl) 1738 | ; fi++, pi++) { 1739 | this.debug('matchOne loop') 1740 | var p = pattern[pi] 1741 | var f = file[fi] 1742 | 1743 | this.debug(pattern, p, f) 1744 | 1745 | // should be impossible. 1746 | // some invalid regexp stuff in the set. 1747 | if (p === false) return false 1748 | 1749 | if (p === GLOBSTAR) { 1750 | this.debug('GLOBSTAR', [pattern, p, f]) 1751 | 1752 | // "**" 1753 | // a/**/b/**/c would match the following: 1754 | // a/b/x/y/z/c 1755 | // a/x/y/z/b/c 1756 | // a/b/x/b/x/c 1757 | // a/b/c 1758 | // To do this, take the rest of the pattern after 1759 | // the **, and see if it would match the file remainder. 1760 | // If so, return success. 1761 | // If not, the ** "swallows" a segment, and try again. 1762 | // This is recursively awful. 1763 | // 1764 | // a/**/b/**/c matching a/b/x/y/z/c 1765 | // - a matches a 1766 | // - doublestar 1767 | // - matchOne(b/x/y/z/c, b/**/c) 1768 | // - b matches b 1769 | // - doublestar 1770 | // - matchOne(x/y/z/c, c) -> no 1771 | // - matchOne(y/z/c, c) -> no 1772 | // - matchOne(z/c, c) -> no 1773 | // - matchOne(c, c) yes, hit 1774 | var fr = fi 1775 | var pr = pi + 1 1776 | if (pr === pl) { 1777 | this.debug('** at the end') 1778 | // a ** at the end will just swallow the rest. 1779 | // We have found a match. 1780 | // however, it will not swallow /.x, unless 1781 | // options.dot is set. 1782 | // . and .. are *never* matched by **, for explosively 1783 | // exponential reasons. 1784 | for (; fi < fl; fi++) { 1785 | if (file[fi] === '.' || file[fi] === '..' || 1786 | (!options.dot && file[fi].charAt(0) === '.')) return false 1787 | } 1788 | return true 1789 | } 1790 | 1791 | // ok, let's see if we can swallow whatever we can. 1792 | while (fr < fl) { 1793 | var swallowee = file[fr] 1794 | 1795 | this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) 1796 | 1797 | // XXX remove this slice. Just pass the start index. 1798 | if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { 1799 | this.debug('globstar found match!', fr, fl, swallowee) 1800 | // found a match. 1801 | return true 1802 | } else { 1803 | // can't swallow "." or ".." ever. 1804 | // can only swallow ".foo" when explicitly asked. 1805 | if (swallowee === '.' || swallowee === '..' || 1806 | (!options.dot && swallowee.charAt(0) === '.')) { 1807 | this.debug('dot detected!', file, fr, pattern, pr) 1808 | break 1809 | } 1810 | 1811 | // ** swallows a segment, and continue. 1812 | this.debug('globstar swallow a segment, and continue') 1813 | fr++ 1814 | } 1815 | } 1816 | 1817 | // no match was found. 1818 | // However, in partial mode, we can't say this is necessarily over. 1819 | // If there's more *pattern* left, then 1820 | if (partial) { 1821 | // ran out of file 1822 | this.debug('\n>>> no match, partial?', file, fr, pattern, pr) 1823 | if (fr === fl) return true 1824 | } 1825 | return false 1826 | } 1827 | 1828 | // something other than ** 1829 | // non-magic patterns just have to match exactly 1830 | // patterns with magic have been turned into regexps. 1831 | var hit 1832 | if (typeof p === 'string') { 1833 | if (options.nocase) { 1834 | hit = f.toLowerCase() === p.toLowerCase() 1835 | } else { 1836 | hit = f === p 1837 | } 1838 | this.debug('string match', p, f, hit) 1839 | } else { 1840 | hit = f.match(p) 1841 | this.debug('pattern match', p, f, hit) 1842 | } 1843 | 1844 | if (!hit) return false 1845 | } 1846 | 1847 | // Note: ending in / means that we'll get a final "" 1848 | // at the end of the pattern. This can only match a 1849 | // corresponding "" at the end of the file. 1850 | // If the file ends in /, then it can only match a 1851 | // a pattern that ends in /, unless the pattern just 1852 | // doesn't have any more for it. But, a/b/ should *not* 1853 | // match "a/b/*", even though "" matches against the 1854 | // [^/]*? pattern, except in partial mode, where it might 1855 | // simply not be reached yet. 1856 | // However, a/b/ should still satisfy a/* 1857 | 1858 | // now either we fell off the end of the pattern, or we're done. 1859 | if (fi === fl && pi === pl) { 1860 | // ran out of pattern and filename at the same time. 1861 | // an exact hit! 1862 | return true 1863 | } else if (fi === fl) { 1864 | // ran out of file, but still had pattern left. 1865 | // this is ok if we're doing the match as part of 1866 | // a glob fs traversal. 1867 | return partial 1868 | } else if (pi === pl) { 1869 | // ran out of pattern, still have file left. 1870 | // this is only acceptable if we're on the very last 1871 | // empty segment of a file with a trailing slash. 1872 | // a/* should match a/b/ 1873 | var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') 1874 | return emptyFileEnd 1875 | } 1876 | 1877 | // should be unreachable. 1878 | throw new Error('wtf?') 1879 | } 1880 | 1881 | // replace stuff like \* with * 1882 | function globUnescape (s) { 1883 | return s.replace(/\\(.)/g, '$1') 1884 | } 1885 | 1886 | function regExpEscape (s) { 1887 | return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') 1888 | } 1889 | 1890 | 1891 | /***/ }), 1892 | 1893 | /***/ 129: 1894 | /***/ (function(module) { 1895 | 1896 | module.exports = require("child_process"); 1897 | 1898 | /***/ }), 1899 | 1900 | /***/ 281: 1901 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 1902 | 1903 | "use strict"; 1904 | 1905 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1906 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1907 | return new (P || (P = Promise))(function (resolve, reject) { 1908 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1909 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1910 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1911 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1912 | }); 1913 | }; 1914 | Object.defineProperty(exports, "__esModule", { value: true }); 1915 | const internal_globber_1 = __webpack_require__(297); 1916 | /** 1917 | * Constructs a globber 1918 | * 1919 | * @param patterns Patterns separated by newlines 1920 | * @param options Glob options 1921 | */ 1922 | function create(patterns, options) { 1923 | return __awaiter(this, void 0, void 0, function* () { 1924 | return yield internal_globber_1.DefaultGlobber.create(patterns, options); 1925 | }); 1926 | } 1927 | exports.create = create; 1928 | //# sourceMappingURL=glob.js.map 1929 | 1930 | /***/ }), 1931 | 1932 | /***/ 297: 1933 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 1934 | 1935 | "use strict"; 1936 | 1937 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1938 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1939 | return new (P || (P = Promise))(function (resolve, reject) { 1940 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1941 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1942 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1943 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1944 | }); 1945 | }; 1946 | var __asyncValues = (this && this.__asyncValues) || function (o) { 1947 | if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); 1948 | var m = o[Symbol.asyncIterator], i; 1949 | return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); 1950 | function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } 1951 | function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } 1952 | }; 1953 | var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } 1954 | var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { 1955 | if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); 1956 | var g = generator.apply(thisArg, _arguments || []), i, q = []; 1957 | return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; 1958 | function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } 1959 | function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } 1960 | function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } 1961 | function fulfill(value) { resume("next", value); } 1962 | function reject(value) { resume("throw", value); } 1963 | function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } 1964 | }; 1965 | Object.defineProperty(exports, "__esModule", { value: true }); 1966 | const core = __webpack_require__(470); 1967 | const fs = __webpack_require__(747); 1968 | const globOptionsHelper = __webpack_require__(601); 1969 | const path = __webpack_require__(622); 1970 | const patternHelper = __webpack_require__(597); 1971 | const internal_match_kind_1 = __webpack_require__(327); 1972 | const internal_pattern_1 = __webpack_require__(923); 1973 | const internal_search_state_1 = __webpack_require__(728); 1974 | const IS_WINDOWS = process.platform === 'win32'; 1975 | class DefaultGlobber { 1976 | constructor(options) { 1977 | this.patterns = []; 1978 | this.searchPaths = []; 1979 | this.options = globOptionsHelper.getOptions(options); 1980 | } 1981 | getSearchPaths() { 1982 | // Return a copy 1983 | return this.searchPaths.slice(); 1984 | } 1985 | glob() { 1986 | var e_1, _a; 1987 | return __awaiter(this, void 0, void 0, function* () { 1988 | const result = []; 1989 | try { 1990 | for (var _b = __asyncValues(this.globGenerator()), _c; _c = yield _b.next(), !_c.done;) { 1991 | const itemPath = _c.value; 1992 | result.push(itemPath); 1993 | } 1994 | } 1995 | catch (e_1_1) { e_1 = { error: e_1_1 }; } 1996 | finally { 1997 | try { 1998 | if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b); 1999 | } 2000 | finally { if (e_1) throw e_1.error; } 2001 | } 2002 | return result; 2003 | }); 2004 | } 2005 | globGenerator() { 2006 | return __asyncGenerator(this, arguments, function* globGenerator_1() { 2007 | // Fill in defaults options 2008 | const options = globOptionsHelper.getOptions(this.options); 2009 | // Implicit descendants? 2010 | const patterns = []; 2011 | for (const pattern of this.patterns) { 2012 | patterns.push(pattern); 2013 | if (options.implicitDescendants && 2014 | (pattern.trailingSeparator || 2015 | pattern.segments[pattern.segments.length - 1] !== '**')) { 2016 | patterns.push(new internal_pattern_1.Pattern(pattern.negate, pattern.segments.concat('**'))); 2017 | } 2018 | } 2019 | // Push the search paths 2020 | const stack = []; 2021 | for (const searchPath of patternHelper.getSearchPaths(patterns)) { 2022 | core.debug(`Search path '${searchPath}'`); 2023 | // Exists? 2024 | try { 2025 | // Intentionally using lstat. Detection for broken symlink 2026 | // will be performed later (if following symlinks). 2027 | yield __await(fs.promises.lstat(searchPath)); 2028 | } 2029 | catch (err) { 2030 | if (err.code === 'ENOENT') { 2031 | continue; 2032 | } 2033 | throw err; 2034 | } 2035 | stack.unshift(new internal_search_state_1.SearchState(searchPath, 1)); 2036 | } 2037 | // Search 2038 | const traversalChain = []; // used to detect cycles 2039 | while (stack.length) { 2040 | // Pop 2041 | const item = stack.pop(); 2042 | // Match? 2043 | const match = patternHelper.match(patterns, item.path); 2044 | const partialMatch = !!match || patternHelper.partialMatch(patterns, item.path); 2045 | if (!match && !partialMatch) { 2046 | continue; 2047 | } 2048 | // Stat 2049 | const stats = yield __await(DefaultGlobber.stat(item, options, traversalChain) 2050 | // Broken symlink, or symlink cycle detected, or no longer exists 2051 | ); 2052 | // Broken symlink, or symlink cycle detected, or no longer exists 2053 | if (!stats) { 2054 | continue; 2055 | } 2056 | // Directory 2057 | if (stats.isDirectory()) { 2058 | // Matched 2059 | if (match & internal_match_kind_1.MatchKind.Directory) { 2060 | yield yield __await(item.path); 2061 | } 2062 | // Descend? 2063 | else if (!partialMatch) { 2064 | continue; 2065 | } 2066 | // Push the child items in reverse 2067 | const childLevel = item.level + 1; 2068 | const childItems = (yield __await(fs.promises.readdir(item.path))).map(x => new internal_search_state_1.SearchState(path.join(item.path, x), childLevel)); 2069 | stack.push(...childItems.reverse()); 2070 | } 2071 | // File 2072 | else if (match & internal_match_kind_1.MatchKind.File) { 2073 | yield yield __await(item.path); 2074 | } 2075 | } 2076 | }); 2077 | } 2078 | /** 2079 | * Constructs a DefaultGlobber 2080 | */ 2081 | static create(patterns, options) { 2082 | return __awaiter(this, void 0, void 0, function* () { 2083 | const result = new DefaultGlobber(options); 2084 | if (IS_WINDOWS) { 2085 | patterns = patterns.replace(/\r\n/g, '\n'); 2086 | patterns = patterns.replace(/\r/g, '\n'); 2087 | } 2088 | const lines = patterns.split('\n').map(x => x.trim()); 2089 | for (const line of lines) { 2090 | // Empty or comment 2091 | if (!line || line.startsWith('#')) { 2092 | continue; 2093 | } 2094 | // Pattern 2095 | else { 2096 | result.patterns.push(new internal_pattern_1.Pattern(line)); 2097 | } 2098 | } 2099 | result.searchPaths.push(...patternHelper.getSearchPaths(result.patterns)); 2100 | return result; 2101 | }); 2102 | } 2103 | static stat(item, options, traversalChain) { 2104 | return __awaiter(this, void 0, void 0, function* () { 2105 | // Note: 2106 | // `stat` returns info about the target of a symlink (or symlink chain) 2107 | // `lstat` returns info about a symlink itself 2108 | let stats; 2109 | if (options.followSymbolicLinks) { 2110 | try { 2111 | // Use `stat` (following symlinks) 2112 | stats = yield fs.promises.stat(item.path); 2113 | } 2114 | catch (err) { 2115 | if (err.code === 'ENOENT') { 2116 | if (options.omitBrokenSymbolicLinks) { 2117 | core.debug(`Broken symlink '${item.path}'`); 2118 | return undefined; 2119 | } 2120 | throw new Error(`No information found for the path '${item.path}'. This may indicate a broken symbolic link.`); 2121 | } 2122 | throw err; 2123 | } 2124 | } 2125 | else { 2126 | // Use `lstat` (not following symlinks) 2127 | stats = yield fs.promises.lstat(item.path); 2128 | } 2129 | // Note, isDirectory() returns false for the lstat of a symlink 2130 | if (stats.isDirectory() && options.followSymbolicLinks) { 2131 | // Get the realpath 2132 | const realPath = yield fs.promises.realpath(item.path); 2133 | // Fixup the traversal chain to match the item level 2134 | while (traversalChain.length >= item.level) { 2135 | traversalChain.pop(); 2136 | } 2137 | // Test for a cycle 2138 | if (traversalChain.some((x) => x === realPath)) { 2139 | core.debug(`Symlink cycle detected for path '${item.path}' and realpath '${realPath}'`); 2140 | return undefined; 2141 | } 2142 | // Update the traversal chain 2143 | traversalChain.push(realPath); 2144 | } 2145 | return stats; 2146 | }); 2147 | } 2148 | } 2149 | exports.DefaultGlobber = DefaultGlobber; 2150 | //# sourceMappingURL=internal-globber.js.map 2151 | 2152 | /***/ }), 2153 | 2154 | /***/ 306: 2155 | /***/ (function(module, __unusedexports, __webpack_require__) { 2156 | 2157 | var concatMap = __webpack_require__(896); 2158 | var balanced = __webpack_require__(621); 2159 | 2160 | module.exports = expandTop; 2161 | 2162 | var escSlash = '\0SLASH'+Math.random()+'\0'; 2163 | var escOpen = '\0OPEN'+Math.random()+'\0'; 2164 | var escClose = '\0CLOSE'+Math.random()+'\0'; 2165 | var escComma = '\0COMMA'+Math.random()+'\0'; 2166 | var escPeriod = '\0PERIOD'+Math.random()+'\0'; 2167 | 2168 | function numeric(str) { 2169 | return parseInt(str, 10) == str 2170 | ? parseInt(str, 10) 2171 | : str.charCodeAt(0); 2172 | } 2173 | 2174 | function escapeBraces(str) { 2175 | return str.split('\\\\').join(escSlash) 2176 | .split('\\{').join(escOpen) 2177 | .split('\\}').join(escClose) 2178 | .split('\\,').join(escComma) 2179 | .split('\\.').join(escPeriod); 2180 | } 2181 | 2182 | function unescapeBraces(str) { 2183 | return str.split(escSlash).join('\\') 2184 | .split(escOpen).join('{') 2185 | .split(escClose).join('}') 2186 | .split(escComma).join(',') 2187 | .split(escPeriod).join('.'); 2188 | } 2189 | 2190 | 2191 | // Basically just str.split(","), but handling cases 2192 | // where we have nested braced sections, which should be 2193 | // treated as individual members, like {a,{b,c},d} 2194 | function parseCommaParts(str) { 2195 | if (!str) 2196 | return ['']; 2197 | 2198 | var parts = []; 2199 | var m = balanced('{', '}', str); 2200 | 2201 | if (!m) 2202 | return str.split(','); 2203 | 2204 | var pre = m.pre; 2205 | var body = m.body; 2206 | var post = m.post; 2207 | var p = pre.split(','); 2208 | 2209 | p[p.length-1] += '{' + body + '}'; 2210 | var postParts = parseCommaParts(post); 2211 | if (post.length) { 2212 | p[p.length-1] += postParts.shift(); 2213 | p.push.apply(p, postParts); 2214 | } 2215 | 2216 | parts.push.apply(parts, p); 2217 | 2218 | return parts; 2219 | } 2220 | 2221 | function expandTop(str) { 2222 | if (!str) 2223 | return []; 2224 | 2225 | // I don't know why Bash 4.3 does this, but it does. 2226 | // Anything starting with {} will have the first two bytes preserved 2227 | // but *only* at the top level, so {},a}b will not expand to anything, 2228 | // but a{},b}c will be expanded to [a}c,abc]. 2229 | // One could argue that this is a bug in Bash, but since the goal of 2230 | // this module is to match Bash's rules, we escape a leading {} 2231 | if (str.substr(0, 2) === '{}') { 2232 | str = '\\{\\}' + str.substr(2); 2233 | } 2234 | 2235 | return expand(escapeBraces(str), true).map(unescapeBraces); 2236 | } 2237 | 2238 | function identity(e) { 2239 | return e; 2240 | } 2241 | 2242 | function embrace(str) { 2243 | return '{' + str + '}'; 2244 | } 2245 | function isPadded(el) { 2246 | return /^-?0\d/.test(el); 2247 | } 2248 | 2249 | function lte(i, y) { 2250 | return i <= y; 2251 | } 2252 | function gte(i, y) { 2253 | return i >= y; 2254 | } 2255 | 2256 | function expand(str, isTop) { 2257 | var expansions = []; 2258 | 2259 | var m = balanced('{', '}', str); 2260 | if (!m || /\$$/.test(m.pre)) return [str]; 2261 | 2262 | var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); 2263 | var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); 2264 | var isSequence = isNumericSequence || isAlphaSequence; 2265 | var isOptions = m.body.indexOf(',') >= 0; 2266 | if (!isSequence && !isOptions) { 2267 | // {a},b} 2268 | if (m.post.match(/,.*\}/)) { 2269 | str = m.pre + '{' + m.body + escClose + m.post; 2270 | return expand(str); 2271 | } 2272 | return [str]; 2273 | } 2274 | 2275 | var n; 2276 | if (isSequence) { 2277 | n = m.body.split(/\.\./); 2278 | } else { 2279 | n = parseCommaParts(m.body); 2280 | if (n.length === 1) { 2281 | // x{{a,b}}y ==> x{a}y x{b}y 2282 | n = expand(n[0], false).map(embrace); 2283 | if (n.length === 1) { 2284 | var post = m.post.length 2285 | ? expand(m.post, false) 2286 | : ['']; 2287 | return post.map(function(p) { 2288 | return m.pre + n[0] + p; 2289 | }); 2290 | } 2291 | } 2292 | } 2293 | 2294 | // at this point, n is the parts, and we know it's not a comma set 2295 | // with a single entry. 2296 | 2297 | // no need to expand pre, since it is guaranteed to be free of brace-sets 2298 | var pre = m.pre; 2299 | var post = m.post.length 2300 | ? expand(m.post, false) 2301 | : ['']; 2302 | 2303 | var N; 2304 | 2305 | if (isSequence) { 2306 | var x = numeric(n[0]); 2307 | var y = numeric(n[1]); 2308 | var width = Math.max(n[0].length, n[1].length) 2309 | var incr = n.length == 3 2310 | ? Math.abs(numeric(n[2])) 2311 | : 1; 2312 | var test = lte; 2313 | var reverse = y < x; 2314 | if (reverse) { 2315 | incr *= -1; 2316 | test = gte; 2317 | } 2318 | var pad = n.some(isPadded); 2319 | 2320 | N = []; 2321 | 2322 | for (var i = x; test(i, y); i += incr) { 2323 | var c; 2324 | if (isAlphaSequence) { 2325 | c = String.fromCharCode(i); 2326 | if (c === '\\') 2327 | c = ''; 2328 | } else { 2329 | c = String(i); 2330 | if (pad) { 2331 | var need = width - c.length; 2332 | if (need > 0) { 2333 | var z = new Array(need + 1).join('0'); 2334 | if (i < 0) 2335 | c = '-' + z + c.slice(1); 2336 | else 2337 | c = z + c; 2338 | } 2339 | } 2340 | } 2341 | N.push(c); 2342 | } 2343 | } else { 2344 | N = concatMap(n, function(el) { return expand(el, false) }); 2345 | } 2346 | 2347 | for (var j = 0; j < N.length; j++) { 2348 | for (var k = 0; k < post.length; k++) { 2349 | var expansion = pre + N[j] + post[k]; 2350 | if (!isTop || isSequence || expansion) 2351 | expansions.push(expansion); 2352 | } 2353 | } 2354 | 2355 | return expansions; 2356 | } 2357 | 2358 | 2359 | 2360 | /***/ }), 2361 | 2362 | /***/ 327: 2363 | /***/ (function(__unusedmodule, exports) { 2364 | 2365 | "use strict"; 2366 | 2367 | Object.defineProperty(exports, "__esModule", { value: true }); 2368 | /** 2369 | * Indicates whether a pattern matches a path 2370 | */ 2371 | var MatchKind; 2372 | (function (MatchKind) { 2373 | /** Not matched */ 2374 | MatchKind[MatchKind["None"] = 0] = "None"; 2375 | /** Matched if the path is a directory */ 2376 | MatchKind[MatchKind["Directory"] = 1] = "Directory"; 2377 | /** Matched if the path is a regular file */ 2378 | MatchKind[MatchKind["File"] = 2] = "File"; 2379 | /** Matched */ 2380 | MatchKind[MatchKind["All"] = 3] = "All"; 2381 | })(MatchKind = exports.MatchKind || (exports.MatchKind = {})); 2382 | //# sourceMappingURL=internal-match-kind.js.map 2383 | 2384 | /***/ }), 2385 | 2386 | /***/ 357: 2387 | /***/ (function(module) { 2388 | 2389 | module.exports = require("assert"); 2390 | 2391 | /***/ }), 2392 | 2393 | /***/ 383: 2394 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2395 | 2396 | "use strict"; 2397 | 2398 | Object.defineProperty(exports, "__esModule", { value: true }); 2399 | const assert = __webpack_require__(357); 2400 | const path = __webpack_require__(622); 2401 | const pathHelper = __webpack_require__(972); 2402 | const IS_WINDOWS = process.platform === 'win32'; 2403 | /** 2404 | * Helper class for parsing paths into segments 2405 | */ 2406 | class Path { 2407 | /** 2408 | * Constructs a Path 2409 | * @param itemPath Path or array of segments 2410 | */ 2411 | constructor(itemPath) { 2412 | this.segments = []; 2413 | // String 2414 | if (typeof itemPath === 'string') { 2415 | assert(itemPath, `Parameter 'itemPath' must not be empty`); 2416 | // Normalize slashes and trim unnecessary trailing slash 2417 | itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); 2418 | // Not rooted 2419 | if (!pathHelper.hasRoot(itemPath)) { 2420 | this.segments = itemPath.split(path.sep); 2421 | } 2422 | // Rooted 2423 | else { 2424 | // Add all segments, while not at the root 2425 | let remaining = itemPath; 2426 | let dir = pathHelper.dirname(remaining); 2427 | while (dir !== remaining) { 2428 | // Add the segment 2429 | const basename = path.basename(remaining); 2430 | this.segments.unshift(basename); 2431 | // Truncate the last segment 2432 | remaining = dir; 2433 | dir = pathHelper.dirname(remaining); 2434 | } 2435 | // Remainder is the root 2436 | this.segments.unshift(remaining); 2437 | } 2438 | } 2439 | // Array 2440 | else { 2441 | // Must not be empty 2442 | assert(itemPath.length > 0, `Parameter 'itemPath' must not be an empty array`); 2443 | // Each segment 2444 | for (let i = 0; i < itemPath.length; i++) { 2445 | let segment = itemPath[i]; 2446 | // Must not be empty 2447 | assert(segment, `Parameter 'itemPath' must not contain any empty segments`); 2448 | // Normalize slashes 2449 | segment = pathHelper.normalizeSeparators(itemPath[i]); 2450 | // Root segment 2451 | if (i === 0 && pathHelper.hasRoot(segment)) { 2452 | segment = pathHelper.safeTrimTrailingSeparator(segment); 2453 | assert(segment === pathHelper.dirname(segment), `Parameter 'itemPath' root segment contains information for multiple segments`); 2454 | this.segments.push(segment); 2455 | } 2456 | // All other segments 2457 | else { 2458 | // Must not contain slash 2459 | assert(!segment.includes(path.sep), `Parameter 'itemPath' contains unexpected path separators`); 2460 | this.segments.push(segment); 2461 | } 2462 | } 2463 | } 2464 | } 2465 | /** 2466 | * Converts the path to it's string representation 2467 | */ 2468 | toString() { 2469 | // First segment 2470 | let result = this.segments[0]; 2471 | // All others 2472 | let skipSlash = result.endsWith(path.sep) || (IS_WINDOWS && /^[A-Z]:$/i.test(result)); 2473 | for (let i = 1; i < this.segments.length; i++) { 2474 | if (skipSlash) { 2475 | skipSlash = false; 2476 | } 2477 | else { 2478 | result += path.sep; 2479 | } 2480 | result += this.segments[i]; 2481 | } 2482 | return result; 2483 | } 2484 | } 2485 | exports.Path = Path; 2486 | //# sourceMappingURL=internal-path.js.map 2487 | 2488 | /***/ }), 2489 | 2490 | /***/ 431: 2491 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2492 | 2493 | "use strict"; 2494 | 2495 | var __importStar = (this && this.__importStar) || function (mod) { 2496 | if (mod && mod.__esModule) return mod; 2497 | var result = {}; 2498 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 2499 | result["default"] = mod; 2500 | return result; 2501 | }; 2502 | Object.defineProperty(exports, "__esModule", { value: true }); 2503 | const os = __importStar(__webpack_require__(87)); 2504 | /** 2505 | * Commands 2506 | * 2507 | * Command Format: 2508 | * ::name key=value,key=value::message 2509 | * 2510 | * Examples: 2511 | * ::warning::This is the message 2512 | * ::set-env name=MY_VAR::some value 2513 | */ 2514 | function issueCommand(command, properties, message) { 2515 | const cmd = new Command(command, properties, message); 2516 | process.stdout.write(cmd.toString() + os.EOL); 2517 | } 2518 | exports.issueCommand = issueCommand; 2519 | function issue(name, message = '') { 2520 | issueCommand(name, {}, message); 2521 | } 2522 | exports.issue = issue; 2523 | const CMD_STRING = '::'; 2524 | class Command { 2525 | constructor(command, properties, message) { 2526 | if (!command) { 2527 | command = 'missing.command'; 2528 | } 2529 | this.command = command; 2530 | this.properties = properties; 2531 | this.message = message; 2532 | } 2533 | toString() { 2534 | let cmdStr = CMD_STRING + this.command; 2535 | if (this.properties && Object.keys(this.properties).length > 0) { 2536 | cmdStr += ' '; 2537 | let first = true; 2538 | for (const key in this.properties) { 2539 | if (this.properties.hasOwnProperty(key)) { 2540 | const val = this.properties[key]; 2541 | if (val) { 2542 | if (first) { 2543 | first = false; 2544 | } 2545 | else { 2546 | cmdStr += ','; 2547 | } 2548 | cmdStr += `${key}=${escapeProperty(val)}`; 2549 | } 2550 | } 2551 | } 2552 | } 2553 | cmdStr += `${CMD_STRING}${escapeData(this.message)}`; 2554 | return cmdStr; 2555 | } 2556 | } 2557 | /** 2558 | * Sanitizes an input into a string so it can be passed into issueCommand safely 2559 | * @param input input to sanitize into a string 2560 | */ 2561 | function toCommandValue(input) { 2562 | if (input === null || input === undefined) { 2563 | return ''; 2564 | } 2565 | else if (typeof input === 'string' || input instanceof String) { 2566 | return input; 2567 | } 2568 | return JSON.stringify(input); 2569 | } 2570 | exports.toCommandValue = toCommandValue; 2571 | function escapeData(s) { 2572 | return toCommandValue(s) 2573 | .replace(/%/g, '%25') 2574 | .replace(/\r/g, '%0D') 2575 | .replace(/\n/g, '%0A'); 2576 | } 2577 | function escapeProperty(s) { 2578 | return toCommandValue(s) 2579 | .replace(/%/g, '%25') 2580 | .replace(/\r/g, '%0D') 2581 | .replace(/\n/g, '%0A') 2582 | .replace(/:/g, '%3A') 2583 | .replace(/,/g, '%2C'); 2584 | } 2585 | //# sourceMappingURL=command.js.map 2586 | 2587 | /***/ }), 2588 | 2589 | /***/ 470: 2590 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2591 | 2592 | "use strict"; 2593 | 2594 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2595 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 2596 | return new (P || (P = Promise))(function (resolve, reject) { 2597 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 2598 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 2599 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 2600 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 2601 | }); 2602 | }; 2603 | var __importStar = (this && this.__importStar) || function (mod) { 2604 | if (mod && mod.__esModule) return mod; 2605 | var result = {}; 2606 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 2607 | result["default"] = mod; 2608 | return result; 2609 | }; 2610 | Object.defineProperty(exports, "__esModule", { value: true }); 2611 | const command_1 = __webpack_require__(431); 2612 | const os = __importStar(__webpack_require__(87)); 2613 | const path = __importStar(__webpack_require__(622)); 2614 | /** 2615 | * The code to exit an action 2616 | */ 2617 | var ExitCode; 2618 | (function (ExitCode) { 2619 | /** 2620 | * A code indicating that the action was successful 2621 | */ 2622 | ExitCode[ExitCode["Success"] = 0] = "Success"; 2623 | /** 2624 | * A code indicating that the action was a failure 2625 | */ 2626 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 2627 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 2628 | //----------------------------------------------------------------------- 2629 | // Variables 2630 | //----------------------------------------------------------------------- 2631 | /** 2632 | * Sets env variable for this action and future actions in the job 2633 | * @param name the name of the variable to set 2634 | * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify 2635 | */ 2636 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2637 | function exportVariable(name, val) { 2638 | const convertedVal = command_1.toCommandValue(val); 2639 | process.env[name] = convertedVal; 2640 | command_1.issueCommand('set-env', { name }, convertedVal); 2641 | } 2642 | exports.exportVariable = exportVariable; 2643 | /** 2644 | * Registers a secret which will get masked from logs 2645 | * @param secret value of the secret 2646 | */ 2647 | function setSecret(secret) { 2648 | command_1.issueCommand('add-mask', {}, secret); 2649 | } 2650 | exports.setSecret = setSecret; 2651 | /** 2652 | * Prepends inputPath to the PATH (for this action and future actions) 2653 | * @param inputPath 2654 | */ 2655 | function addPath(inputPath) { 2656 | command_1.issueCommand('add-path', {}, inputPath); 2657 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 2658 | } 2659 | exports.addPath = addPath; 2660 | /** 2661 | * Gets the value of an input. The value is also trimmed. 2662 | * 2663 | * @param name name of the input to get 2664 | * @param options optional. See InputOptions. 2665 | * @returns string 2666 | */ 2667 | function getInput(name, options) { 2668 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 2669 | if (options && options.required && !val) { 2670 | throw new Error(`Input required and not supplied: ${name}`); 2671 | } 2672 | return val.trim(); 2673 | } 2674 | exports.getInput = getInput; 2675 | /** 2676 | * Sets the value of an output. 2677 | * 2678 | * @param name name of the output to set 2679 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 2680 | */ 2681 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2682 | function setOutput(name, value) { 2683 | command_1.issueCommand('set-output', { name }, value); 2684 | } 2685 | exports.setOutput = setOutput; 2686 | /** 2687 | * Enables or disables the echoing of commands into stdout for the rest of the step. 2688 | * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 2689 | * 2690 | */ 2691 | function setCommandEcho(enabled) { 2692 | command_1.issue('echo', enabled ? 'on' : 'off'); 2693 | } 2694 | exports.setCommandEcho = setCommandEcho; 2695 | //----------------------------------------------------------------------- 2696 | // Results 2697 | //----------------------------------------------------------------------- 2698 | /** 2699 | * Sets the action status to failed. 2700 | * When the action exits it will be with an exit code of 1 2701 | * @param message add error issue message 2702 | */ 2703 | function setFailed(message) { 2704 | process.exitCode = ExitCode.Failure; 2705 | error(message); 2706 | } 2707 | exports.setFailed = setFailed; 2708 | //----------------------------------------------------------------------- 2709 | // Logging Commands 2710 | //----------------------------------------------------------------------- 2711 | /** 2712 | * Gets whether Actions Step Debug is on or not 2713 | */ 2714 | function isDebug() { 2715 | return process.env['RUNNER_DEBUG'] === '1'; 2716 | } 2717 | exports.isDebug = isDebug; 2718 | /** 2719 | * Writes debug message to user log 2720 | * @param message debug message 2721 | */ 2722 | function debug(message) { 2723 | command_1.issueCommand('debug', {}, message); 2724 | } 2725 | exports.debug = debug; 2726 | /** 2727 | * Adds an error issue 2728 | * @param message error issue message. Errors will be converted to string via toString() 2729 | */ 2730 | function error(message) { 2731 | command_1.issue('error', message instanceof Error ? message.toString() : message); 2732 | } 2733 | exports.error = error; 2734 | /** 2735 | * Adds an warning issue 2736 | * @param message warning issue message. Errors will be converted to string via toString() 2737 | */ 2738 | function warning(message) { 2739 | command_1.issue('warning', message instanceof Error ? message.toString() : message); 2740 | } 2741 | exports.warning = warning; 2742 | /** 2743 | * Writes info to log with console.log. 2744 | * @param message info message 2745 | */ 2746 | function info(message) { 2747 | process.stdout.write(message + os.EOL); 2748 | } 2749 | exports.info = info; 2750 | /** 2751 | * Begin an output group. 2752 | * 2753 | * Output until the next `groupEnd` will be foldable in this group 2754 | * 2755 | * @param name The name of the output group 2756 | */ 2757 | function startGroup(name) { 2758 | command_1.issue('group', name); 2759 | } 2760 | exports.startGroup = startGroup; 2761 | /** 2762 | * End an output group. 2763 | */ 2764 | function endGroup() { 2765 | command_1.issue('endgroup'); 2766 | } 2767 | exports.endGroup = endGroup; 2768 | /** 2769 | * Wrap an asynchronous function call in a group. 2770 | * 2771 | * Returns the same type as the function itself. 2772 | * 2773 | * @param name The name of the group 2774 | * @param fn The function to wrap in the group 2775 | */ 2776 | function group(name, fn) { 2777 | return __awaiter(this, void 0, void 0, function* () { 2778 | startGroup(name); 2779 | let result; 2780 | try { 2781 | result = yield fn(); 2782 | } 2783 | finally { 2784 | endGroup(); 2785 | } 2786 | return result; 2787 | }); 2788 | } 2789 | exports.group = group; 2790 | //----------------------------------------------------------------------- 2791 | // Wrapper action state 2792 | //----------------------------------------------------------------------- 2793 | /** 2794 | * Saves state for current action, the state can only be retrieved by this action's post job execution. 2795 | * 2796 | * @param name name of the state to store 2797 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 2798 | */ 2799 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2800 | function saveState(name, value) { 2801 | command_1.issueCommand('save-state', { name }, value); 2802 | } 2803 | exports.saveState = saveState; 2804 | /** 2805 | * Gets the value of an state set by this action's main execution. 2806 | * 2807 | * @param name name of the state to get 2808 | * @returns string 2809 | */ 2810 | function getState(name) { 2811 | return process.env[`STATE_${name}`] || ''; 2812 | } 2813 | exports.getState = getState; 2814 | //# sourceMappingURL=core.js.map 2815 | 2816 | /***/ }), 2817 | 2818 | /***/ 597: 2819 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2820 | 2821 | "use strict"; 2822 | 2823 | Object.defineProperty(exports, "__esModule", { value: true }); 2824 | const pathHelper = __webpack_require__(972); 2825 | const internal_match_kind_1 = __webpack_require__(327); 2826 | const IS_WINDOWS = process.platform === 'win32'; 2827 | /** 2828 | * Given an array of patterns, returns an array of paths to search. 2829 | * Duplicates and paths under other included paths are filtered out. 2830 | */ 2831 | function getSearchPaths(patterns) { 2832 | // Ignore negate patterns 2833 | patterns = patterns.filter(x => !x.negate); 2834 | // Create a map of all search paths 2835 | const searchPathMap = {}; 2836 | for (const pattern of patterns) { 2837 | const key = IS_WINDOWS 2838 | ? pattern.searchPath.toUpperCase() 2839 | : pattern.searchPath; 2840 | searchPathMap[key] = 'candidate'; 2841 | } 2842 | const result = []; 2843 | for (const pattern of patterns) { 2844 | // Check if already included 2845 | const key = IS_WINDOWS 2846 | ? pattern.searchPath.toUpperCase() 2847 | : pattern.searchPath; 2848 | if (searchPathMap[key] === 'included') { 2849 | continue; 2850 | } 2851 | // Check for an ancestor search path 2852 | let foundAncestor = false; 2853 | let tempKey = key; 2854 | let parent = pathHelper.dirname(tempKey); 2855 | while (parent !== tempKey) { 2856 | if (searchPathMap[parent]) { 2857 | foundAncestor = true; 2858 | break; 2859 | } 2860 | tempKey = parent; 2861 | parent = pathHelper.dirname(tempKey); 2862 | } 2863 | // Include the search pattern in the result 2864 | if (!foundAncestor) { 2865 | result.push(pattern.searchPath); 2866 | searchPathMap[key] = 'included'; 2867 | } 2868 | } 2869 | return result; 2870 | } 2871 | exports.getSearchPaths = getSearchPaths; 2872 | /** 2873 | * Matches the patterns against the path 2874 | */ 2875 | function match(patterns, itemPath) { 2876 | let result = internal_match_kind_1.MatchKind.None; 2877 | for (const pattern of patterns) { 2878 | if (pattern.negate) { 2879 | result &= ~pattern.match(itemPath); 2880 | } 2881 | else { 2882 | result |= pattern.match(itemPath); 2883 | } 2884 | } 2885 | return result; 2886 | } 2887 | exports.match = match; 2888 | /** 2889 | * Checks whether to descend further into the directory 2890 | */ 2891 | function partialMatch(patterns, itemPath) { 2892 | return patterns.some(x => !x.negate && x.partialMatch(itemPath)); 2893 | } 2894 | exports.partialMatch = partialMatch; 2895 | //# sourceMappingURL=internal-pattern-helper.js.map 2896 | 2897 | /***/ }), 2898 | 2899 | /***/ 601: 2900 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2901 | 2902 | "use strict"; 2903 | 2904 | Object.defineProperty(exports, "__esModule", { value: true }); 2905 | const core = __webpack_require__(470); 2906 | /** 2907 | * Returns a copy with defaults filled in. 2908 | */ 2909 | function getOptions(copy) { 2910 | const result = { 2911 | followSymbolicLinks: true, 2912 | implicitDescendants: true, 2913 | omitBrokenSymbolicLinks: true 2914 | }; 2915 | if (copy) { 2916 | if (typeof copy.followSymbolicLinks === 'boolean') { 2917 | result.followSymbolicLinks = copy.followSymbolicLinks; 2918 | core.debug(`followSymbolicLinks '${result.followSymbolicLinks}'`); 2919 | } 2920 | if (typeof copy.implicitDescendants === 'boolean') { 2921 | result.implicitDescendants = copy.implicitDescendants; 2922 | core.debug(`implicitDescendants '${result.implicitDescendants}'`); 2923 | } 2924 | if (typeof copy.omitBrokenSymbolicLinks === 'boolean') { 2925 | result.omitBrokenSymbolicLinks = copy.omitBrokenSymbolicLinks; 2926 | core.debug(`omitBrokenSymbolicLinks '${result.omitBrokenSymbolicLinks}'`); 2927 | } 2928 | } 2929 | return result; 2930 | } 2931 | exports.getOptions = getOptions; 2932 | //# sourceMappingURL=internal-glob-options-helper.js.map 2933 | 2934 | /***/ }), 2935 | 2936 | /***/ 614: 2937 | /***/ (function(module) { 2938 | 2939 | module.exports = require("events"); 2940 | 2941 | /***/ }), 2942 | 2943 | /***/ 621: 2944 | /***/ (function(module) { 2945 | 2946 | "use strict"; 2947 | 2948 | module.exports = balanced; 2949 | function balanced(a, b, str) { 2950 | if (a instanceof RegExp) a = maybeMatch(a, str); 2951 | if (b instanceof RegExp) b = maybeMatch(b, str); 2952 | 2953 | var r = range(a, b, str); 2954 | 2955 | return r && { 2956 | start: r[0], 2957 | end: r[1], 2958 | pre: str.slice(0, r[0]), 2959 | body: str.slice(r[0] + a.length, r[1]), 2960 | post: str.slice(r[1] + b.length) 2961 | }; 2962 | } 2963 | 2964 | function maybeMatch(reg, str) { 2965 | var m = str.match(reg); 2966 | return m ? m[0] : null; 2967 | } 2968 | 2969 | balanced.range = range; 2970 | function range(a, b, str) { 2971 | var begs, beg, left, right, result; 2972 | var ai = str.indexOf(a); 2973 | var bi = str.indexOf(b, ai + 1); 2974 | var i = ai; 2975 | 2976 | if (ai >= 0 && bi > 0) { 2977 | begs = []; 2978 | left = str.length; 2979 | 2980 | while (i >= 0 && !result) { 2981 | if (i == ai) { 2982 | begs.push(i); 2983 | ai = str.indexOf(a, i + 1); 2984 | } else if (begs.length == 1) { 2985 | result = [ begs.pop(), bi ]; 2986 | } else { 2987 | beg = begs.pop(); 2988 | if (beg < left) { 2989 | left = beg; 2990 | right = bi; 2991 | } 2992 | 2993 | bi = str.indexOf(b, i + 1); 2994 | } 2995 | 2996 | i = ai < bi && ai >= 0 ? ai : bi; 2997 | } 2998 | 2999 | if (begs.length) { 3000 | result = [ left, right ]; 3001 | } 3002 | } 3003 | 3004 | return result; 3005 | } 3006 | 3007 | 3008 | /***/ }), 3009 | 3010 | /***/ 622: 3011 | /***/ (function(module) { 3012 | 3013 | module.exports = require("path"); 3014 | 3015 | /***/ }), 3016 | 3017 | /***/ 669: 3018 | /***/ (function(module) { 3019 | 3020 | module.exports = require("util"); 3021 | 3022 | /***/ }), 3023 | 3024 | /***/ 672: 3025 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 3026 | 3027 | "use strict"; 3028 | 3029 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3030 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3031 | return new (P || (P = Promise))(function (resolve, reject) { 3032 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 3033 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 3034 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 3035 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 3036 | }); 3037 | }; 3038 | var _a; 3039 | Object.defineProperty(exports, "__esModule", { value: true }); 3040 | const assert_1 = __webpack_require__(357); 3041 | const fs = __webpack_require__(747); 3042 | const path = __webpack_require__(622); 3043 | _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; 3044 | exports.IS_WINDOWS = process.platform === 'win32'; 3045 | function exists(fsPath) { 3046 | return __awaiter(this, void 0, void 0, function* () { 3047 | try { 3048 | yield exports.stat(fsPath); 3049 | } 3050 | catch (err) { 3051 | if (err.code === 'ENOENT') { 3052 | return false; 3053 | } 3054 | throw err; 3055 | } 3056 | return true; 3057 | }); 3058 | } 3059 | exports.exists = exists; 3060 | function isDirectory(fsPath, useStat = false) { 3061 | return __awaiter(this, void 0, void 0, function* () { 3062 | const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath); 3063 | return stats.isDirectory(); 3064 | }); 3065 | } 3066 | exports.isDirectory = isDirectory; 3067 | /** 3068 | * On OSX/Linux, true if path starts with '/'. On Windows, true for paths like: 3069 | * \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases). 3070 | */ 3071 | function isRooted(p) { 3072 | p = normalizeSeparators(p); 3073 | if (!p) { 3074 | throw new Error('isRooted() parameter "p" cannot be empty'); 3075 | } 3076 | if (exports.IS_WINDOWS) { 3077 | return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello 3078 | ); // e.g. C: or C:\hello 3079 | } 3080 | return p.startsWith('/'); 3081 | } 3082 | exports.isRooted = isRooted; 3083 | /** 3084 | * Recursively create a directory at `fsPath`. 3085 | * 3086 | * This implementation is optimistic, meaning it attempts to create the full 3087 | * path first, and backs up the path stack from there. 3088 | * 3089 | * @param fsPath The path to create 3090 | * @param maxDepth The maximum recursion depth 3091 | * @param depth The current recursion depth 3092 | */ 3093 | function mkdirP(fsPath, maxDepth = 1000, depth = 1) { 3094 | return __awaiter(this, void 0, void 0, function* () { 3095 | assert_1.ok(fsPath, 'a path argument must be provided'); 3096 | fsPath = path.resolve(fsPath); 3097 | if (depth >= maxDepth) 3098 | return exports.mkdir(fsPath); 3099 | try { 3100 | yield exports.mkdir(fsPath); 3101 | return; 3102 | } 3103 | catch (err) { 3104 | switch (err.code) { 3105 | case 'ENOENT': { 3106 | yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1); 3107 | yield exports.mkdir(fsPath); 3108 | return; 3109 | } 3110 | default: { 3111 | let stats; 3112 | try { 3113 | stats = yield exports.stat(fsPath); 3114 | } 3115 | catch (err2) { 3116 | throw err; 3117 | } 3118 | if (!stats.isDirectory()) 3119 | throw err; 3120 | } 3121 | } 3122 | } 3123 | }); 3124 | } 3125 | exports.mkdirP = mkdirP; 3126 | /** 3127 | * Best effort attempt to determine whether a file exists and is executable. 3128 | * @param filePath file path to check 3129 | * @param extensions additional file extensions to try 3130 | * @return if file exists and is executable, returns the file path. otherwise empty string. 3131 | */ 3132 | function tryGetExecutablePath(filePath, extensions) { 3133 | return __awaiter(this, void 0, void 0, function* () { 3134 | let stats = undefined; 3135 | try { 3136 | // test file exists 3137 | stats = yield exports.stat(filePath); 3138 | } 3139 | catch (err) { 3140 | if (err.code !== 'ENOENT') { 3141 | // eslint-disable-next-line no-console 3142 | console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); 3143 | } 3144 | } 3145 | if (stats && stats.isFile()) { 3146 | if (exports.IS_WINDOWS) { 3147 | // on Windows, test for valid extension 3148 | const upperExt = path.extname(filePath).toUpperCase(); 3149 | if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) { 3150 | return filePath; 3151 | } 3152 | } 3153 | else { 3154 | if (isUnixExecutable(stats)) { 3155 | return filePath; 3156 | } 3157 | } 3158 | } 3159 | // try each extension 3160 | const originalFilePath = filePath; 3161 | for (const extension of extensions) { 3162 | filePath = originalFilePath + extension; 3163 | stats = undefined; 3164 | try { 3165 | stats = yield exports.stat(filePath); 3166 | } 3167 | catch (err) { 3168 | if (err.code !== 'ENOENT') { 3169 | // eslint-disable-next-line no-console 3170 | console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); 3171 | } 3172 | } 3173 | if (stats && stats.isFile()) { 3174 | if (exports.IS_WINDOWS) { 3175 | // preserve the case of the actual file (since an extension was appended) 3176 | try { 3177 | const directory = path.dirname(filePath); 3178 | const upperName = path.basename(filePath).toUpperCase(); 3179 | for (const actualName of yield exports.readdir(directory)) { 3180 | if (upperName === actualName.toUpperCase()) { 3181 | filePath = path.join(directory, actualName); 3182 | break; 3183 | } 3184 | } 3185 | } 3186 | catch (err) { 3187 | // eslint-disable-next-line no-console 3188 | console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`); 3189 | } 3190 | return filePath; 3191 | } 3192 | else { 3193 | if (isUnixExecutable(stats)) { 3194 | return filePath; 3195 | } 3196 | } 3197 | } 3198 | } 3199 | return ''; 3200 | }); 3201 | } 3202 | exports.tryGetExecutablePath = tryGetExecutablePath; 3203 | function normalizeSeparators(p) { 3204 | p = p || ''; 3205 | if (exports.IS_WINDOWS) { 3206 | // convert slashes on Windows 3207 | p = p.replace(/\//g, '\\'); 3208 | // remove redundant slashes 3209 | return p.replace(/\\\\+/g, '\\'); 3210 | } 3211 | // remove redundant slashes 3212 | return p.replace(/\/\/+/g, '/'); 3213 | } 3214 | // on Mac/Linux, test the execute bit 3215 | // R W X R W X R W X 3216 | // 256 128 64 32 16 8 4 2 1 3217 | function isUnixExecutable(stats) { 3218 | return ((stats.mode & 1) > 0 || 3219 | ((stats.mode & 8) > 0 && stats.gid === process.getgid()) || 3220 | ((stats.mode & 64) > 0 && stats.uid === process.getuid())); 3221 | } 3222 | //# sourceMappingURL=io-util.js.map 3223 | 3224 | /***/ }), 3225 | 3226 | /***/ 676: 3227 | /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { 3228 | 3229 | const core = __webpack_require__(470); 3230 | const glob = __webpack_require__(281); 3231 | const exec = __webpack_require__(986); 3232 | 3233 | async function run() { 3234 | const buildPath = core.getInput("path"); 3235 | const fbSubCmd = core.getInput("subcmd"); 3236 | const fbArgs = core.getInput("args"); 3237 | const fbVersion = core.getInput("version"); 3238 | 3239 | // const options = {}; 3240 | // options.listeners = { 3241 | // stdout: (data) => { 3242 | // myOutput += data.toString(); 3243 | // }, 3244 | // stderr: (data) => { 3245 | // myError += data.toString(); 3246 | // }, 3247 | // }; 3248 | 3249 | // ================== 3250 | // Install fontbakery 3251 | // ================== 3252 | try { 3253 | await exec.exec("python -m pip install fontbakery==0.7.31"); 3254 | // Show the installed version 3255 | console.log(""); 3256 | console.log("Dependency versions after fontbakery installation:"); 3257 | await exec.exec("python -m pip list"); 3258 | await exec.exec("python -m pip show fontbakery"); 3259 | } catch (error) { 3260 | core.setFailed( 3261 | `font-bakery Action failed during fontbakery installation attempt with error: ${error.message}` 3262 | ); 3263 | } 3264 | // ========================== 3265 | // Display files to be tested 3266 | // ========================== 3267 | try { 3268 | const globber = await glob.create(`${buildPath}`); 3269 | console.log(""); 3270 | console.log("Beginning fontbakery tests on the following files:"); 3271 | for await (const file of globber.globGenerator()) { 3272 | console.log(file); 3273 | } 3274 | console.log(""); 3275 | } catch (error) { 3276 | core.setFailed( 3277 | `font-bakery Action failed during fontbakery file path display attempt with error: ${error.message}` 3278 | ); 3279 | } 3280 | // ======================== 3281 | // Execute fontbakery tests 3282 | // ======================== 3283 | try { 3284 | if (fbArgs !== "none") { 3285 | await exec.exec(`fontbakery ${fbSubCmd} ${fbArgs} ${buildPath}`); 3286 | } else { 3287 | await exec.exec(`fontbakery ${fbSubCmd} ${buildPath}`); 3288 | } 3289 | } catch (error) { 3290 | core.setFailed( 3291 | `font-bakery Action failed during fontbakery execution attempt with error: ${error.message}` 3292 | ); 3293 | } 3294 | } 3295 | 3296 | run(); 3297 | 3298 | 3299 | /***/ }), 3300 | 3301 | /***/ 728: 3302 | /***/ (function(__unusedmodule, exports) { 3303 | 3304 | "use strict"; 3305 | 3306 | Object.defineProperty(exports, "__esModule", { value: true }); 3307 | class SearchState { 3308 | constructor(path, level) { 3309 | this.path = path; 3310 | this.level = level; 3311 | } 3312 | } 3313 | exports.SearchState = SearchState; 3314 | //# sourceMappingURL=internal-search-state.js.map 3315 | 3316 | /***/ }), 3317 | 3318 | /***/ 747: 3319 | /***/ (function(module) { 3320 | 3321 | module.exports = require("fs"); 3322 | 3323 | /***/ }), 3324 | 3325 | /***/ 896: 3326 | /***/ (function(module) { 3327 | 3328 | module.exports = function (xs, fn) { 3329 | var res = []; 3330 | for (var i = 0; i < xs.length; i++) { 3331 | var x = fn(xs[i], i); 3332 | if (isArray(x)) res.push.apply(res, x); 3333 | else res.push(x); 3334 | } 3335 | return res; 3336 | }; 3337 | 3338 | var isArray = Array.isArray || function (xs) { 3339 | return Object.prototype.toString.call(xs) === '[object Array]'; 3340 | }; 3341 | 3342 | 3343 | /***/ }), 3344 | 3345 | /***/ 923: 3346 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 3347 | 3348 | "use strict"; 3349 | 3350 | Object.defineProperty(exports, "__esModule", { value: true }); 3351 | const assert = __webpack_require__(357); 3352 | const os = __webpack_require__(87); 3353 | const path = __webpack_require__(622); 3354 | const pathHelper = __webpack_require__(972); 3355 | const minimatch_1 = __webpack_require__(93); 3356 | const internal_match_kind_1 = __webpack_require__(327); 3357 | const internal_path_1 = __webpack_require__(383); 3358 | const IS_WINDOWS = process.platform === 'win32'; 3359 | class Pattern { 3360 | constructor(patternOrNegate, segments) { 3361 | /** 3362 | * Indicates whether matches should be excluded from the result set 3363 | */ 3364 | this.negate = false; 3365 | // Pattern overload 3366 | let pattern; 3367 | if (typeof patternOrNegate === 'string') { 3368 | pattern = patternOrNegate.trim(); 3369 | } 3370 | // Segments overload 3371 | else { 3372 | // Convert to pattern 3373 | segments = segments || []; 3374 | assert(segments.length, `Parameter 'segments' must not empty`); 3375 | const root = Pattern.getLiteral(segments[0]); 3376 | assert(root && pathHelper.hasAbsoluteRoot(root), `Parameter 'segments' first element must be a root path`); 3377 | pattern = new internal_path_1.Path(segments).toString().trim(); 3378 | if (patternOrNegate) { 3379 | pattern = `!${pattern}`; 3380 | } 3381 | } 3382 | // Negate 3383 | while (pattern.startsWith('!')) { 3384 | this.negate = !this.negate; 3385 | pattern = pattern.substr(1).trim(); 3386 | } 3387 | // Normalize slashes and ensures absolute root 3388 | pattern = Pattern.fixupPattern(pattern); 3389 | // Segments 3390 | this.segments = new internal_path_1.Path(pattern).segments; 3391 | // Trailing slash indicates the pattern should only match directories, not regular files 3392 | this.trailingSeparator = pathHelper 3393 | .normalizeSeparators(pattern) 3394 | .endsWith(path.sep); 3395 | pattern = pathHelper.safeTrimTrailingSeparator(pattern); 3396 | // Search path (literal path prior to the first glob segment) 3397 | let foundGlob = false; 3398 | const searchSegments = this.segments 3399 | .map(x => Pattern.getLiteral(x)) 3400 | .filter(x => !foundGlob && !(foundGlob = x === '')); 3401 | this.searchPath = new internal_path_1.Path(searchSegments).toString(); 3402 | // Root RegExp (required when determining partial match) 3403 | this.rootRegExp = new RegExp(Pattern.regExpEscape(searchSegments[0]), IS_WINDOWS ? 'i' : ''); 3404 | // Create minimatch 3405 | const minimatchOptions = { 3406 | dot: true, 3407 | nobrace: true, 3408 | nocase: IS_WINDOWS, 3409 | nocomment: true, 3410 | noext: true, 3411 | nonegate: true 3412 | }; 3413 | pattern = IS_WINDOWS ? pattern.replace(/\\/g, '/') : pattern; 3414 | this.minimatch = new minimatch_1.Minimatch(pattern, minimatchOptions); 3415 | } 3416 | /** 3417 | * Matches the pattern against the specified path 3418 | */ 3419 | match(itemPath) { 3420 | // Last segment is globstar? 3421 | if (this.segments[this.segments.length - 1] === '**') { 3422 | // Normalize slashes 3423 | itemPath = pathHelper.normalizeSeparators(itemPath); 3424 | // Append a trailing slash. Otherwise Minimatch will not match the directory immediately 3425 | // preceeding the globstar. For example, given the pattern `/foo/**`, Minimatch returns 3426 | // false for `/foo` but returns true for `/foo/`. Append a trailing slash to handle that quirk. 3427 | if (!itemPath.endsWith(path.sep)) { 3428 | // Note, this is safe because the constructor ensures the pattern has an absolute root. 3429 | // For example, formats like C: and C:foo on Windows are resolved to an aboslute root. 3430 | itemPath = `${itemPath}${path.sep}`; 3431 | } 3432 | } 3433 | else { 3434 | // Normalize slashes and trim unnecessary trailing slash 3435 | itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); 3436 | } 3437 | // Match 3438 | if (this.minimatch.match(itemPath)) { 3439 | return this.trailingSeparator ? internal_match_kind_1.MatchKind.Directory : internal_match_kind_1.MatchKind.All; 3440 | } 3441 | return internal_match_kind_1.MatchKind.None; 3442 | } 3443 | /** 3444 | * Indicates whether the pattern may match descendants of the specified path 3445 | */ 3446 | partialMatch(itemPath) { 3447 | // Normalize slashes and trim unnecessary trailing slash 3448 | itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); 3449 | // matchOne does not handle root path correctly 3450 | if (pathHelper.dirname(itemPath) === itemPath) { 3451 | return this.rootRegExp.test(itemPath); 3452 | } 3453 | return this.minimatch.matchOne(itemPath.split(IS_WINDOWS ? /\\+/ : /\/+/), this.minimatch.set[0], true); 3454 | } 3455 | /** 3456 | * Escapes glob patterns within a path 3457 | */ 3458 | static globEscape(s) { 3459 | return (IS_WINDOWS ? s : s.replace(/\\/g, '\\\\')) // escape '\' on Linux/macOS 3460 | .replace(/(\[)(?=[^/]+\])/g, '[[]') // escape '[' when ']' follows within the path segment 3461 | .replace(/\?/g, '[?]') // escape '?' 3462 | .replace(/\*/g, '[*]'); // escape '*' 3463 | } 3464 | /** 3465 | * Normalizes slashes and ensures absolute root 3466 | */ 3467 | static fixupPattern(pattern) { 3468 | // Empty 3469 | assert(pattern, 'pattern cannot be empty'); 3470 | // Must not contain `.` segment, unless first segment 3471 | // Must not contain `..` segment 3472 | const literalSegments = new internal_path_1.Path(pattern).segments.map(x => Pattern.getLiteral(x)); 3473 | assert(literalSegments.every((x, i) => (x !== '.' || i === 0) && x !== '..'), `Invalid pattern '${pattern}'. Relative pathing '.' and '..' is not allowed.`); 3474 | // Must not contain globs in root, e.g. Windows UNC path \\foo\b*r 3475 | assert(!pathHelper.hasRoot(pattern) || literalSegments[0], `Invalid pattern '${pattern}'. Root segment must not contain globs.`); 3476 | // Normalize slashes 3477 | pattern = pathHelper.normalizeSeparators(pattern); 3478 | // Replace leading `.` segment 3479 | if (pattern === '.' || pattern.startsWith(`.${path.sep}`)) { 3480 | pattern = Pattern.globEscape(process.cwd()) + pattern.substr(1); 3481 | } 3482 | // Replace leading `~` segment 3483 | else if (pattern === '~' || pattern.startsWith(`~${path.sep}`)) { 3484 | const homedir = os.homedir(); 3485 | assert(homedir, 'Unable to determine HOME directory'); 3486 | assert(pathHelper.hasAbsoluteRoot(homedir), `Expected HOME directory to be a rooted path. Actual '${homedir}'`); 3487 | pattern = Pattern.globEscape(homedir) + pattern.substr(1); 3488 | } 3489 | // Replace relative drive root, e.g. pattern is C: or C:foo 3490 | else if (IS_WINDOWS && 3491 | (pattern.match(/^[A-Z]:$/i) || pattern.match(/^[A-Z]:[^\\]/i))) { 3492 | let root = pathHelper.ensureAbsoluteRoot('C:\\dummy-root', pattern.substr(0, 2)); 3493 | if (pattern.length > 2 && !root.endsWith('\\')) { 3494 | root += '\\'; 3495 | } 3496 | pattern = Pattern.globEscape(root) + pattern.substr(2); 3497 | } 3498 | // Replace relative root, e.g. pattern is \ or \foo 3499 | else if (IS_WINDOWS && (pattern === '\\' || pattern.match(/^\\[^\\]/))) { 3500 | let root = pathHelper.ensureAbsoluteRoot('C:\\dummy-root', '\\'); 3501 | if (!root.endsWith('\\')) { 3502 | root += '\\'; 3503 | } 3504 | pattern = Pattern.globEscape(root) + pattern.substr(1); 3505 | } 3506 | // Otherwise ensure absolute root 3507 | else { 3508 | pattern = pathHelper.ensureAbsoluteRoot(Pattern.globEscape(process.cwd()), pattern); 3509 | } 3510 | return pathHelper.normalizeSeparators(pattern); 3511 | } 3512 | /** 3513 | * Attempts to unescape a pattern segment to create a literal path segment. 3514 | * Otherwise returns empty string. 3515 | */ 3516 | static getLiteral(segment) { 3517 | let literal = ''; 3518 | for (let i = 0; i < segment.length; i++) { 3519 | const c = segment[i]; 3520 | // Escape 3521 | if (c === '\\' && !IS_WINDOWS && i + 1 < segment.length) { 3522 | literal += segment[++i]; 3523 | continue; 3524 | } 3525 | // Wildcard 3526 | else if (c === '*' || c === '?') { 3527 | return ''; 3528 | } 3529 | // Character set 3530 | else if (c === '[' && i + 1 < segment.length) { 3531 | let set = ''; 3532 | let closed = -1; 3533 | for (let i2 = i + 1; i2 < segment.length; i2++) { 3534 | const c2 = segment[i2]; 3535 | // Escape 3536 | if (c2 === '\\' && !IS_WINDOWS && i2 + 1 < segment.length) { 3537 | set += segment[++i2]; 3538 | continue; 3539 | } 3540 | // Closed 3541 | else if (c2 === ']') { 3542 | closed = i2; 3543 | break; 3544 | } 3545 | // Otherwise 3546 | else { 3547 | set += c2; 3548 | } 3549 | } 3550 | // Closed? 3551 | if (closed >= 0) { 3552 | // Cannot convert 3553 | if (set.length > 1) { 3554 | return ''; 3555 | } 3556 | // Convert to literal 3557 | if (set) { 3558 | literal += set; 3559 | i = closed; 3560 | continue; 3561 | } 3562 | } 3563 | // Otherwise fall thru 3564 | } 3565 | // Append 3566 | literal += c; 3567 | } 3568 | return literal; 3569 | } 3570 | /** 3571 | * Escapes regexp special characters 3572 | * https://javascript.info/regexp-escaping 3573 | */ 3574 | static regExpEscape(s) { 3575 | return s.replace(/[[\\^$.|?*+()]/g, '\\$&'); 3576 | } 3577 | } 3578 | exports.Pattern = Pattern; 3579 | //# sourceMappingURL=internal-pattern.js.map 3580 | 3581 | /***/ }), 3582 | 3583 | /***/ 972: 3584 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 3585 | 3586 | "use strict"; 3587 | 3588 | Object.defineProperty(exports, "__esModule", { value: true }); 3589 | const assert = __webpack_require__(357); 3590 | const path = __webpack_require__(622); 3591 | const IS_WINDOWS = process.platform === 'win32'; 3592 | /** 3593 | * Similar to path.dirname except normalizes the path separators and slightly better handling for Windows UNC paths. 3594 | * 3595 | * For example, on Linux/macOS: 3596 | * - `/ => /` 3597 | * - `/hello => /` 3598 | * 3599 | * For example, on Windows: 3600 | * - `C:\ => C:\` 3601 | * - `C:\hello => C:\` 3602 | * - `C: => C:` 3603 | * - `C:hello => C:` 3604 | * - `\ => \` 3605 | * - `\hello => \` 3606 | * - `\\hello => \\hello` 3607 | * - `\\hello\world => \\hello\world` 3608 | */ 3609 | function dirname(p) { 3610 | // Normalize slashes and trim unnecessary trailing slash 3611 | p = safeTrimTrailingSeparator(p); 3612 | // Windows UNC root, e.g. \\hello or \\hello\world 3613 | if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) { 3614 | return p; 3615 | } 3616 | // Get dirname 3617 | let result = path.dirname(p); 3618 | // Trim trailing slash for Windows UNC root, e.g. \\hello\world\ 3619 | if (IS_WINDOWS && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) { 3620 | result = safeTrimTrailingSeparator(result); 3621 | } 3622 | return result; 3623 | } 3624 | exports.dirname = dirname; 3625 | /** 3626 | * Roots the path if not already rooted. On Windows, relative roots like `\` 3627 | * or `C:` are expanded based on the current working directory. 3628 | */ 3629 | function ensureAbsoluteRoot(root, itemPath) { 3630 | assert(root, `ensureAbsoluteRoot parameter 'root' must not be empty`); 3631 | assert(itemPath, `ensureAbsoluteRoot parameter 'itemPath' must not be empty`); 3632 | // Already rooted 3633 | if (hasAbsoluteRoot(itemPath)) { 3634 | return itemPath; 3635 | } 3636 | // Windows 3637 | if (IS_WINDOWS) { 3638 | // Check for itemPath like C: or C:foo 3639 | if (itemPath.match(/^[A-Z]:[^\\/]|^[A-Z]:$/i)) { 3640 | let cwd = process.cwd(); 3641 | assert(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); 3642 | // Drive letter matches cwd? Expand to cwd 3643 | if (itemPath[0].toUpperCase() === cwd[0].toUpperCase()) { 3644 | // Drive only, e.g. C: 3645 | if (itemPath.length === 2) { 3646 | // Preserve specified drive letter case (upper or lower) 3647 | return `${itemPath[0]}:\\${cwd.substr(3)}`; 3648 | } 3649 | // Drive + path, e.g. C:foo 3650 | else { 3651 | if (!cwd.endsWith('\\')) { 3652 | cwd += '\\'; 3653 | } 3654 | // Preserve specified drive letter case (upper or lower) 3655 | return `${itemPath[0]}:\\${cwd.substr(3)}${itemPath.substr(2)}`; 3656 | } 3657 | } 3658 | // Different drive 3659 | else { 3660 | return `${itemPath[0]}:\\${itemPath.substr(2)}`; 3661 | } 3662 | } 3663 | // Check for itemPath like \ or \foo 3664 | else if (normalizeSeparators(itemPath).match(/^\\$|^\\[^\\]/)) { 3665 | const cwd = process.cwd(); 3666 | assert(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); 3667 | return `${cwd[0]}:\\${itemPath.substr(1)}`; 3668 | } 3669 | } 3670 | assert(hasAbsoluteRoot(root), `ensureAbsoluteRoot parameter 'root' must have an absolute root`); 3671 | // Otherwise ensure root ends with a separator 3672 | if (root.endsWith('/') || (IS_WINDOWS && root.endsWith('\\'))) { 3673 | // Intentionally empty 3674 | } 3675 | else { 3676 | // Append separator 3677 | root += path.sep; 3678 | } 3679 | return root + itemPath; 3680 | } 3681 | exports.ensureAbsoluteRoot = ensureAbsoluteRoot; 3682 | /** 3683 | * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: 3684 | * `\\hello\share` and `C:\hello` (and using alternate separator). 3685 | */ 3686 | function hasAbsoluteRoot(itemPath) { 3687 | assert(itemPath, `hasAbsoluteRoot parameter 'itemPath' must not be empty`); 3688 | // Normalize separators 3689 | itemPath = normalizeSeparators(itemPath); 3690 | // Windows 3691 | if (IS_WINDOWS) { 3692 | // E.g. \\hello\share or C:\hello 3693 | return itemPath.startsWith('\\\\') || /^[A-Z]:\\/i.test(itemPath); 3694 | } 3695 | // E.g. /hello 3696 | return itemPath.startsWith('/'); 3697 | } 3698 | exports.hasAbsoluteRoot = hasAbsoluteRoot; 3699 | /** 3700 | * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: 3701 | * `\`, `\hello`, `\\hello\share`, `C:`, and `C:\hello` (and using alternate separator). 3702 | */ 3703 | function hasRoot(itemPath) { 3704 | assert(itemPath, `isRooted parameter 'itemPath' must not be empty`); 3705 | // Normalize separators 3706 | itemPath = normalizeSeparators(itemPath); 3707 | // Windows 3708 | if (IS_WINDOWS) { 3709 | // E.g. \ or \hello or \\hello 3710 | // E.g. C: or C:\hello 3711 | return itemPath.startsWith('\\') || /^[A-Z]:/i.test(itemPath); 3712 | } 3713 | // E.g. /hello 3714 | return itemPath.startsWith('/'); 3715 | } 3716 | exports.hasRoot = hasRoot; 3717 | /** 3718 | * Removes redundant slashes and converts `/` to `\` on Windows 3719 | */ 3720 | function normalizeSeparators(p) { 3721 | p = p || ''; 3722 | // Windows 3723 | if (IS_WINDOWS) { 3724 | // Convert slashes on Windows 3725 | p = p.replace(/\//g, '\\'); 3726 | // Remove redundant slashes 3727 | const isUnc = /^\\\\+[^\\]/.test(p); // e.g. \\hello 3728 | return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\'); // preserve leading \\ for UNC 3729 | } 3730 | // Remove redundant slashes 3731 | return p.replace(/\/\/+/g, '/'); 3732 | } 3733 | exports.normalizeSeparators = normalizeSeparators; 3734 | /** 3735 | * Normalizes the path separators and trims the trailing separator (when safe). 3736 | * For example, `/foo/ => /foo` but `/ => /` 3737 | */ 3738 | function safeTrimTrailingSeparator(p) { 3739 | // Short-circuit if empty 3740 | if (!p) { 3741 | return ''; 3742 | } 3743 | // Normalize separators 3744 | p = normalizeSeparators(p); 3745 | // No trailing slash 3746 | if (!p.endsWith(path.sep)) { 3747 | return p; 3748 | } 3749 | // Check '/' on Linux/macOS and '\' on Windows 3750 | if (p === path.sep) { 3751 | return p; 3752 | } 3753 | // On Windows check if drive root. E.g. C:\ 3754 | if (IS_WINDOWS && /^[A-Z]:\\$/i.test(p)) { 3755 | return p; 3756 | } 3757 | // Otherwise trim trailing slash 3758 | return p.substr(0, p.length - 1); 3759 | } 3760 | exports.safeTrimTrailingSeparator = safeTrimTrailingSeparator; 3761 | //# sourceMappingURL=internal-path-helper.js.map 3762 | 3763 | /***/ }), 3764 | 3765 | /***/ 986: 3766 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 3767 | 3768 | "use strict"; 3769 | 3770 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3771 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3772 | return new (P || (P = Promise))(function (resolve, reject) { 3773 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 3774 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 3775 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 3776 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 3777 | }); 3778 | }; 3779 | var __importStar = (this && this.__importStar) || function (mod) { 3780 | if (mod && mod.__esModule) return mod; 3781 | var result = {}; 3782 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 3783 | result["default"] = mod; 3784 | return result; 3785 | }; 3786 | Object.defineProperty(exports, "__esModule", { value: true }); 3787 | const tr = __importStar(__webpack_require__(9)); 3788 | /** 3789 | * Exec a command. 3790 | * Output will be streamed to the live console. 3791 | * Returns promise with return code 3792 | * 3793 | * @param commandLine command to execute (can include additional args). Must be correctly escaped. 3794 | * @param args optional arguments for tool. Escaping is handled by the lib. 3795 | * @param options optional exec options. See ExecOptions 3796 | * @returns Promise exit code 3797 | */ 3798 | function exec(commandLine, args, options) { 3799 | return __awaiter(this, void 0, void 0, function* () { 3800 | const commandArgs = tr.argStringToArray(commandLine); 3801 | if (commandArgs.length === 0) { 3802 | throw new Error(`Parameter 'commandLine' cannot be null or empty.`); 3803 | } 3804 | // Path to tool to execute should be first arg 3805 | const toolPath = commandArgs[0]; 3806 | args = commandArgs.slice(1).concat(args || []); 3807 | const runner = new tr.ToolRunner(toolPath, args, options); 3808 | return runner.exec(); 3809 | }); 3810 | } 3811 | exports.exec = exec; 3812 | //# sourceMappingURL=exec.js.map 3813 | 3814 | /***/ }) 3815 | 3816 | /******/ }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "font-bakery", 3 | "version": "1.0.2", 4 | "description": "f-Actions Font Bakery Action", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "lint": "eslint src/index.js", 8 | "lint:fix": "eslint src/index.js --fix", 9 | "package": "ncc build src/index.js -o dist", 10 | "test": "eslint src/index.js && jest" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/wcys-co/fontbakery.git" 15 | }, 16 | "keywords": [ 17 | "GitHub", 18 | "Actions", 19 | "font", 20 | "fonts", 21 | "typeface", 22 | "build", 23 | "opentype", 24 | "QA" 25 | ], 26 | "author": "f-actions Authors", 27 | "license": "Apache-2.0", 28 | "bugs": { 29 | "url": "https://github.com/wcys-co/fontbakery/issues" 30 | }, 31 | "homepage": "https://github.com/wcys-co/fontbakery", 32 | "dependencies": { 33 | "@actions/core": "^1.2.6", 34 | "@actions/exec": "^1.0.4", 35 | "@actions/glob": "^0.1.1" 36 | }, 37 | "devDependencies": { 38 | "@zeit/ncc": "^0.22.3", 39 | "babel-eslint": "^9.0.0", 40 | "eslint": "^5.16.0", 41 | "eslint-config-airbnb": "^17.1.1", 42 | "eslint-config-airbnb-base": "^14.2.1", 43 | "eslint-config-prettier": "^4.3.0", 44 | "eslint-config-wesbos": "0.0.19", 45 | "eslint-plugin-html": "^5.0.5", 46 | "eslint-plugin-import": "^2.22.1", 47 | "eslint-plugin-jsx-a11y": "^6.4.1", 48 | "eslint-plugin-node": "^11.1.0", 49 | "eslint-plugin-prettier": "^3.3.1", 50 | "eslint-plugin-promise": "^4.2.1", 51 | "eslint-plugin-react": "^7.22.0", 52 | "eslint-plugin-react-hooks": "^1.7.0", 53 | "jest": "^26.6.3", 54 | "prettier": "^1.19.1" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const core = require("@actions/core"); 2 | const glob = require("@actions/glob"); 3 | const exec = require("@actions/exec"); 4 | 5 | async function run() { 6 | const buildPath = core.getInput("path"); 7 | const fbSubCmd = core.getInput("subcmd"); 8 | const fbArgs = core.getInput("args"); 9 | const fbVersion = core.getInput("version"); 10 | 11 | // const options = {}; 12 | // options.listeners = { 13 | // stdout: (data) => { 14 | // myOutput += data.toString(); 15 | // }, 16 | // stderr: (data) => { 17 | // myError += data.toString(); 18 | // }, 19 | // }; 20 | 21 | // ================== 22 | // Install fontbakery 23 | // ================== 24 | try { 25 | await exec.exec("python -m pip install fontbakery==0.7.31"); 26 | // Show the installed version 27 | console.log(""); 28 | console.log("Dependency versions after fontbakery installation:"); 29 | await exec.exec("python -m pip list"); 30 | await exec.exec("python -m pip show fontbakery"); 31 | } catch (error) { 32 | core.setFailed( 33 | `font-bakery Action failed during fontbakery installation attempt with error: ${error.message}` 34 | ); 35 | } 36 | // ========================== 37 | // Display files to be tested 38 | // ========================== 39 | try { 40 | const globber = await glob.create(`${buildPath}`); 41 | console.log(""); 42 | console.log("Beginning fontbakery tests on the following files:"); 43 | for await (const file of globber.globGenerator()) { 44 | console.log(file); 45 | } 46 | console.log(""); 47 | } catch (error) { 48 | core.setFailed( 49 | `font-bakery Action failed during fontbakery file path display attempt with error: ${error.message}` 50 | ); 51 | } 52 | // ======================== 53 | // Execute fontbakery tests 54 | // ======================== 55 | try { 56 | if (fbArgs !== "none") { 57 | await exec.exec(`fontbakery ${fbSubCmd} ${fbArgs} ${buildPath}`); 58 | } else { 59 | await exec.exec(`fontbakery ${fbSubCmd} ${buildPath}`); 60 | } 61 | } catch (error) { 62 | core.setFailed( 63 | `font-bakery Action failed during fontbakery execution attempt with error: ${error.message}` 64 | ); 65 | } 66 | } 67 | 68 | run(); 69 | -------------------------------------------------------------------------------- /tests/LICENSE_OFL.txt: -------------------------------------------------------------------------------- 1 | This Font Software is licensed under the SIL Open Font License, 2 | Version 1.1. 3 | 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | ----------------------------------------------------------- 8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 9 | ----------------------------------------------------------- 10 | 11 | PREAMBLE 12 | The goals of the Open Font License (OFL) are to stimulate worldwide 13 | development of collaborative font projects, to support the font 14 | creation efforts of academic and linguistic communities, and to 15 | provide a free and open framework in which fonts may be shared and 16 | improved in partnership with others. 17 | 18 | The OFL allows the licensed fonts to be used, studied, modified and 19 | redistributed freely as long as they are not sold by themselves. The 20 | fonts, including any derivative works, can be bundled, embedded, 21 | redistributed and/or sold with any software provided that any reserved 22 | names are not used by derivative works. The fonts and derivatives, 23 | however, cannot be released under any other type of license. The 24 | requirement for fonts to remain under this license does not apply to 25 | any document created using the fonts or their derivatives. 26 | 27 | DEFINITIONS 28 | "Font Software" refers to the set of files released by the Copyright 29 | Holder(s) under this license and clearly marked as such. This may 30 | include source files, build scripts and documentation. 31 | 32 | "Reserved Font Name" refers to any names specified as such after the 33 | copyright statement(s). 34 | 35 | "Original Version" refers to the collection of Font Software 36 | components as distributed by the Copyright Holder(s). 37 | 38 | "Modified Version" refers to any derivative made by adding to, 39 | deleting, or substituting -- in part or in whole -- any of the 40 | components of the Original Version, by changing formats or by porting 41 | the Font Software to a new environment. 42 | 43 | "Author" refers to any designer, engineer, programmer, technical 44 | writer or other person who contributed to the Font Software. 45 | 46 | PERMISSION & CONDITIONS 47 | Permission is hereby granted, free of charge, to any person obtaining 48 | a copy of the Font Software, to use, study, copy, merge, embed, 49 | modify, redistribute, and sell modified and unmodified copies of the 50 | Font Software, subject to the following conditions: 51 | 52 | 1) Neither the Font Software nor any of its individual components, in 53 | Original or Modified Versions, may be sold by itself. 54 | 55 | 2) Original or Modified Versions of the Font Software may be bundled, 56 | redistributed and/or sold with any software, provided that each copy 57 | contains the above copyright notice and this license. These can be 58 | included either as stand-alone text files, human-readable headers or 59 | in the appropriate machine-readable metadata fields within text or 60 | binary files as long as those fields can be easily viewed by the user. 61 | 62 | 3) No Modified Version of the Font Software may use the Reserved Font 63 | Name(s) unless explicit written permission is granted by the 64 | corresponding Copyright Holder. This restriction only applies to the 65 | primary font name as presented to the users. 66 | 67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 68 | Software shall not be used to promote, endorse or advertise any 69 | Modified Version, except to acknowledge the contribution(s) of the 70 | Copyright Holder(s) and the Author(s) or with their explicit written 71 | permission. 72 | 73 | 5) The Font Software, modified or unmodified, in part or in whole, 74 | must be distributed entirely under this license, and must not be 75 | distributed under any other license. The requirement for fonts to 76 | remain under this license does not apply to any document created using 77 | the Font Software. 78 | 79 | TERMINATION 80 | This license becomes null and void if any of the above conditions are 81 | not met. 82 | 83 | DISCLAIMER 84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 92 | OTHER DEALINGS IN THE FONT SOFTWARE. 93 | -------------------------------------------------------------------------------- /tests/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WCYS-Co/fontbakery/21fac33e4aaee86516bc14c9b67aaded9c799025/tests/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /tests/NotoSans-Regular2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WCYS-Co/fontbakery/21fac33e4aaee86516bc14c9b67aaded9c799025/tests/NotoSans-Regular2.ttf -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | The Noto font artifacts distributed in this repository are licensed under the SIL Open Font License v1.1. Please see [LICENSE_OFL.txt](LICENSE_OFL.txt) for the full text of the license. -------------------------------------------------------------------------------- /tests/check-test.py: -------------------------------------------------------------------------------- 1 | from fontbakery.checkrunner import Section, PASS, FAIL 2 | from fontbakery.callable import check 3 | from fontbakery.fonts_profile import profile_factory 4 | 5 | profile_imports = () 6 | profile = profile_factory(default_section=Section("Test profile for Action CI")) 7 | 8 | PROFILE_CHECKS = [ 9 | "com.factions/tests/alwayspass", 10 | ] 11 | 12 | excluded_check_ids = () 13 | 14 | 15 | @check( 16 | id="com.factions/tests/alwayspass", 17 | rationale=""" 18 | A test check for CI testing of the wcys-co/fontbakery GitHub 19 | Action 20 | """, 21 | ) 22 | def com_factions_tests_alwayspass(ttFonts): 23 | """Fake test for testing purposes""" 24 | yield PASS, "This always passes so that checks themselves do not fail CI" 25 | 26 | 27 | # ================================================ 28 | # 29 | # End check definitions 30 | # 31 | # ================================================ 32 | 33 | # skip filter function to exclude checks defined in the 34 | # fontbakery universal profile 35 | def check_skip_filter(checkid, font=None, **iterargs): 36 | if font and checkid in excluded_check_ids: 37 | return False, ("Check skipped in this profile") 38 | return True, None 39 | 40 | 41 | profile.check_skip_filter = check_skip_filter 42 | profile.auto_register(globals()) 43 | profile.test_expected_checks(PROFILE_CHECKS, exclusive=True) 44 | --------------------------------------------------------------------------------