11 Commits

Author SHA1 Message Date
Gergő Jedlicska 352365220a move to a file based function input 2023-08-10 17:03:40 +02:00
Gergő Jedlicska c3d711f76d update dist 2023-08-10 16:26:47 +02:00
Gergő Jedlicska ae84132685 Merge branch 'main' of github.com:specklesystems/speckle-automate-github-action 2023-08-10 16:06:40 +02:00
Gergő Jedlicska 937dd88b55 merge error raising 2023-08-10 16:06:11 +02:00
dependabot[bot] c05a324919 build(deps-dev): bump @typescript-eslint/eslint-plugin (#190)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.2.1 to 6.3.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.3.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 09:47:11 +02:00
dependabot[bot] 2f49a4a2c3 build(deps-dev): bump vite from 4.4.8 to 4.4.9 (#188)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.8 to 4.4.9.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.9/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 09:43:24 +02:00
dependabot[bot] 62fe5d2d6e build(deps-dev): bump @typescript-eslint/parser from 6.2.1 to 6.3.0 (#191)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.2.1 to 6.3.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.3.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 09:43:00 +02:00
dependabot[bot] 0715b5030c build(deps-dev): bump @types/node from 18.17.1 to 18.17.4 (#192)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.17.1 to 18.17.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 09:41:39 +02:00
Gergő Jedlicska 0b374bbe38 gergo/simplify (#189)
* refactor to a lean implementation

* update gitignore

* rework retry errors

* add main test example

* remove integration tests

* prettier fix
2023-08-09 09:39:37 +02:00
Gergő Jedlicska d742e579eb remove speckle function path 2023-08-07 16:38:26 +02:00
Gergő Jedlicska 5af60941ce Update action.yaml 2023-08-07 15:59:36 +02:00
52 changed files with 428 additions and 123071 deletions
-23
View File
@@ -7,29 +7,6 @@ on: # rebuild any PRs and main branch changes
- 'releases/*'
jobs:
integration-test: # make sure the action works on a clean machine without building
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.4.0
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- name: Yarn Install
run: yarn install
- uses: actions/cache/save@v3
id: cache-save
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
- run: |
yarn run run:mockserver & # run mockserver in background, will be killed when test finishes
- uses: ./
with:
speckle_automate_url: 'http://127.0.0.1:3000'
speckle_token: 'lolzSuperSecretzToken'
speckle_function_id: 'functionid'
speckle_function_path: 'examples/minimal'
speckle_function_command: 'echo'
pre-commit:
runs-on: ubuntu-latest
steps:
+1
View File
@@ -34,6 +34,7 @@ node_modules
# dotenv environment variables file
.env
.env.test
.envrc
# Ignore built ts files
lib
-16
View File
@@ -5,7 +5,6 @@ repos:
- id: check-yaml
args:
- --allow-multiple-documents
exclude: deploy/helm
- id: check-merge-conflict
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
@@ -49,21 +48,6 @@ repos:
types:
- ts
language: system
- id: build-mockserver
name: build mockserver package
entry: yarn run package:mockserver
pass_filenames: false
types:
- ts
language: system
- id: unit tests
name: unit tests
entry: yarn run test
pass_filenames: false
language: system
types:
- ts
exclude: ^dist/
- repo: https://github.com/specklesystems/pre-commit
rev: '0.2.0'
+6 -10
View File
@@ -1,26 +1,22 @@
name: 'Speckle Automate Function Publisher'
description: 'Builds and publishes a Speckle Automate Function to the Speckle Server.'
name: 'Speckle Automate function version publisher'
description: 'Publishes a new version of a Speckle Automate Function to the Speckle Automate platform.'
author: 'Speckle Systems'
branding:
icon: 'upload-cloud'
color: 'blue'
inputs:
speckle_automate_url:
description: 'Speckle Automate Server URL.'
description: 'Speckle Automate URL.'
required: false
default: 'https://automate.speckle.dev'
speckle_token:
description: 'Token for authentication to Speckle Automate Server, allowing publishing of Speckle Functions. **The token must be stored in GitHub as an encrypted secret**.'
description: 'Token for authentication to Speckle Automate, allowing publishing of Speckle Automate Functions. **The token must be stored in GitHub as an encrypted secret**.'
required: true
speckle_function_path:
description: 'Path to the Speckle Function definition (`specklefunction.yaml`) to be published.'
required: false
default: '.' # root directory of the checked out source code, ${GITHUB_WORKSPACE}
speckle_function_id:
description: 'The unique identifier of the function. Go to automate to generate one.'
required: true
speckle_function_input_schema:
description: 'JSON Schema of the parameters object required by the function.'
speckle_function_input_schema_file_path:
description: 'File path containing JSON Schema of the parameters object required by the function.'
required: false
speckle_function_command:
description: 'The command to run to execute the function in a runtime environment.'
Generated Vendored
+1 -1
View File
@@ -9,7 +9,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "toFormData": () => (/* binding */ toFormData)
/* harmony export */ });
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2777);
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7972);
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8010);
Generated Vendored
+134 -8193
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
-457
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-28552
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-1087
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-1929
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-6131
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-28541
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-3872
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-2900
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-38030
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-833
View File
@@ -1,833 +0,0 @@
@parcel/watcher-wasm
MIT
arch
MIT
The MIT License (MIT)
Copyright (c) Feross Aboukhadijeh
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
braces
MIT
The MIT License (MIT)
Copyright (c) 2014-2018, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
clipboardy
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
consola
MIT
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
Prompt support is based on https://github.com/natemoo-re/clack
MIT License
Copyright (c) Nate Moore
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
Color support is based on https://github.com/jorgebucaran/colorette
Copyright © Jorge Bucaran <https://jorgebucaran.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cross-spawn
MIT
The MIT License (MIT)
Copyright (c) 2018 Made With MOXY Lda <hello@moxy.studio>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
execa
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
fill-range
MIT
The MIT License (MIT)
Copyright (c) 2014-present, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
get-stream
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
h3
MIT
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
human-signals
Apache-2.0
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2019 ehmicky <ehmicky@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
is-docker
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
is-extglob
MIT
The MIT License (MIT)
Copyright (c) 2014-2016, Jon Schlinkert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
is-glob
MIT
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
is-number
MIT
The MIT License (MIT)
Copyright (c) 2014-present, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
is-stream
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
is-wsl
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
isexe
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
jiti
MIT
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
listhen
MIT
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
merge-stream
MIT
The MIT License (MIT)
Copyright (c) Stephen Sugden <me@stephensugden.com> (stephensugden.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
micromatch
MIT
The MIT License (MIT)
Copyright (c) 2014-present, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
mimic-fn
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
npm-run-path
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
onetime
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
path-key
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
picomatch
MIT
The MIT License (MIT)
Copyright (c) 2017-present, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
shebang-command
MIT
MIT License
Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com> (github.com/kevva)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
shebang-regex
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
signal-exit
ISC
The ISC License
Copyright (c) 2015, Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
strip-final-newline
MIT
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
to-regex-range
MIT
The MIT License (MIT)
Copyright (c) 2015-present, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
which
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-3
View File
@@ -1,3 +0,0 @@
{
"type": "module"
}
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.
-7
View File
@@ -1,7 +0,0 @@
apiVersion: speckle.systems/v1alpha1
kind: SpeckleFunction
metadata:
name: minimal
annotations:
'speckle.systems/v1alpha1/publishing/status': 'draft'
spec: {}
+6 -16
View File
@@ -8,16 +8,14 @@
"main": "lib/main.js",
"type": "module",
"scripts": {
"all": "yarn run build && yarn run prettier:check && yarn run lint && yarn run package && yarn run package:mockserver && yarn run test",
"all": "yarn run build && yarn run prettier:check && yarn run lint && yarn run package",
"build": "tsc -p tsconfig.json",
"build:image": "docker build -t speckle/speckle-automate-github-action:local .",
"lint": "eslint src/**/*.ts",
"package": "ncc build --target es2020 --source-map --license licenses.txt -o dist/action src/main.ts",
"package:mockserver": "ncc build --target es2020 --source-map --license licenses.txt -o dist/testing/mockserver src/tests/mock-server.ts",
"precommit": "pre-commit run --all-files",
"prettier:check": "prettier --check '**/*.ts'",
"prettier:fix": "prettier --write '**/*.ts'",
"run:mockserver": "node dist/testing/mockserver/index.js",
"test": "vitest --run --coverage",
"test:watch": "vitest"
},
@@ -28,14 +26,13 @@
"@actions/core": "^1.10.0",
"@lifeomic/attempt": "^3.0.3",
"node-fetch": "^3.3.2",
"zod": "^3.21.4",
"zod-validation-error": "^1.3.1"
"zod": "^3.21.4"
},
"devDependencies": {
"@types/js-yaml": "^4.0.5",
"@types/node": "^18.17.1",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"@types/node": "^18.17.4",
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"@vercel/ncc": "^0.36.1",
"@vitest/coverage-istanbul": "^0.34.1",
"eslint": "^8.46.0",
@@ -48,16 +45,9 @@
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vitest": "^0.2.8",
"get-port-please": "^3.0.1",
"h3": "^1.7.1",
"js-yaml": "^4.1.0",
"listhen": "^1.2.2",
"msw": "^1.2.3",
"pino": "^8.14.2",
"pino-pretty": "^10.2.0",
"prettier": "^3.0.1",
"typescript": "^5.1.6",
"vite": "^4.4.8",
"vite": "^4.4.9",
"vitest": "^0.34.1"
}
}
-275
View File
@@ -1,275 +0,0 @@
import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'
import { setupServer } from 'msw/node'
import { rest } from 'msw'
import { getMinimalSpeckleFunctionExample } from '../schema/specklefunction.spec.js'
import httpClient, {
defaultClientErrorHandler,
throwErrorOnClientErrorStatusCode,
NonRetryableError,
RetryableError
} from './client.js'
import { getLogger } from '../tests/logger.js'
import { ValidationError } from 'zod-validation-error'
import { AttemptContext } from '@lifeomic/attempt'
import fetch, { AbortError, FetchError } from 'node-fetch'
import { Readable } from 'stream'
describe('client', () => {
const server = setupServer()
beforeAll(() => {
server.listen({ onUnhandledRequest: 'error' })
})
afterAll(() => {
server.close()
})
afterEach(() => {
server.resetHandlers()
})
function createFakeContext(): AttemptContext {
return {
attemptNum: 0,
attemptsRemaining: 0,
aborted: false,
abort() {
this.aborted = true
}
}
}
function fakeErrorHandler(error: unknown, context: AttemptContext) {
const fakeContext = createFakeContext()
defaultClientErrorHandler(error, createFakeContext())
context.aborted = fakeContext.aborted
}
describe('postManifest', () => {
describe('valid input', () => {
it('should respond to client with image name, function id, and version id', async () => {
server.use(
rest.post(
'https://success.automate.speckle.example.org/api/v1/functions/functionid/versions',
async (req, res, ctx) => {
expect(await req.json()).toStrictEqual({
versionTag: 'main',
commitId: '1234567890',
command: [],
inputSchema: {},
annotations: getMinimalSpeckleFunctionExample().metadata?.annotations
})
expect(req.headers.get('Authorization')).toBe('Bearer supersecret')
const response = await res(
ctx.status(201),
ctx.json({
versionId: 'minimalversionid'
})
)
return response
}
)
)
const test = httpClient.postManifest(
'https://success.automate.speckle.example.org',
'supersecret',
'functionid',
{
versionTag: 'main',
commitId: '1234567890',
inputSchema: {},
command: [],
annotations: getMinimalSpeckleFunctionExample()?.metadata?.annotations
},
getLogger(),
fetch,
fakeErrorHandler
)
await expect(test).resolves.toStrictEqual({
versionId: 'minimalversionid'
})
})
})
describe('server responds with a 500 HTTP Status Code', () => {
it('should throw an error', async () => {
server.use(
rest.post(
'https://failure.automate.speckle.example.org/api/v1/functions/functionid/versions',
async (req, res, ctx) => {
const response = await res(ctx.status(500))
return response
}
)
)
await expect(
httpClient.postManifest(
'https://failure.automate.speckle.example.org',
'sometoken',
'functionid',
{
versionTag: '',
commitId: '',
command: [],
inputSchema: {},
annotations: getMinimalSpeckleFunctionExample()?.metadata?.annotations
},
getLogger(),
fetch,
fakeErrorHandler
)
).rejects.toThrow()
})
})
describe('server responds with an unexpected response body', () => {
it('should throw an error', async () => {
server.use(
rest.post(
'https://unexpectedresponse.automate.speckle.example.org/api/v1/functions/functionid/versions',
async (req, res, ctx) => {
const response = await res(
ctx.status(201),
ctx.json({
unexpected: 'unexpected'
})
)
return response
}
)
)
await expect(
httpClient.postManifest(
'https://unexpectedresponse.automate.speckle.example.org',
'sometoken',
'functionid',
{
versionTag: '',
commitId: '',
command: [],
inputSchema: {},
annotations: getMinimalSpeckleFunctionExample()?.metadata?.annotations
},
getLogger(),
fetch,
fakeErrorHandler
)
).rejects.toThrow(ValidationError)
})
})
describe('invalid input', () => {
describe('empty url', () => {
it('should throw an error', async () => {
await expect(
httpClient.postManifest(
'',
'supersecret',
'functionid',
{
versionTag: 'main',
commitId: '1234567890',
command: [],
inputSchema: {},
annotations: getMinimalSpeckleFunctionExample()?.metadata?.annotations
},
getLogger(),
fetch,
fakeErrorHandler
)
).rejects.toThrow(Error)
})
})
describe('empty token', () => {
it('should throw an error', async () => {
await expect(
httpClient.postManifest(
'https://example.org',
'',
'functionid',
{
versionTag: 'main',
commitId: '1234567890',
inputSchema: {},
command: [],
annotations: getMinimalSpeckleFunctionExample()?.metadata?.annotations
},
getLogger(),
fetch,
fakeErrorHandler
)
).rejects.toThrow(Error)
})
})
})
})
describe('defaultClientErrorHandler', () => {
it('aborts unknown errors', () => {
const context = createFakeContext()
expect(context.aborted).toBeFalsy()
defaultClientErrorHandler('🚨', context)
expect(context.aborted).toBeTruthy()
})
it('aborts when the error is a fetch abort error', () => {
const context = createFakeContext()
expect(context.aborted).toBeFalsy()
defaultClientErrorHandler(new AbortError('aborting'), context)
expect(context.aborted).toBeTruthy()
})
it('aborts when the error is a fetch error', () => {
const context = createFakeContext()
expect(context.aborted).toBeFalsy()
defaultClientErrorHandler(new FetchError('not found', 'ENOTFOUND'), context)
expect(context.aborted).toBeTruthy()
})
it('does not abort when the error is a retryable error', () => {
const context = createFakeContext()
expect(context.aborted).toBeFalsy()
defaultClientErrorHandler(new RetryableError('retryable'), context)
expect(context.aborted).toBeFalsy()
})
})
describe('throwErrorOnClientErrorStatusCode', () => {
it('does not throw an error on 2xx', async () => {
const result = await throwErrorOnClientErrorStatusCode(async () => {
return { body: Readable.from(''), status: 200 }
})()
expect(result.status).toBe(200)
})
it('does not throw an error on 3xx', async () => {
const result = await throwErrorOnClientErrorStatusCode(async () => {
return { body: Readable.from(''), status: 300 }
})()
expect(result.status).toBe(300)
})
it('throws an error on 4xx', async () => {
const result = throwErrorOnClientErrorStatusCode(async () => {
return { body: Readable.from(''), status: 400 }
})()
await expect(result).rejects.toThrow(NonRetryableError)
})
it('throws an error on 5xx', async () => {
const result = throwErrorOnClientErrorStatusCode(async () => {
return { body: Readable.from(''), status: 500 }
})()
await expect(result).rejects.toThrow(RetryableError)
})
it('fetch errors are passed through', async () => {
const result = throwErrorOnClientErrorStatusCode(async () => {
throw new FetchError('not found', 'ENOTFOUND')
})()
await expect(result).rejects.toThrow(FetchError)
})
it('abort errors are passed through', async () => {
const result = throwErrorOnClientErrorStatusCode(async () => {
throw new AbortError('aborting error')
})()
await expect(result).rejects.toThrow(AbortError)
})
it('unknown errors are passed through', async () => {
const result = throwErrorOnClientErrorStatusCode(async () => {
throw new Error('unknown error')
})()
await expect(result).rejects.toThrow(Error)
})
})
})
-122
View File
@@ -1,122 +0,0 @@
import {
SpeckleFunctionPostResponseBody,
SpeckleFunctionPostResponseBodySchema,
FunctionVersionRequest
} from './schema.js'
import { URL } from 'url'
import { handleZodError } from '../schema/errors.js'
import { Logger } from '../logging/logger.js'
import fetch, { Response } from 'node-fetch'
import { AttemptContext, HandleError, retry } from '@lifeomic/attempt'
export default {
postManifest: async (
url: string,
token: string,
functionId: string,
body: FunctionVersionRequest,
logger: Logger,
_fetch: typeof fetch = fetch,
errorHandler = defaultClientErrorHandler
): Promise<SpeckleFunctionPostResponseBody> => {
if (!url) throw new Error('Speckle Server URL is required')
if (!token) throw new Error('Speckle Token is required')
const endpointUrl = new URL(`/api/v1/functions/${functionId}/versions`, url)
let responseBodyStream: NodeJS.ReadableStream | null
try {
responseBodyStream = await retryAPIRequest(
throwErrorOnClientErrorStatusCode(async () =>
_fetch(endpointUrl.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify(body)
})
),
errorHandler
)
} catch (err) {
throw new Error(`Failed to register Speckle Function: ${err}`, { cause: err }) //FIXME use a more specific error type
}
const response = new Response(responseBodyStream)
let responseBody: SpeckleFunctionPostResponseBody
try {
responseBody = SpeckleFunctionPostResponseBodySchema.parse(await response.json())
} catch (err) {
throw handleZodError(err, logger)
}
return responseBody
}
}
export function defaultClientErrorHandler(
error: unknown,
context: AttemptContext
): void {
if (isNonRetryableError(error)) {
context.abort()
}
}
function isNonRetryableError(error: unknown) {
return !(error instanceof RetryableError)
}
export function throwErrorOnClientErrorStatusCode<
T extends NodeJS.ReadableStream | null
>(
apiRequest: () => Promise<{ body: T; status: number }>
): () => Promise<{ body: T; status: number }> {
return async () => {
const response = await apiRequest()
// do not retry our failures
if (response.status >= 400 && response.status < 500)
throw new NonRetryableError(
`Status code indicates a client error. Not retrying. (status: "${
response.status
}"; body: "${await new Response(response.body).text()}")`
)
if (response.status >= 500)
throw new RetryableError(
`Status code indicates a server error. Retrying. (status: "${
response.status
}"; body: "${await new Response(response.body).text()}")`
)
return response
}
}
export async function retryAPIRequest<T>(
apiRequest: () => Promise<{ body: T; status: number }>,
errorHandler: HandleError<{ body: T; status: number }>
): Promise<T> {
const { body } = await retry(apiRequest, {
delay: 200,
factor: 2,
maxAttempts: 5,
minDelay: 100,
maxDelay: 500,
jitter: true,
handleError: errorHandler
})
return body
}
export class RetryableError extends Error {
constructor(message: string) {
super(message)
this.name = 'RetryableError'
}
}
export class NonRetryableError extends Error {
constructor(message: string) {
super(message)
this.name = 'NonRetryableError'
}
}
-51
View File
@@ -1,51 +0,0 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { ZodError } from 'zod'
import {
getMinimalSpeckleFunctionExample,
NonConformantSpeckleFunction
} from '../schema/specklefunction.spec.js'
import { FunctionVersionRequestSchema } from './schema.js'
type NonConformanSpeckleFunctionPostRequestBody = {
versionTag: string | undefined
commitId: string | undefined
steps: []
inputSchema: object
manifest: NonConformantSpeckleFunction | undefined
}
function getMinimumRequestBody(): NonConformanSpeckleFunctionPostRequestBody {
return {
versionTag: 'main',
commitId: 'sha123',
steps: [],
inputSchema: {},
manifest: getMinimalSpeckleFunctionExample()
}
}
describe('schema', () => {
let minimal: NonConformanSpeckleFunctionPostRequestBody
beforeEach(() => {
minimal = getMinimumRequestBody()
})
describe('Speckle Function Post Request Body Schema', () => {
it('cannot be empty', async () => {
expect(() => FunctionVersionRequestSchema.parse('')).toThrow(ZodError)
})
describe('versionTag', () => {
it('cannot be empty', () => {
minimal.versionTag = ''
expect(() => FunctionVersionRequestSchema.parse(minimal)).toThrow(ZodError)
})
})
describe('commitId', () => {
it('cannot be empty', () => {
minimal.commitId = ''
expect(() => FunctionVersionRequestSchema.parse(minimal)).toThrow(ZodError)
})
})
})
})
-21
View File
@@ -1,21 +0,0 @@
import { z } from 'zod'
import { SpeckleFunctionAnnotationsSchema } from '../schema/specklefunction.js'
import { CommitIdSchema, VersionTagSchema } from '../schema/inputs.js'
export const FunctionVersionRequestSchema = z.object({
commitId: CommitIdSchema,
versionTag: VersionTagSchema, // TODO: this should be a valid semver...
inputSchema: z.record(z.string(), z.unknown()),
command: z.array(z.string().nonempty()),
annotations: SpeckleFunctionAnnotationsSchema
})
export type FunctionVersionRequest = z.infer<typeof FunctionVersionRequestSchema>
export const SpeckleFunctionPostResponseBodySchema = z.object({
versionId: z.string().nonempty()
})
export type SpeckleFunctionPostResponseBody = z.infer<
typeof SpeckleFunctionPostResponseBodySchema
>
-15
View File
@@ -1,15 +0,0 @@
'use strict'
import { promises as fsPromises } from 'fs'
import yaml from 'js-yaml'
export type FileSystem = {
loadYaml: (filePath: string) => Promise<unknown>
}
const fileUtil = {
loadYaml: async (filePath: string) => {
return yaml.load(await fsPromises.readFile(filePath, 'utf8'))
}
}
export default fileUtil
-64
View File
@@ -1,64 +0,0 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { getMinimalSpeckleFunctionExample } from '../schema/specklefunction.spec.js'
import { getLogger } from '../tests/logger.js'
import { findAndParseManifest } from './parser.js'
import { ValidationError } from 'zod-validation-error'
describe('filesystem/parser', () => {
afterEach(async () => {
vi.restoreAllMocks()
})
describe('No Yaml file', () => {
it('should throw', async () => {
await expect(async () =>
findAndParseManifest('doesNotExist', {
logger: getLogger(),
fileSystem: {
loadYaml: async () => {
throw new Error('File does not exist')
}
}
})
).rejects.toThrow(Error)
})
})
})
describe('Minimal yaml file', () => {
it('should parse', async () => {
const speckleFunction = await findAndParseManifest('examples/minimal', {
logger: getLogger(),
fileSystem: { loadYaml: async () => getMinimalSpeckleFunctionExample() }
})
expect(speckleFunction).toBeDefined()
expect(speckleFunction.metadata.name).toBe('minimal')
})
describe('with filename in path', () => {
it('should parse', async () => {
const speckleFunction = await findAndParseManifest(
'examples/minimal/specklefunction.yaml',
{
logger: getLogger(),
fileSystem: {
loadYaml: async () => getMinimalSpeckleFunctionExample()
}
}
)
expect(speckleFunction).toBeDefined()
expect(speckleFunction.metadata.name).toBe('minimal')
})
})
describe('Invalid yaml file', () => {
it('should throw', async () => {
await expect(async () =>
findAndParseManifest('src/tests/data/invalid', {
logger: getLogger(),
fileSystem: {
loadYaml: async () => {
return 'invalid: yaml'
}
}
})
).rejects.toThrow(ValidationError)
})
})
})
-32
View File
@@ -1,32 +0,0 @@
import { FileSystem } from './files.js'
import { SpeckleFunction, SpeckleFunctionSchema } from '../schema/specklefunction.js'
import * as path from 'path'
import { Logger } from '../logging/logger.js'
import { handleZodError } from '../schema/errors.js'
export type ParserOptions = {
logger: Logger
fileSystem: FileSystem
}
export async function findAndParseManifest(
pathToSpeckleFunctionFile: string,
opts: ParserOptions
): Promise<SpeckleFunction> {
if (!pathToSpeckleFunctionFile.toLocaleLowerCase().endsWith('specklefunction.yaml')) {
pathToSpeckleFunctionFile = path.join(
pathToSpeckleFunctionFile,
'specklefunction.yaml'
)
}
const speckleFunctionRaw = await opts.fileSystem.loadYaml(pathToSpeckleFunctionFile)
let speckleFunction: SpeckleFunction
try {
speckleFunction = await SpeckleFunctionSchema.parseAsync(speckleFunctionRaw)
} catch (err) {
throw handleZodError(err, opts.logger)
}
return speckleFunction
}
-5
View File
@@ -1,5 +0,0 @@
export interface Logger {
error: (message: string | Error) => void
info: (message: string) => void
debug: (message: string) => void
}
+162 -33
View File
@@ -1,44 +1,173 @@
import * as core from '@actions/core'
import { registerSpeckleFunction } from './registerspecklefunction.js'
import fileUtil from './filesystem/files.js'
import { z } from 'zod'
import fetch from 'node-fetch'
import { retry } from '@lifeomic/attempt'
import { readFileSync } from 'node:fs'
async function run(): Promise<void> {
const InputVariablesSchema = z.object({
speckleAutomateUrl: z.string().url().nonempty(),
speckleToken: z.string().nonempty(),
speckleFunctionId: z.string().nonempty(),
speckleFunctionInputSchema: z.record(z.string().nonempty(), z.unknown()).nullable(),
speckleFunctionCommand: z.string().nonempty().array()
})
type InputVariables = z.infer<typeof InputVariablesSchema>
const parseInputs = (): InputVariables => {
const speckleTokenRaw = core.getInput('speckle_token', { required: true })
core.setSecret(speckleTokenRaw)
let speckleFunctionInputSchema: Record<string, unknown> | null = null
try {
const speckleAutomateUrlRaw = core.getInput('speckle_automate_url')
const speckleTokenRaw = core.getInput('speckle_token')
core.setSecret(speckleTokenRaw)
const speckleFunctionPathRaw = core.getInput('speckle_function_path')
const speckleFunctionIdRaw = core.getInput('speckle_function_id')
const speckleFunctionInputSchema = core.getInput('speckle_function_input_schema')
const speckleFunctionCommand = core.getInput('speckle_function_command')
const gitRefName = process.env.GITHUB_REF_NAME
const gitRefType = process.env.GITHUB_REF_TYPE
const gitCommitShaRaw = process.env.GITHUB_SHA
const rawInputSchemaPath = core.getInput('speckle_function_input_schema_file_path')
if (rawInputSchemaPath) {
const rawInputSchema = readFileSync(rawInputSchemaPath, 'utf-8')
speckleFunctionInputSchema = JSON.parse(rawInputSchema)
}
} catch (err) {
core.setFailed(`Parsing the function input schema failed with: ${err}`)
throw err
}
const rawInputs: InputVariables = {
speckleAutomateUrl: core.getInput('speckle_automate_url', { required: true }),
speckleToken: speckleTokenRaw,
speckleFunctionId: core.getInput('speckle_function_id', { required: true }),
speckleFunctionInputSchema,
speckleFunctionCommand: core
.getInput('speckle_function_command', { required: true })
.split(' ')
}
const inputParseResult = InputVariablesSchema.safeParse(rawInputs)
if (inputParseResult.success) return inputParseResult.data
core.setFailed(
`The provided inputs do not match the required schema, ${inputParseResult.error.message}`
)
throw inputParseResult.error
}
if (!gitCommitShaRaw) throw new Error('GITHUB_REF_NAME is not defined')
if (!gitRefName) throw new Error('GITHUB_REF_NAME is not defined')
if (!gitRefType) throw new Error('GITHUB_REF_TYPE is not defined')
const RequiredEnvVarsSchema = z.object({
gitRefName: z.string().nonempty(),
gitRefType: z.string().nonempty(),
gitCommitSha: z.string().nonempty()
})
const speckleAutomateHost = new URL(speckleAutomateUrlRaw).host
type RequiredEnvVars = z.infer<typeof RequiredEnvVarsSchema>
const { versionId } = await registerSpeckleFunction({
speckleServerUrl: speckleAutomateUrlRaw,
speckleToken: speckleTokenRaw,
speckleFunctionPath: speckleFunctionPathRaw,
speckleFunctionId: speckleFunctionIdRaw,
speckleFunctionInputSchema,
speckleFunctionCommand,
versionTag: gitRefType === 'tag' ? gitRefName : gitCommitShaRaw,
commitId: gitCommitShaRaw,
logger: core,
fileSystem: fileUtil
})
const parseEnvVars = (): RequiredEnvVars => {
const parseResult = RequiredEnvVarsSchema.safeParse({
gitCommitSha: process.env.GITHUB_SHA,
gitRefType: process.env.GITHUB_REF_TYPE,
gitRefName: process.env.GITHUB_REF_NAME
} as RequiredEnvVars)
if (parseResult.success) return parseResult.data
core.setFailed(
`The current execution environment does not have the required variables: ${parseResult.error.message}`
)
throw parseResult.error
}
core.setOutput('version_id', versionId)
core.setOutput('speckle_automate_host', speckleAutomateHost)
} catch (error) {
if (error instanceof Error) core.setFailed(error.message)
type FunctionVersionRequestBody = {
commitId: string
versionTag: string
command: string[]
inputSchema: Record<string, unknown> | null
}
const FunctionVersionResponseBodySchema = z.object({
versionId: z.string().nonempty()
})
type FunctionVersionResponseBody = z.infer<typeof FunctionVersionResponseBodySchema>
const registerNewVersionForTheSpeckleAutomateFunction = async (
{
speckleAutomateUrl,
speckleFunctionCommand,
speckleFunctionId,
speckleFunctionInputSchema,
speckleToken
}: InputVariables,
{ gitCommitSha, gitRefName, gitRefType }: RequiredEnvVars
): Promise<FunctionVersionResponseBody> => {
try {
const requestBody: FunctionVersionRequestBody = {
commitId: gitCommitSha,
versionTag: gitRefType === 'tag' ? gitRefName : gitCommitSha,
command: speckleFunctionCommand,
inputSchema: speckleFunctionInputSchema
}
const versionRegisterUrl = new URL(
`/api/v1/functions/${speckleFunctionId}/versions`,
speckleAutomateUrl
)
const retryFlag = 'RETRY THIS'
const response = await retry(
async () => {
const res = await fetch(versionRegisterUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
authorization: `Bearer ${speckleToken}`
},
body: JSON.stringify(requestBody)
})
if (res.ok) return await res.json()
if (res.status >= 500) {
core.warning(
`RETRYING Version creation request since it failed with: ${await res.text()}`
)
throw retryFlag
}
throw Error(
`Request failed with status ${res.status}. Reason: ${await res.text()} `
)
},
{
delay: 200,
factor: 2,
maxAttempts: 5,
minDelay: 100,
maxDelay: 500,
jitter: true,
handleError: (err, context) => {
if (err !== retryFlag) {
context.abort()
throw err
}
}
}
)
return FunctionVersionResponseBodySchema.parse(response)
} catch (err) {
core.setFailed(
`Failed to register new function version to the automate server: ${err}`
)
throw err
}
}
export async function run(): Promise<void> {
core.info('Start registering a new version on the automate instance')
const inputVariables = parseInputs()
core.info(`Parsed input variables to: ${JSON.stringify(inputVariables)}`)
const requiredEnvVars = parseEnvVars()
core.info(
`Parsed required environment variables to: ${JSON.stringify(requiredEnvVars)}`
)
const { speckleAutomateUrl, speckleFunctionId } = inputVariables
core.setOutput('speckle_automate_host', new URL(speckleAutomateUrl).host)
core.info(
`Sending a new function version definition for function ${speckleFunctionId} to the automate server: ${speckleAutomateUrl}`
)
const { versionId } = await registerNewVersionForTheSpeckleAutomateFunction(
inputVariables,
requiredEnvVars
)
core.setOutput('version_id', versionId)
core.info(`Registered function version with new id: ${versionId}`)
}
run()
-90
View File
@@ -1,90 +0,0 @@
import client from './client/client.js'
import { Logger } from './logging/logger.js'
import {
SpeckleServerUrlSchema,
SpeckleTokenSchema,
SpeckleFunctionPathSchema,
SpeckleFunctionIdSchema,
SpeckleFunctionInputSchema,
VersionTagSchema,
CommitIdSchema
} from './schema/inputs.js'
import { handleZodError } from './schema/errors.js'
import { FunctionVersionRequest } from './client/schema.js'
// import { findAndParseManifest } from './filesystem/parser.js'
import { FileSystem } from './filesystem/files.js'
type ProcessOptions = {
speckleServerUrl: string | undefined
speckleToken: string
versionTag: string
commitId: string
speckleFunctionPath: string | undefined
speckleFunctionId: string
speckleFunctionCommand: string
speckleFunctionInputSchema?: string | undefined
logger: Logger
fileSystem: FileSystem
}
type ProcessResult = {
versionId: string
}
export async function registerSpeckleFunction(
opts: ProcessOptions
): Promise<ProcessResult> {
let speckleServerUrl: string
let speckleToken: string
let speckleFunctionPath: string
let speckleFunctionId: string
let speckleFunctionCommand: string[]
let speckleFunctionInputSchema: Record<string, unknown>
let versionTag: string
let commitId: string
try {
speckleServerUrl = SpeckleServerUrlSchema.parse(opts.speckleServerUrl)
speckleToken = SpeckleTokenSchema.parse(opts.speckleToken)
speckleFunctionPath = SpeckleFunctionPathSchema.parse(opts.speckleFunctionPath)
speckleFunctionId = SpeckleFunctionIdSchema.parse(opts.speckleFunctionId)
versionTag = VersionTagSchema.parse(opts.versionTag)
commitId = CommitIdSchema.parse(opts.commitId)
speckleFunctionInputSchema = opts.speckleFunctionInputSchema
? SpeckleFunctionInputSchema.parse(JSON.parse(opts.speckleFunctionInputSchema))
: {}
speckleFunctionCommand = opts.speckleFunctionCommand.split(' ')
} catch (err) {
throw handleZodError(err, opts.logger)
}
opts.logger.info(`Speckle Server URL: '${speckleServerUrl}'`)
//token is masked in the logs, so no need to print it here.
opts.logger.info(`Speckle Function Path: '${speckleFunctionPath}'`)
opts.logger.info(`Speckle Function ID: '${speckleFunctionId}'`)
// const manifest = await findAndParseManifest(speckleFunctionPath, {
// logger: opts.logger,
// fileSystem: opts.fileSystem
// })
const body: FunctionVersionRequest = {
commitId,
versionTag,
command: speckleFunctionCommand,
inputSchema: speckleFunctionInputSchema
}
const response = await client.postManifest(
speckleServerUrl,
speckleToken,
speckleFunctionId,
body,
opts.logger
)
opts.logger.info(
`Successfully registered version ${response.versionId} of Speckle Function ${speckleFunctionId}`
)
return response
}
-23
View File
@@ -1,23 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { handleZodError } from './errors.js'
import { ZodError } from 'zod'
import { ValidationError } from 'zod-validation-error'
describe('errors', () => {
describe('with ZodError', () => {
it('logs and throws', async () => {
const errorFn = vi.fn()
const logger = { error: errorFn, info: vi.fn(), warn: vi.fn(), debug: vi.fn() }
expect(() => handleZodError(new ZodError([]), logger)).toThrow(ValidationError)
expect(errorFn).toHaveBeenCalledTimes(1)
})
})
describe('with unknown error', () => {
it('throws', async () => {
const errorFn = vi.fn()
const logger = { error: errorFn, info: vi.fn(), warn: vi.fn(), debug: vi.fn() }
expect(() => handleZodError(new Error('unknown'), logger)).toThrow(Error)
expect(errorFn).toHaveBeenCalledTimes(0)
})
})
})
-12
View File
@@ -1,12 +0,0 @@
import { Logger } from '../logging/logger.js'
import { fromZodError } from 'zod-validation-error'
import { ZodError } from 'zod'
export function handleZodError(err: unknown, logger: Logger): void {
if (err instanceof ZodError) {
const validationError = fromZodError(err)
logger.error(validationError)
throw validationError
}
throw err
}
-55
View File
@@ -1,55 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
SpeckleFunctionPathSchema,
SpeckleServerUrlSchema,
SpeckleTokenSchema,
SpeckleFunctionInputSchema
} from './inputs.js'
import { ZodError } from 'zod'
describe('schema', () => {
describe('Speckle Server URL', () => {
it('cannot be empty', async () => {
expect(() => SpeckleServerUrlSchema.parse('')).toThrow(ZodError)
})
})
describe('Speckle Token', () => {
it('cannot be empty', async () => {
expect(() => SpeckleTokenSchema.parse('')).toThrow(ZodError)
})
})
describe('Speckle Function Path', () => {
it('cannot be empty', async () => {
expect(() => SpeckleFunctionPathSchema.parse('')).toThrow(ZodError)
})
it('cannot be an absolute path', async () => {
expect(() => SpeckleFunctionPathSchema.parse('/')).toThrow(ZodError)
})
it('can be a nested relative path', async () => {
expect(SpeckleFunctionPathSchema.parse('src/main.ts')).toBe('src/main.ts')
})
it('can have a leading dot slash', async () => {
expect(SpeckleFunctionPathSchema.parse('./src/main.ts')).toBe('./src/main.ts')
})
it('can be at the current directory', async () => {
expect(SpeckleFunctionPathSchema.parse('.')).toBe('.')
})
})
describe('Speckle Function Input Schema', () => {
it('can parse objects', () => {
const inputSchema = { foo: 'bar' }
expect(SpeckleFunctionInputSchema.parse(inputSchema)).toStrictEqual(inputSchema)
})
it('works for empty objects', () => {
const inputSchema = {}
expect(SpeckleFunctionInputSchema.parse(inputSchema)).toStrictEqual(inputSchema)
})
it('fails for not object types', () => {
const inputSchema = '{ "foo": "bar" }'
expect(SpeckleFunctionInputSchema.safeParse(inputSchema).success).toBeFalsy()
})
})
})
-15
View File
@@ -1,15 +0,0 @@
import { z } from 'zod'
export const SpeckleServerUrlSchema = z.string().url().nonempty()
export const SpeckleTokenSchema = z.string().nonempty()
export const SpeckleFunctionRepositorySchema = z.string().nonempty() //TODO validate this as a git+https, https, or ssh url
export const SpeckleFunctionPathSchema = z
.string()
.nonempty()
.refine((value: string) => !value.startsWith('/'), {
message: 'Must not be an absolute path.'
})
export const SpeckleFunctionIdSchema = z.string().nonempty()
export const VersionTagSchema = z.string().nonempty()
export const CommitIdSchema = z.string().nonempty()
export const SpeckleFunctionInputSchema = z.record(z.string(), z.unknown())
-90
View File
@@ -1,90 +0,0 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { SpeckleFunctionAnnotations, SpeckleFunctionSchema } from './specklefunction.js'
import { ZodError } from 'zod'
export type NonConformantSpeckleFunction = {
apiVersion: string | undefined
kind: string | undefined
metadata:
| {
name: string | undefined
annotations: SpeckleFunctionAnnotations | undefined
}
| undefined
spec: object | undefined
}
export function getMinimalSpeckleFunctionExample(): NonConformantSpeckleFunction {
return {
apiVersion: 'speckle.systems/v1alpha1',
kind: 'SpeckleFunction',
metadata: {
name: 'minimal',
annotations: {
'speckle.systems/v1alpha1/publishing/status': 'draft'
}
},
spec: {}
}
}
describe('speckle function schema', () => {
let minimal: NonConformantSpeckleFunction
beforeEach(() => {
minimal = getMinimalSpeckleFunctionExample()
})
describe('Speckle Function', () => {
it('cannot be empty', async () => {
expect(() => SpeckleFunctionSchema.parse({})).toThrow(ZodError)
})
describe('apiVersion', () => {
it('cannot be missing-', async () => {
minimal.apiVersion = ''
expect(() => SpeckleFunctionSchema.parse('{}')).toThrow(ZodError)
})
it('cannot be invalid', async () => {
minimal.apiVersion = 'invalid'
expect(() => SpeckleFunctionSchema.parse(minimal)).toThrow(ZodError)
})
})
describe('kind', () => {
it('cannot be missing', async () => {
minimal.kind = ''
expect(() => SpeckleFunctionSchema.parse('/')).toThrow(ZodError)
})
it('cannot be invalid', async () => {
minimal.kind = 'invalid'
expect(() => SpeckleFunctionSchema.parse(minimal)).toThrow(ZodError)
})
})
describe('metadata', () => {
it('cannot be missing a metadata', async () => {
minimal.metadata = undefined
expect(() => SpeckleFunctionSchema.parse(minimal)).toThrow(ZodError)
})
describe('name', () => {
it('cannot be missing', async () => {
if (minimal.metadata === undefined) throw new Error('metadata is undefined') // for typescript
minimal.metadata.name = ''
expect(() => SpeckleFunctionSchema.parse(minimal)).toThrow(ZodError)
})
})
})
describe('spec', () => {
it('cannot be missing', async () => {
minimal.spec = undefined
expect(() => SpeckleFunctionSchema.parse(minimal)).toThrow(ZodError)
})
})
it('can be minimal', async () => {
expect(SpeckleFunctionSchema.parse(minimal)).toStrictEqual(minimal)
})
})
})
-61
View File
@@ -1,61 +0,0 @@
import { z } from 'zod'
export type SpeckleFunctionKind = 'SpeckleFunction'
export const SpeckleFunctionKind: SpeckleFunctionKind = 'SpeckleFunction'
export type SpeckleFunctionApiVersion = 'speckle.systems/v1alpha1'
export const SpeckleFunctionApiVersionV1Alpha1: SpeckleFunctionApiVersion =
'speckle.systems/v1alpha1'
export type SpeckleFunctionAnnotations = z.infer<
typeof SpeckleFunctionAnnotationsSchema
>
export const SpeckleFunctionAnnotationsSchema = z
.object({
'speckle.systems/v1alpha1/publishing/status': z
.enum(['publish', 'draft', 'archive'])
.default('draft'), //description('Whether this Function is published (and should appear in the library), a draft, or archived.'),
'speckle.systems/v1alpha1/author': z.string().optional(), //.description('The name of the authoring organisation or individual of this Function.'),
'speckle.systems/v1alpha1/license': z
.enum(['MIT', 'BSD', 'Apache-2.0', 'MPL', 'CC0', 'Unlicense'])
.optional(), //.description('The license under under which this Function is made available. This must match the license in the source code repository.'), //TODO match the specification for license names
'speckle.systems/v1alpha1/website': z.string().url().optional(), //.description('The marketing website for this Function or its authors.'),
'speckle.systems/v1alpha1/documentation': z.string().url().optional(), //.description('The documentation website for this function. For example, this could be a url to the README in the source code repository.'),
'speckle.systems/v1alpha1/keywords': z.string().optional(), //.description('Comma separated list of keywords used for categorising this function.'),
'speckle.systems/v1alpha1/description': z.string().optional()
})
.optional()
export type SpeckleFunction = z.infer<typeof SpeckleFunctionSchema>
export const SpeckleFunctionSchema = z.object({
kind: z.literal(SpeckleFunctionKind),
apiVersion: z.enum([SpeckleFunctionApiVersionV1Alpha1]),
metadata: z.object({
name: z.string().nonempty(),
annotations: SpeckleFunctionAnnotationsSchema
}),
spec: z.object({
inputs: z
.array(
z.object({
//TODO
})
)
.optional(),
results: z
.array(
z.object({
//TODO
})
)
.optional(),
requirements: z
.object({
os: z.enum(['windows', 'linux']).default('linux'),
architecture: z.enum(['amd64']).default('amd64'),
infrastructure: z.array(z.enum(['gpu'])).optional()
})
.optional()
})
})
-88
View File
@@ -1,88 +0,0 @@
import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'
import { setupServer } from 'msw/node'
import { rest } from 'msw'
import { registerSpeckleFunction } from '../registerspecklefunction.js'
import { getLogger } from './logger.js'
import { getMinimalSpeckleFunctionExample } from '../schema/specklefunction.spec.js'
import { ValidationError } from 'zod-validation-error'
describe('integration', () => {
const server = setupServer()
beforeAll(() => {
server.listen({ onUnhandledRequest: 'error' })
})
afterAll(() => {
server.close()
})
afterEach(() => {
server.resetHandlers()
})
describe('Load from ./examples directory', () => {
describe('registerSpeckleAutomate', () => {
describe('valid input', () => {
it('should respond with the version id', async () => {
server.use(
rest.post(
'https://integration1.automate.speckle.example.org/api/v1/functions/functionid/versions',
async (req, res, ctx) => {
const requestData = await req.json()
expect(requestData).toStrictEqual({
versionTag: 'main',
commitId: '1234567890',
command: ['echo', 'Hello', 'world'],
inputSchema: {}
// annotations: getMinimalSpeckleFunctionExample().metadata?.annotations
})
expect(req.headers.get('Authorization')).toBe('Bearer supersecret')
const response = await res(
ctx.status(201),
ctx.json({
versionId: 'minimalversionid'
})
)
return response
}
)
)
const result = registerSpeckleFunction({
speckleFunctionId: 'functionid',
speckleServerUrl: 'https://integration1.automate.speckle.example.org',
speckleToken: 'supersecret',
speckleFunctionPath: 'examples/minimal',
speckleFunctionCommand: 'echo Hello world',
versionTag: 'main',
commitId: '1234567890',
logger: getLogger(),
fileSystem: {
loadYaml: async () => getMinimalSpeckleFunctionExample()
}
})
await expect(result).resolves.toStrictEqual({
versionId: 'minimalversionid'
})
})
})
describe('invalid input', () => {
it('should throw an error', async () => {
await expect(async () =>
registerSpeckleFunction({
speckleFunctionId: 'functionid',
speckleServerUrl: 'https://integration1.automate.speckle.example.org',
speckleToken: '',
speckleFunctionPath: undefined,
speckleFunctionCommand: 'echo Hello world',
versionTag: '',
commitId: '',
logger: getLogger(),
fileSystem: {
loadYaml: async () => getMinimalSpeckleFunctionExample()
}
})
).rejects.toThrow(ValidationError)
})
})
})
})
})
-27
View File
@@ -1,27 +0,0 @@
import { pino, LoggerOptions, stdTimeFunctions } from 'pino'
export function getLogger(): pino.Logger<LoggerOptions> {
const pinoOptions: LoggerOptions = {
base: undefined, // Set to undefined to avoid adding pid, hostname properties to each log.
formatters: {
level: (label: string) => {
return { level: label }
}
},
level: 'debug',
timestamp: stdTimeFunctions.isoTime
}
pinoOptions.transport = {
target: 'pino-pretty',
options: {
colorize: true,
destination: 2, //stderr
ignore: 'time',
levelFirst: true,
singleLine: true
}
}
return pino(pinoOptions)
}
-103
View File
@@ -1,103 +0,0 @@
import {
eventHandler,
createApp,
createRouter,
H3Event,
toNodeListener,
readBody,
sendError,
createError
} from 'h3'
import { listen } from 'listhen'
import { getPort } from 'get-port-please'
import { z } from 'zod'
import { SpeckleFunctionPostResponseBody } from '../client/schema.js'
async function run() {
const hostname = '127.0.0.1'
const app = createApp({ debug: false })
const router = createRouter().post(
'/api/v1/functions/functionid/versions',
eventHandler(async (event: H3Event): Promise<SpeckleFunctionPostResponseBody> => {
try {
const body = await readBody(event)
FunctionVersionRequestSchema.parse(body) // throw error if invalid
event.node.res.statusCode = 201
event.node.res.statusMessage = 'Created'
event.node.res.setHeader('Content-Type', 'application/json')
} catch (err) {
sendError(
event,
createError({
status: 422,
statusText: `Unprocessable Entity. ${
err instanceof Error ? err.message : JSON.stringify(err)
}`
})
)
}
return {
versionId: 'minimalversionid'
}
})
)
app.use(router)
const port = await getPort(3000)
listen(toNodeListener(app), {
hostname,
port
})
}
run()
// copied as of commit 2e04a81dea7f9ee079d17617d4e5fed6b2192211
export const FunctionVersionRequestSchema = z.object({
commitId: z.string(),
versionTag: z.string(),
inputSchema: z.record(z.string(), z.unknown()),
command: z.array(z.string().nonempty()),
annotations: z
.object({
'speckle.systems/v1alpha1/publishing/status': z
.enum(['publish', 'draft', 'archive'], {
description:
'Whether this Function is published (and should appear in the library), a draft, or archived.'
})
.default('draft'),
'speckle.systems/v1alpha1/author': z
.string({
description:
'The name of the authoring organization or individual of this Function.'
})
.optional(),
'speckle.systems/v1alpha1/license': z
.enum(['MIT', 'BSD', 'Apache-2.0', 'MPL', 'CC0', 'Unlicense'], {
description:
'The license under under which this Function is made available. This must match the license in the source code repository.'
})
.optional(), //TODO match the specification for license names
'speckle.systems/v1alpha1/website': z
.string({
description: 'The marketing website for this Function or its authors.'
})
.url()
.optional(),
'speckle.systems/v1alpha1/documentation': z
.string({
description:
'The documentation website for this function. For example, this could be a url to the README in the source code repository.'
})
.url()
.optional(),
'speckle.systems/v1alpha1/keywords': z
.string({
description:
'Comma separated list of keywords used for categorizing this function.'
})
.optional(),
'speckle.systems/v1alpha1/description': z.string().optional()
})
.optional()
})
+16
View File
@@ -0,0 +1,16 @@
import { run } from '../src/main.js'
import { describe, it, vi } from 'vitest'
describe('Register new version', () => {
it('send the request', async () => {
vi.stubEnv('INPUT_SPECKLE_FUNCTION_ID', '{fake}')
vi.stubEnv('INPUT_SPECKLE_TOKEN', '{token}')
vi.stubEnv('INPUT_SPECKLE_FUNCTION_COMMAND', 'echo "hello automate"')
vi.stubEnv('INPUT_SPECKLE_FUNCTION_INPUT_SCHEMA', '{}')
vi.stubEnv('INPUT_SPECKLE_AUTOMATE_URL', 'http://automate.speckle.internal:3030')
vi.stubEnv('GITHUB_SHA', 'commitSha')
vi.stubEnv('GITHUB_REF_TYPE', 'commit')
vi.stubEnv('GITHUB_REF_NAME', 'version')
await run()
})
})
+101 -1277
View File
File diff suppressed because it is too large Load Diff