Compare commits

...

960 Commits

Author SHA1 Message Date
Rob Herley 16b786a545 better error message for usage limits 2023-12-11 22:01:08 -05:00
Rob Herley 18ce228b82 Merge pull request #1603 from actions/robherley/network-errors
Add specific messages for network-specific node error codes
2023-12-11 17:34:24 -05:00
Rob Herley a4bd0f1214 Add specific messages for network-specific node error codes 2023-12-11 17:07:48 -05:00
Rob Herley 37a66ebd47 Merge pull request #1602 from actions/robherley/replace-unzip-lib
[artifact] replace unzipper with unzip-stream
2023-12-11 14:22:07 -05:00
Rob Herley 09249a72d7 push null at end of mocked message 2023-12-11 13:41:11 -05:00
Rob Herley 4c531c013a update packages 2023-12-11 12:24:41 -05:00
Rob Herley 3c3af56b29 replace unzipper with unzip-stream 2023-12-11 12:15:40 -05:00
Vallie Joseph 950e1711a1 Improve error messages (duplicate artifacts; too many artifacts) (#1600)
* cleaning up error messages

* updating package-json

* updating package-lock

* .

* .

* testing return message

* updating error check

* adding test

* rmv unused var

* updating status code to match conflict message
2023-12-11 11:26:54 -05:00
Jonathan Tamsut 88b76de595 Add back 429 to list of retryable requests (#1599)
* add back 429 to list of retryable requests

* fix lint error
2023-12-08 11:00:44 -08:00
Jonathan Tamsut 55a05255d7 Remove 429 request from list of retry-able status codes (#1597)
* remove 429 request from retryable

* remove 413

* make linter happy
2023-12-07 13:22:17 -08:00
Rob Herley 64d1b104d0 Generate Typescript Docs for @actions/artifact (#1595)
* autogenerate artifact documentation

* clean up comments for better autogen docs
2023-12-07 09:57:20 -08:00
Rob Herley 43ccaf05d9 Merge pull request #1596 from actions/robherley/cleanup-handlers
Cleanup artifact handlers hanging node process
2023-12-06 19:27:30 -05:00
Rob Herley f732e4cd62 linter 2023-12-06 23:57:33 +00:00
Rob Herley 8c317a0e59 one too many parses 2023-12-06 23:51:16 +00:00
Rob Herley 715b1acc05 cleanup artifact handlers hanging node process 2023-12-06 23:42:07 +00:00
Rob Herley 207747e7af Merge pull request #1594 from actions/robherley/artifact-docs-updates
@actions/artifact doc updates
2023-12-06 14:30:00 -05:00
Rob Herley c042a30d3d Update packages/artifact/CONTRIBUTIONS.md
Co-authored-by: Mattia Richetto <mattiaerre@github.com>
2023-12-06 14:05:38 -05:00
Rob Herley 70cad3f635 Update packages/artifact/README.md
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2023-12-06 13:19:38 -05:00
Rob Herley 1f87038676 Update packages/artifact/README.md
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2023-12-06 13:19:32 -05:00
Rob Herley 8cd4434523 mention job limit 2023-12-06 17:30:13 +00:00
Rob Herley 2e6c9a1f14 pr feedback 2023-12-06 17:28:03 +00:00
Rob Herley c08a7d1b2e Update packages/artifact/README.md
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2023-12-06 12:19:49 -05:00
Rob Herley 49ef8b93a8 fix typo 2023-12-06 15:38:59 +00:00
Rob Herley 19d4d9d3b2 releases.md: link to breaking v2 changes 2023-12-06 14:52:49 +00:00
Rob Herley b43b97985c Update packages/artifact/docs/faq.md
Co-authored-by: Bethany <bethanyj28@users.noreply.github.com>
2023-12-06 09:31:55 -05:00
Rob Herley 23fb8c4782 Update packages/artifact/README.md
Co-authored-by: Bethany <bethanyj28@users.noreply.github.com>
2023-12-06 09:31:09 -05:00
Rob Herley dc515188a8 Update packages/artifact/README.md
Co-authored-by: Bethany <bethanyj28@users.noreply.github.com>
2023-12-06 09:30:53 -05:00
Rob Herley 79ace256d6 Update packages/artifact/README.md
Co-authored-by: Bethany <bethanyj28@users.noreply.github.com>
2023-12-06 09:30:35 -05:00
Rob Herley 68958c2486 Update packages/artifact/README.md
Co-authored-by: Bethany <bethanyj28@users.noreply.github.com>
2023-12-06 09:30:20 -05:00
Rob Herley 0c9621922e add faq, update releases 2023-12-06 04:22:18 +00:00
Rob Herley 9b31b03496 more readme updates 2023-12-06 04:10:46 +00:00
Rob Herley befa19f3a8 initalize artifact client as default export 2023-12-06 04:00:07 +00:00
Rob Herley e27efe5620 readme & error updates 2023-12-05 21:55:22 +00:00
Rob Herley 449b28aee2 update contributing docs 2023-12-05 21:10:48 +00:00
Rob Herley 04945c6048 Merge pull request #1593 from actions/robherley/api-consistency
Consistent error behavior for Artifact methods
2023-12-05 15:22:16 -05:00
Rob Herley 5f152b798e Update artifact-tests.yml 2023-12-05 13:54:14 -05:00
Rob Herley c390199be6 Update artifact-tests.yml 2023-12-05 13:51:51 -05:00
Rob Herley a3053b5cc2 fix typo 2023-12-05 18:47:37 +00:00
Rob Herley b9872153b8 update GHES warning behavior 2023-12-05 18:42:36 +00:00
Rob Herley ce9eae0785 consistent promise behavior for download artifact 2023-12-05 18:35:26 +00:00
Rob Herley d3c5f358d1 consistent promise behavior for get artifact 2023-12-05 17:56:18 +00:00
Rob Herley 75a3586061 consistent promise behavior for upload artifact 2023-12-05 17:35:46 +00:00
Rob Herley 8ac8bf1d3d Merge pull request #1592 from actions/robherley/get-list-artifact-updates
Additional get/list artifact updates
2023-12-04 12:40:59 -05:00
Rob Herley 141b3509e4 update import 2023-12-03 21:13:55 +00:00
Rob Herley 790e6f7194 more docs 2023-12-03 20:52:36 +00:00
Rob Herley ef454f0991 add tests for list-artifacts 2023-12-03 20:48:33 +00:00
Rob Herley 86ce0b159a get artifact tests 2023-12-03 19:43:37 +00:00
Rob Herley c11a7cdeac wip 2023-12-03 06:24:49 +00:00
Rob Herley c94ca49c9c ability to filter artifacts by latest 2023-12-03 05:01:20 +00:00
Rob Herley fa7657714a fix import 2023-12-02 21:34:07 -05:00
Rob Herley c1f9d37323 updates to get/list artifacts 2023-12-02 21:18:22 -05:00
Rob Herley 8f1c589e25 Merge pull request #1591 from actions/robherley/artifact-internal-apis
Implement internal APIs for list/get/download artifacts
2023-12-01 16:17:26 -05:00
Rob Herley 281697ecbe fix test expectations 2023-12-01 16:34:27 +00:00
Rob Herley a59f976dd4 minor fixes 2023-12-01 09:05:46 -05:00
Rob Herley 57db7a6302 more debug info 2023-12-01 03:04:10 +00:00
Rob Herley 4789a46578 make FindOptions interface more user friendly 2023-12-01 02:15:25 +00:00
Rob Herley 32549e8197 update download-artifact tests for public and internal impl 2023-12-01 01:32:45 +00:00
Rob Herley 22b7aeb707 some test updates 2023-12-01 00:31:27 +00:00
Rob Herley e9d6649a14 consume new pb wrappers 2023-11-30 19:10:07 +00:00
Rob Herley 695bf98f84 rewrite artifacts client to have public and internal implementations 2023-11-30 03:47:04 +00:00
Tingluo Huang 0787a93181 Merge pull request #1588 from sshmaxime/main
Add RUN_ATTEMPT to `@actions/github` Context class
2023-11-28 10:43:43 -05:00
Maxime Aubanel faa425440f Add RUN_ATTEMPT to Github context 2023-11-28 16:32:10 +01:00
Rob Herley 0407266511 Merge pull request #1584 from actions/robherley/upload-v4-improvements
Increase Artifact v4 upload speed
2023-11-20 16:30:50 -05:00
Rob Herley a920781ca9 fix results url construction 2023-11-20 18:06:44 +00:00
Rob Herley 9e7201ff5b audit fix 2023-11-20 16:51:13 +00:00
Rob Herley 3a610e848c linter 2023-11-20 16:46:08 +00:00
Rob Herley 606ebdcf6d extra log line for debug 2023-11-20 16:27:35 +00:00
Rob Herley 7b01731091 increase upload concurrency based on cpus, adjust highWaterMark, specify compression level 2023-11-20 15:03:58 +00:00
Nikolai Laevskii 20f826bfe7 Add platform info utilities to @actions/core (#1551)
* Introduce platform utilities into @actions/core

* Add tests for the platform helper

* Update README.md

* Update README.md with more details
2023-11-14 14:15:26 -05:00
Rob Herley fe3e7ce9a7 Merge pull request #1563 from actions/robherley/artifact-v4/sha256
Use sha256 instead of md5 for artifact v4 integrity hash
2023-10-16 13:31:00 -04:00
Rob Herley 8cd02dfabc audit fix 2023-10-16 16:27:26 +00:00
Rob Herley 82474125c8 use sha256 instead of md5 for artifact v4 integrity hash 2023-10-16 16:20:24 +00:00
Tatyana Kostromskaya 494f12bcd9 Update dependencies in github package (#1553)
* Update octokit package

* define type for function

* fix linter

* Update github package to latest

* Update RELEASES.md
2023-10-10 16:04:42 +02:00
Tatyana Kostromskaya 797f48fcfa Update release notes for http-client@2.2.0 (#1549) 2023-10-06 16:03:00 +02:00
Tatyana Kostromskaya c8d1588732 Merge pull request #1547 from actions/takost/update-http-client
Add function to return proxy agent dispatcher for compatibility with latest `octokit` packages
2023-10-06 14:47:16 +02:00
Tatyana Kostromskaya 13e0ce9cf7 resolve comments 2023-10-06 12:39:29 +00:00
Tatyana Kostromskaya eae1b66cb0 fix audit 2023-10-05 16:41:02 +02:00
Tatyana Kostromskaya 129f884271 fix format 2023-10-05 16:34:31 +02:00
Tatyana Kostromskaya 0faced6a0b Add function to return proxy agent dispatcher for compatibility with latest octokit 2023-10-05 16:20:26 +02:00
Patrick Ellis 0d63834474 Merge pull request #1541 from actions/pje/upgrade-codeql-actions-to-v2
Upgrade codeql actions to v2
2023-09-27 16:14:48 -04:00
Patrick Ellis 8f032d304a Upgrade codeql actions to v2
Currently we're using v1, and there have been some important changes since then.

In particular, the latest version, v2.14.6, contains an important security patch:

> The CodeQL CLI no longer supports the `SEMMLE_JAVA_ARGS` environment variable. All previous versions of the CodeQL CLI perform command substitution on the `SEMMLE_JAVA_ARGS` value (for example, replacing `'$(echo foo)'` with `'foo'`) when starting a new Java virtual machine, which, depending on the execution environment, may have security implications. Users are advised to check their environments for possible `SEMMLE_JAVA_ARGS` misuse.

See the [codeql-cli-binaries release notes](https://github.com/github/codeql-cli-binaries/releases/tag/v2.14.4) for full details.
2023-09-27 15:18:59 -04:00
Tatyana Kostromskaya 28b09e224f Merge pull request #1526 from actions/takost/upd-dependencies
Update dependencies to latest
2023-09-27 12:37:10 +02:00
Tatyana Kostromskaya 111c95866e fix test + update semver 2023-09-26 11:10:18 +00:00
Tatyana Kostromskaya ddc9c52eb6 revert octokit changes 2023-09-26 11:05:37 +00:00
Tatyana Kostromskaya 6d37c6eb2b try to fix tests 2023-09-15 15:04:21 +00:00
Tatyana Kostromskaya 6477ef1460 tests 2023-09-15 13:54:28 +00:00
Tatyana Kostromskaya 2e5b10e3bd fix tests 2023-09-15 13:45:26 +00:00
Tatyana Kostromskaya 8c1e6a00f0 try to fix test 2023-09-15 13:28:29 +00:00
Tatyana Kostromskaya b2d5fa216f update github package 2023-09-14 14:32:08 +00:00
Luke Tomlinson c5c786523e @actions/core v1.10.1 (#1529) 2023-09-11 10:45:23 -04:00
Sean Burgess 63c648f3c2 Fix error message reference (#1511) 2023-09-11 10:25:17 -04:00
Tatyana Kostromskaya ce31408ff5 Update dependencies 2023-09-08 14:29:27 +00:00
Tatyana Kostromskaya e26febd988 Merge pull request #1508 from actions/takost/update-workflows-to-node20
Update workflows to node20
2023-09-01 11:55:53 +02:00
Tatyana Kostromskaya b051b4bada . 2023-08-29 14:56:32 +00:00
Tatyana Kostromskaya a08d666c78 . 2023-08-29 14:23:58 +00:00
Tatyana Kostromskaya 83bb7cdeef . 2023-08-29 14:09:20 +00:00
Tatyana Kostromskaya b552972717 revert 2023-08-29 11:19:06 +00:00
Tatyana Kostromskaya e3b0601228 test 2023-08-29 10:43:51 +00:00
Tatyana Kostromskaya 0956e634df test 2023-08-29 10:27:11 +00:00
Tatyana Kostromskaya c171cf52fb upd 2023-08-28 17:09:50 +02:00
Tatyana Kostromskaya 2f1b34f165 test tests 2023-08-28 16:59:29 +02:00
Tatyana Kostromskaya b61854c5ca update workflows to node20 2023-08-28 16:40:06 +02:00
Bethany 3d652d3133 Merge pull request #1505 from actions/bethanyj28/upload-tests
Add tests for `upload-artifact.ts`
2023-08-24 09:29:01 -04:00
Rob Herley c3df0928e2 Merge pull request #1502 from actions/robherley/download-artifact
[Artifacts] Support streaming download of artifact archive from blob storage
2023-08-24 09:27:27 -04:00
Rob Herley 9d756b2bc9 linter 2023-08-24 09:16:35 -04:00
Rob Herley 67c3b7a45c add tests for download artifact 2023-08-23 23:18:03 -04:00
Bethany 3963c722d8 merge download changes and lint 2023-08-23 14:02:50 -07:00
Bethany 3b44a4cc23 prettier 2023-08-23 13:55:26 -07:00
Bethany 03a876f0a7 add tests for upload 2023-08-23 13:54:31 -07:00
Bethany 62f943c0cc Merge pull request #1503 from actions/bethanyj28/download-artifact
Get a single artifact by name and download to `GITHUB_WORKSPACE`
2023-08-23 14:11:06 -04:00
Bethany 291200d54f include get artifact changes 2023-08-23 10:40:25 -07:00
Bethany 06e751600e move constants to retry-options 2023-08-23 10:36:33 -07:00
Bethany 4b6a4d80e1 use inline eslint disable 2023-08-23 10:12:06 -07:00
Bethany b2da9aa12c use string interpolation 2023-08-23 07:35:23 -07:00
Bethany 88f749f686 lint 2023-08-23 07:28:17 -07:00
Bethany b4f8e602b2 remove folder option in favor of path 2023-08-23 07:21:01 -07:00
Bethany ced07aa89c Use options to specify download folder 2023-08-23 06:47:51 -07:00
Bethany 6adf053d36 prettier 2023-08-22 11:47:14 -07:00
Bethany 671bf1ebd5 use GITHUB_WORKSPACE as default download dir 2023-08-22 11:44:38 -07:00
Bethany dd26bb1149 use require 2023-08-22 11:33:00 -07:00
Bethany 81a802e7e0 lint 2023-08-22 10:06:40 -07:00
Bethany 4214a1ff24 update dependencies and prettier 2023-08-22 09:57:14 -07:00
Bethany 0555a5f458 add get-artifact logic 2023-08-22 09:17:43 -07:00
Rob Herley 3aaff6685b cleanup 2023-08-21 17:47:17 -04:00
Rob Herley 9b383229c1 add download apis to stream zip from blob storage 2023-08-21 21:23:54 +00:00
Konrad Pabjan 7b617c260d [Artifacts] @actions/artifact list artifact functionality + download interface setup (#1495)
* actions/artifact preparation for download-artifact v4

* Test matrix strategy

* Fix needs dependency

* Improve list artifact test

* Fix typo

* Fix variables

* Cleanup download-all interfaces

* Fix tsc error

* Simplify to just name instead of artifactName

* Simplify to id instead of ArtifactId

* PR cleanup
2023-08-17 14:40:33 -04:00
Konrad Pabjan 20afb1a9fc [Artifacts] Add tests for E2E artifact upload (#1497)
* Add tests for E2E artifact upload

* Trigger Build

* Extra debug logs

* Debug dumping GitHub Context

* More logging

* Minor cleanup

* Trigger Build

* Unique artifact name

* Fix typo

* Fix

* Try using github-script

* Potential fix

* Cleanup

* More cleanup
2023-08-17 12:32:55 -04:00
Konrad Pabjan c9dab8c79d [Artifacts] Save md5 hash for each artifact upload (#1494)
* Hash artifact upload using md5

* Add imports

* Small tweaks

* PR feedback

* PR Feedback
2023-08-15 13:39:57 -04:00
Konrad Pabjan 45c49b09df [Artifacts] zip creation + blob storage upload functionality (#1488)
* Artifact zip creation + blob storage upload functionality

* Fix lint

* PR feedback
2023-08-10 15:28:41 -04:00
Bethany ab78839e86 Merge pull request #1487 from actions/bethanyj28/add-artifact-api-logic
Utilize client to create and finalize artifact
2023-08-10 10:19:24 -04:00
Bethany f03b6d639f update import 2023-08-09 17:50:46 -07:00
Bethany 58858b5078 don't use non-null assertions 2023-08-09 17:48:53 -07:00
Bethany 188abfc20b implement feedback 2023-08-09 17:42:14 -07:00
Bethany 2f42c127c7 update tests 2023-08-09 13:20:06 -07:00
Bethany 4dda3ab8a0 move getExpiration to upload-artifact 2023-08-09 13:12:30 -07:00
Bethany 4b219f79f3 Add tests for backend id fetch 2023-08-09 12:29:43 -07:00
Bethany 08d6314f7c prettier 2023-08-09 12:09:17 -07:00
Bethany b851b70474 catch errors at the root, remove unneccessary disabled rule 2023-08-09 12:08:43 -07:00
Bethany e8fb71c4bb lint 2023-08-09 11:34:18 -07:00
Bethany 73ad88882e utilize client, fetch IDs 2023-08-09 11:26:33 -07:00
Bethany 92695f58da Merge pull request #1486 from actions/bethanyj28/add-twirp-client
Add twirp client
2023-08-09 10:46:24 -04:00
Bethany 760f3fd3d1 Update packages/artifact/src/internal/shared/config.ts
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2023-08-09 10:30:50 -04:00
Bethany c6117995d3 Update packages/artifact/src/internal/shared/config.ts
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2023-08-09 10:30:44 -04:00
Bethany 24da3e2d1c lint 2023-08-09 07:10:43 -07:00
Bethany deda97d5e6 don't add extra line breaks 2023-08-09 07:02:06 -07:00
Bethany cfad1451e9 Update generated files to not use bigint 2023-08-09 07:00:27 -07:00
Bethany c0684c5add prettier 2023-08-08 13:19:43 -07:00
Bethany ad9b955fe9 remove unused package 2023-08-08 12:51:54 -07:00
Bethany 1718e0d97c revert target to es6 2023-08-08 12:49:45 -07:00
Bethany e85cd96d85 tests and fix bug for retry 2023-08-08 12:49:05 -07:00
Bethany bc24adbfd6 Merge pull request #1481 from actions/bethanyj28/add-twirp-definitions
[Artifacts] Add artifact Twirp API definitions
2023-08-08 10:36:34 -04:00
Bethany af1621025d wip 2023-08-07 16:26:07 -07:00
Bethany 6552cb9722 wip 2023-08-07 14:24:58 -07:00
Chad Kimes f74ff155bd Add option for concurrent cache downloads with timeout (#1484)
* Add option for concurrent cache downloads with timeout

* Add release notes

* Fix lint
2023-08-07 13:25:56 -04:00
Bethany a66e49ec8a Merge branch 'bethanyj28/add-twirp-definitions' into bethanyj28/add-twirp-client 2023-08-07 09:10:06 -07:00
Bethany d4c2fa4c68 add generated to eslintignore 2023-08-07 09:01:14 -07:00
Bethany 8c9ab93da7 Merge remote-tracking branch 'origin' into bethanyj28/add-twirp-definitions 2023-08-07 08:56:08 -07:00
Bethany 3773ef22b1 prettier and add generated files to prettierignore 2023-08-07 08:55:42 -07:00
Bethany 80e4680ac8 Merge branch 'bethanyj28/add-twirp-definitions' into bethanyj28/add-twirp-client 2023-08-07 08:48:20 -07:00
Bethany c608703ecf revert root tsconfig.json 2023-08-07 08:48:15 -07:00
Bethany 66ac937f2f target es2020 2023-08-07 08:45:28 -07:00
Bethany efcab31d38 pass in http client to constructor 2023-08-07 08:43:39 -07:00
Bethany 4c6d88f93a Start writing tests 2023-08-04 13:00:58 -07:00
Chad Kimes 19e0016878 actions/http-client 2.1.1 release (#1483) 2023-08-04 15:00:50 -04:00
Chad Kimes 2820b17d9d Add readBodyBuffer method to HttpClientResponse (#1475)
* Add readBodyBuffer method to HttpClientResponse

* Implement method in other package tests

* Make method optional to satisfy the test process
2023-08-04 14:35:26 -04:00
Bethany 8a5343d54a add twirp client 2023-08-04 09:23:14 -07:00
Bethany 3ebee1e8b4 package-lock.json conflict 2023-08-04 07:12:36 -07:00
Konrad Pabjan 7da3ac6eda [Artifacts] Name validation + zip specification creation (#1482)
* Artifact name validation + zip specification creation

* Fix linting issues

* Grammar fix

* Update test description
2023-08-04 09:53:42 -04:00
Vallie Joseph 2461056696 Audit Fix (#1480)
* fixing audit failures

* replacing lerna bootstrap with npm command

* audit fix for cache and tool-cache

* updating tunnel

* upgrading core packages

* re-adding tunnel as prod dep

* updating dependencies

* updating exec deps

* updating exec io package

* .

* Revert

* updating packages

* adding core as dep

* updating learna config

* updating lerna commands

* Removing audit failing packages in cache + tool-cache

* updating contribution bootstrap description

* updating libraries

* prettier lint

* hiding stricter rules

* updating prettier command

* Removing unknown flag

* Adding eslint prettier

* ignoring sym links

* updating ignore path

* updating prettier rules

* changing prettier + github ver

* updating ts and ignores

* Revert ts

* Adding unknown ignores

* downgrading lerna

* .

* adding nx

* Adding lint auto lint rules

* updating eslint ignore for glob packages

* Adding subdirs to ignore

* adding flag for ignore pattern in linter

* Expanding ignore regex

* Adding ignore rules

* adding another ignore pattern to tsconfig eslint

* adding ignore pattern to eslintrc

* syncing package-json

* updating traverse

* .

* test adding core and http client to base package

* running npm ci

* adding tsconfig paths

* adding base URL

* Adding explicit path to core and http-client

* editing tsc call

* updating artifact packages

* force build

* updating lock file version

* updating lock file version

* upgrading node version

* Adding babel traverse back

* fixing build issue

* fixing typescript ver

* updating package json

* Adding ignore for artifact test

* adding ignore to flags

* unlink after test completes

* cleanup

* merge + package edit
2023-08-03 16:36:11 -04:00
Bethany 3749c51d21 npm install 2023-08-03 12:59:51 -07:00
Bethany 769c896931 add artifact api twirp definitions 2023-08-03 12:43:45 -07:00
Konrad Pabjan c4f5ce2665 [Artifacts] Prepare for v2.0.0 of @actions/artifact (#1479)
* Prepare for v2.0.0 of @actions/artifact

* Run prettier

* temporary disable unused vars
2023-08-03 13:34:41 -04:00
Ferenc Hammerl 91d3933eb5 Prepend http:// to http(s)_proxy env if missing (#1439)
* Prepend http:// to http(s)_proxy env if missing

* Formatting

* Fix linting
2023-06-22 11:03:38 +02:00
Francesco Renzi a6bf8726aa Merge pull request #1430 from actions/add-mask-docs
Update docs for setSecret
2023-05-25 11:17:42 +01:00
Francesco Renzi ae9272d5cb Update docs/commands.md
Co-authored-by: JoannaaKL <joannaakl@github.com>
2023-05-25 11:07:37 +01:00
Francesco Renzi f481b8c8dc Update docs for setSecret 2023-05-25 11:00:25 +01:00
Francesco Renzi 59851786d4 Add tests to ensure secrets are escaped 2023-05-25 10:59:41 +01:00
Francesco Renzi 37e09c586f Merge pull request #1429 from actions/rentziass/postman
Use postman-echo to replace httpbin
2023-05-23 13:22:40 +01:00
Francesco Renzi 12c01ac203 Merge pull request #1428 from actions/rentziass/audit-fix
Update actions/cache dependencies to fix vulnerabilities
2023-05-23 13:20:12 +01:00
Francesco Renzi bbab4bec57 Update packages/http-client/__tests__/proxy.test.ts
Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com>
2023-05-23 13:10:40 +01:00
Francesco Renzi 672c88ec4b Use postman-echo to replace httpbin 2023-05-23 12:37:39 +01:00
Francesco Renzi a103f5eefe Update actions/cache dependencies to fix vulnerabilities 2023-05-22 14:32:33 +01:00
Vallie Joseph 457303960f toolkit/io 1.1.3 release (#1374)
* updating version

* adding new minor version to package-lock

* updating release doc

* Update packages/io/RELEASES.md

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

---------

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2023-03-15 15:10:56 -04:00
Vallie Joseph 463b49d872 Removing childprocess for rmRF (#1373)
* try awaiting spawn on windows

* formatting

* updating package-lock

* .

* .

* updating packages

* adding sync rm

* test with sync

* pointing to rmsync

* adding error handling

* testing rmsync

* adding try/catch

* adding windows conditional for locked file

* switch to contians

* fixing formatting

* fixing formatting

* fixing formatting

* adding enonet catch for windows files

* adding enonet catch for windows files

* adding catch for file not found

* updating stat call

* updating stat call

* adding conditonal for symlink

* removing symlink test

* adding ebusy check

* changing error check

* changing error check

* changing error check

* changing error check

* cleanup and comments

* Update packages/io/__tests__/io.test.ts

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

* Update packages/io/src/io-util.ts

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

* moving comment placement

* updating eperm

* change back to ebusy

* Update packages/io/__tests__/io.test.ts

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

* Formatting

* converting to async

---------

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2023-03-15 14:51:02 -04:00
Sankalp Kotewar a91ee0b497 Merge pull request #1367 from actions/kotewar/update-readme
Update README for latest cache release changes
2023-03-09 16:36:44 +05:30
Sankalp Kotewar 94e340bfb1 Update README.md 2023-03-09 16:24:15 +05:30
Sankalp Kotewar 599c6164e8 Update README.md 2023-03-09 16:23:41 +05:30
Sankalp Kotewar b8261b0fb0 Update README.md 2023-03-09 16:21:20 +05:30
Sankalp Kotewar aeb16eeca1 Merge pull request #1363 from actions/kotewar/updating-blobstorage-client-to-12.13.0
Updating blob storage client to 12.13.0 in actions/cache
2023-03-09 16:01:52 +05:30
Sankalp Kotewar 7a11743b35 Fixed typo 2023-03-08 19:14:15 +00:00
Sankalp Kotewar fe92749762 Merge branch 'main' into kotewar/updating-blobstorage-client-to-12.13.0 2023-03-09 00:33:52 +05:30
Sankalp Kotewar 0e8edb0780 Merge pull request #1286 from cdce8p/cache-dry-run
Add cache restore `lookupOnly` option
2023-03-08 17:45:20 +05:30
Sankalp Kotewar 7d1daaf15e Fixed test case 2023-03-08 09:26:29 +00:00
Sankalp Kotewar 40ec298d4b updated segment timeout to 10 mins 2023-03-08 07:28:50 +00:00
Ferenc Hammerl 787b2cf270 Bump http-client to version 2.1.0 (#1364)
* Update package.json

* Update package.json

* Update RELEASES.md
2023-03-06 17:03:09 +01:00
Sankalp Kotewar 8e32b1fca3 updated version prefix to caret for ts dep 2023-03-06 13:38:19 +00:00
Sankalp Kotewar d9a2c5a9f9 updated comment with more info 2023-03-06 13:20:45 +00:00
Sankalp Kotewar e6e7b6156f updated segment size to 128MB for failing fast 2023-03-06 13:11:54 +00:00
Sankalp Kotewar f3de1e53d6 updated version 2023-03-06 12:36:29 +00:00
Sankalp Kotewar 703d5ac24a fixed lockfile 2023-03-06 12:22:47 +00:00
Sankalp Kotewar 97f21173cc upgraded typescript version
Upgrade ts version to support latest azure sdk
2023-03-06 12:18:32 +00:00
Sankalp Kotewar ce1bf116fc formatted and updated releases file 2023-03-06 11:56:51 +00:00
Sankalp Kotewar 9ba9ae31a9 updated azure storage blob to 12.13.0 2023-03-06 11:55:21 +00:00
Ferenc Hammerl 94ab8de5f3 Bypass proxy on loopback IPs (localhost, 127.*, ::1 etc) (#1361)
* Bypass proxy on loopback IPs

* Expect empty array instead of undefined

* Restore accidentally deleted test

* Fix formatting

* Fix linting

* Update proxy.ts

* Better ipv6 definitions

* Fix linting

* Update proxy.test.ts
2023-03-06 11:07:04 +01:00
Ferenc Hammerl d47e0bac60 Support '*' wildcard (#1355) 2023-03-06 11:02:29 +01:00
Ferenc Hammerl 1f4b3fac06 Revert "Bypass proxy on loopback IPs"
This reverts commit 8d92c9c903.
2023-03-01 13:48:44 +00:00
Ferenc Hammerl 8d92c9c903 Bypass proxy on loopback IPs 2023-03-01 13:45:12 +00:00
Marc Mueller e45a26f771 Update package version and changelog 2023-02-21 13:56:25 +01:00
Marc Mueller a3849b77ae Rename option to lookupOnly 2023-02-21 12:37:48 +01:00
Marc Mueller eb06c21794 Add cache restore dryRun option 2023-02-21 12:37:48 +01:00
Lovepreet Singh 0db3029fcf Merge pull request #1353 from actions/pdotl/zstd-version-fix
Hotfix Zstd breaking due to version change in runners
2023-02-21 00:50:51 +05:30
Lovepreet Singh e6e29846f2 Add debug statement for exact zstd version value and remove dependence on version for now 2023-02-20 19:13:38 +00:00
Lovepreet Singh 7c15bf6f40 Fix failing windows test 2023-02-20 18:50:26 +00:00
Lovepreet Singh bc713ab90d Add release info 2023-02-20 18:38:47 +00:00
Lovepreet Singh a9d266bb7c Fix lint issues 2023-02-20 15:26:04 +00:00
Lovepreet Singh cf3dd065b8 Add default value and rename args 2023-02-20 14:59:12 +00:00
Lovepreet Singh 6ec51745ad Update debug statement to include latest command 2023-02-20 14:23:53 +00:00
Lovepreet Singh 0f91c9c203 Bump version using npm 2023-02-20 13:53:17 +00:00
Lovepreet Singh e18b2d8a33 0.0.1 2023-02-20 13:43:31 +00:00
Lovepreet Singh 4fd425926c Fix version number 2023-02-20 13:43:24 +00:00
Lovepreet Singh 83dffb7746 Fix lint issues 2023-02-20 13:33:16 +00:00
Lovepreet Singh 1d1d5456e3 Removed code that checks for version less than 1.3.2 as it was not working. Defaulting to zstd without long as that is what is always happening currently. 2023-02-20 13:27:45 +00:00
Lovepreet Singh 9e06993ffc Hotfix zstd version change only 2023-02-20 13:08:22 +00:00
Lovepreet Singh 3630ea6eed Fix bug with version shortcircuiting because of version being null 2023-02-20 12:51:49 +00:00
Lovepreet Singh c2d3089f83 bump version 2023-02-20 10:32:34 +00:00
Lovepreet Singh 652109d32c Test passing quiet as argument 2023-02-20 10:30:41 +00:00
Lovepreet Singh f2aa430c9d Add debug statements 2023-02-20 10:05:34 +00:00
Felix Luthman d2b7d85e7c Standardize behaviour of no_proxy environmental variable (#1223)
* match no_proxy to subdomains

* strip leading dot + '*' match all + testcases

* Update proxy.test.ts

* Revert "Update proxy.test.ts"

This reverts commit 0e925a6dc5.

* remove support for leading dots and wildcard no_proxy

* change order of tests for logic consistency

* add test for working leading dot

* add check for partial domain, as opposed to subdomain
2023-02-13 15:00:05 +01:00
Ferenc Hammerl 409d616a6e Merge pull request #1333 from actions/dependabot/npm_and_yarn/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1
2023-02-09 13:40:44 +01:00
Sampark Sharma e3c2a88bbf Release patch version update for cache (#1338) 2023-02-09 17:21:19 +05:30
Christoph Reiter ea21da6993 Don't set the MSYS env var globally (#1329)
b2d865f180 introduced a call to exportVariable() to export the MSYS env
var, which configures the symlink strategy for MSYS2/cygwin binaries it calls.

By setting the env var globally, this also changes the behaviour of other MSYS2
using tools in a CI job, and also overrides MSYS configuration set by the user,
which I think was not intended.

To avoid this leakage set the MSYS env var only for the commands which
@actions/cache calls.

Fixes #1312
2023-02-08 10:58:25 +05:30
dependabot[bot] c6005c2a3c Bump http-cache-semantics from 4.1.0 to 4.1.1
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-03 04:52:15 +00:00
John Sudol 1589a5c066 Update @actions/glob to 0.4.0 (#1321) 2023-01-25 09:23:29 -05:00
John Sudol d3801d332c Pass in the directory for hashFiles (#1318) 2023-01-24 14:12:47 -05:00
Josh Soref 5804607845 Grammar: set up (#1241) 2023-01-19 10:57:29 -05:00
Ferenc Hammerl c26f803662 Merge pull request #1300 from actions/fhammerl/setup-node-latest
Use newest version of actions
2023-01-19 16:16:02 +01:00
Héctor Molinero Fernández 6c1f9eaae8 [Artifacts] Add more extensions to the gzip compression exception list (#1118)
* [Artifacts] Add more extensions to the gzip compression exception list

* [Artifacts] Test .zip extension

* Exempt .zstd files from compression
2023-01-11 15:19:28 -05:00
Konrad Pabjan 412417d0b0 Document notice command
Ported over from https://github.com/actions/toolkit/pull/1105 which was merged into master instead of main
2023-01-11 14:18:20 -05:00
Rob Cowsill 71a6fceb8c core: Update "core.error" documentation (#905)
Change the `core.error` documentation to say that it won't automatically
fail the action. This matches the existing example in the "logging" section
2023-01-11 14:12:52 -05:00
Konrad Pabjan 34577b269e Remove error annotations why retrying artifact download (#1309) 2023-01-11 13:53:41 -05:00
Eric Cornelissen 06c3c38ef2 Fix reject call in package artifact's upload-zip.ts (#1125) 2023-01-06 10:15:36 -05:00
Ramiro Antonio 03d6c2479c Fix typo in AnnotationProperties doc (#1114) 2023-01-06 10:10:33 -05:00
Randolf J 411e8fa448 fix: use stat instead of lstat (#1190) 2023-01-06 10:07:56 -05:00
Luca Casonato 2c09aaef3b [artifact] exempt .tar.zst files from compression (#1184)
* [artifact] exempt .tar.zst files from compression

These files are already compressed with zstd - no need to attempt re-compression.

* fix missing comma

* fmt

* Update upload-gzip.ts
2023-01-05 16:00:03 -05:00
Sampark Sharma b2d865f180 Cache package release for compression change in windows with symlink fix (#1291)
* Cache package release for compression change in windows

This reverts commit 86fe4abd8e.

* Add env variable to enable windows symlinks

* Add cross os opt-in functionality for cache on windows

* Fix test

* Address review comments

* Fix test

* Fix tests

* Fix tests

* Fix tests

* Address review comments

* Address review comments

* Fix tests

* Fix tests

* Add npm version

* Add release details
2023-01-04 12:16:25 +05:30
Ferenc Hammerl 56146a6713 Bump actions to newer versions 2023-01-03 16:59:01 +01:00
Ferenc Hammerl 74f24b41d1 Use most recent setup-node 2023-01-03 16:43:09 +01:00
Ferenc Hammerl c0b323a0bb Merge pull request #1298 from actions/fhammerl/artifact-release-1-1-1
Artifact release 1.1.1
2023-01-03 15:52:36 +01:00
Ferenc Hammerl 83db1b8e43 Bump artifact package 2023-01-03 15:19:24 +01:00
Ferenc Hammerl 5b2351aebf Release notes for 1.1.1 2023-01-03 15:19:16 +01:00
Ferenc Hammerl f5024e4e97 Merge pull request #1278 from actions/fhammerl/node-v16-and-toolkit-fixes
Migrate dev environment and workflows to node16
2023-01-03 14:02:07 +01:00
Ferenc Hammerl 4ea08312c6 Fix json5 vuln 2023-01-03 13:37:01 +01:00
Ferenc Hammerl 5e9bcaca7c Update title with hint 2023-01-03 13:36:38 +01:00
Ferenc Hammerl af2d2ff198 Remove allow-list from audit
Releases can be made or PRs can be merged even if the workflow is failing
2023-01-03 13:34:55 +01:00
Ferenc Hammerl 3d46598e70 Add disabling explanation in audit-allow-list 2023-01-03 13:33:43 +01:00
Ferenc Hammerl 894a0490f9 Merge branch 'main' of https://github.com/actions/toolkit into fhammerl/node-v16-and-toolkit-fixes 2023-01-03 11:58:29 +01:00
Sampark Sharma 86fe4abd8e Revert "Cache package release for compression change in windows" (#1289)
* Revert "Cache package release for compression change in windows (#1281)"

This reverts commit b228732644.

* Update release version to patch
2022-12-27 16:00:28 +05:30
Sampark Sharma b228732644 Cache package release for compression change in windows (#1281)
* bsd + zstd fallback implementation

* bsd + zstd fallback implementation

* Fix tar operations

* Add -v option for testing

* Fix order of args for tar

* Add GNUtar as default on windows

* Fix test

* Fix tar tests

* Fix lint issues

* Fix windows gnutar test case

* Temporarily remove thhe condition that prevents zstd usage on windows unless with GNUtar

* Address some comments and correct compression commands

* Add windows bsdtar test

* Fix windows test

* Fix test

* Separate args

* Fix old tests

* Add new tests

* Fix tests

* Fix lint test

* Refactor code

* Address review comments

* Fix test

* Fix tar test

* Add await to async function calls

* Fix test

* Update for beta release

* Fix audit issues

* Add fallback to gzip compression if cache not found

* Fix test

* Add test

* Address review comments

* Revert Address review comments

* Release 3.1.0-beta.2 cache package

* Fix issues

* Reconfigure catch block

* Add debug logging for gzip fall back

* Fix test

* Add end to end test for cache using bsd on windows
and address review comments

* Fix test

* Fix test

* Fix tests

* Add better comments

* Update packages/cache/src/internal/cacheHttpClient.ts

Co-authored-by: Bishal Prasad <bishal-pdmsft@github.com>

* Address review comments

* Update for new beta cache package release

* Address bugbash issues

* Fix tests

* Release new actions/cache minor version

Co-authored-by: Lovepreet Singh <pdotl@github.com>
Co-authored-by: Bishal Prasad <bishal-pdmsft@github.com>
2022-12-22 20:47:35 +05:30
Sampark Sharma 2a4f3544ad Merge pull request #1234 from actions/phantsure/version-logging
Add logs for cache version on miss
2022-12-22 11:48:58 +05:30
Sampark Sharma c23fe4b81f FIx test 2022-12-21 10:30:22 +00:00
Sampark Sharma 034d154f88 Merge branch 'phantsure/version-logging' of https://github.com/actions/toolkit into phantsure/version-logging 2022-12-21 10:27:13 +00:00
Sampark Sharma ccfa36f304 Address review comments 2022-12-21 10:24:52 +00:00
Ferenc Hammerl 2afea665ed Try sequential jest tests 2022-12-20 16:32:59 +01:00
Sampark Sharma e96dc8a69a Update packages/cache/src/internal/cacheHttpClient.ts
Co-authored-by: Bishal Prasad <bishal-pdmsft@github.com>
2022-12-16 18:17:37 +05:30
Sampark Sharma b8c50aa82d Fix response code 2022-12-16 05:55:53 +00:00
Sampark Sharma 24685611e2 Add current scope from github ref 2022-12-16 05:54:48 +00:00
Ferenc Hammerl 80d992795c Fix linting 2022-12-14 16:13:28 +01:00
Ferenc Hammerl b9de68a590 Await finish of filestream so file is created for node16 2022-12-14 15:57:48 +01:00
Ferenc Hammerl 1d61e5fb19 Fix linting 2022-12-14 01:38:01 +01:00
Ferenc Hammerl 4abb5a2ae0 Quote workflows for windows 2022-12-14 01:30:49 +01:00
Ferenc Hammerl 6b18932b86 Fix missing typescript casts 2022-12-14 01:28:46 +01:00
Ferenc Hammerl 56c460630a Fix audit 2022-12-14 01:27:55 +01:00
Ferenc Hammerl e1a991ffb7 Run workflows on 16 2022-12-14 01:19:05 +01:00
Ferenc Hammerl cc9ec0424e Test out checking for fileexists in rmFile 2022-12-14 01:17:17 +01:00
Ferenc Hammerl c91bdbadbf Update ts types to node16 2022-12-14 01:13:46 +01:00
Ferenc Hammerl 23811ac52f Update nock to work with node 16 2022-12-13 18:21:57 +01:00
Sampark Sharma e559a15ca6 Fix test 2022-12-13 11:36:10 +00:00
Sampark Sharma 816c1b3760 Fix tests 2022-12-13 11:25:40 +00:00
Sampark Sharma 819157bf87 Merge pull request #1238 from actions/revert-1232-phantsure/gnutar_windows
Revert "Add GNUtar as default in windows"
2022-11-17 12:42:10 +05:30
Sampark Sharma 86102e88e9 Revert "Add GNUtar as default in windows" 2022-11-17 12:26:27 +05:30
Sampark Sharma e4c071ba19 Merge pull request #1232 from actions/phantsure/gnutar_windows
Add GNUtar as default in windows
2022-11-16 16:55:59 +05:30
Sampark Sharma b9d1dd898e Address review comments 2022-11-15 11:04:24 +00:00
Sampark Sharma aaac0e6c98 Address review comments 2022-11-15 10:32:24 +00:00
Sampark Sharma 9443e26349 Address review comments 2022-11-15 10:18:46 +00:00
Sampark Sharma 5a0405df4e Fix tests 2022-11-15 08:48:29 +00:00
Sampark Sharma 0e707aeabc Address comments 2022-11-15 08:41:04 +00:00
Sampark Sharma 7441dc5e59 Fix tests 2022-11-14 10:25:17 +00:00
Sampark Sharma 1ddac5e02f Fix tests 2022-11-14 10:11:46 +00:00
Sampark Sharma 55484166d8 Address review comments 2022-11-14 08:12:15 +00:00
Sampark Sharma 7181b913f5 Remove export 2022-11-14 06:34:18 +00:00
Sampark Sharma 81cd5a5c2e Revert "Add logs for cache version on miss"
This reverts commit 4b348086a9.
2022-11-14 06:33:53 +00:00
Sampark Sharma a735d9bcd4 Add logs for cache version on miss 2022-11-14 06:31:26 +00:00
Sampark Sharma 4b348086a9 Add logs for cache version on miss 2022-11-14 05:24:09 +00:00
Sampark Sharma 436cf8d6ea Fix tests 2022-11-10 15:50:06 +00:00
Sampark Sharma e0aadb573c Fix GNUtar path 2022-11-08 08:29:31 +00:00
Sampark Sharma 62a66a8ce9 Fix tests 2022-11-08 06:43:28 +00:00
Sampark Sharma 0c58e4113e Fix gnutar check on windows 2022-11-07 13:43:54 +00:00
Sampark Sharma 9366237c90 Add gnuTar as default in windows 2022-11-07 13:39:07 +00:00
Sankalp Kotewar b36e70495f Merge pull request #1217 from actions/kotewar/release-new-version
Upgraded actions/cache version to 3.0.6
2022-10-19 00:37:15 +05:30
Sankalp Kotewar 8423354d7d Update RELEASES.md 2022-10-18 23:14:31 +05:30
Sankalp Kotewar abcca5a0b2 Upgraded actions/cache version to 3.0.6 2022-10-18 22:56:17 +05:30
Sankalp Kotewar b2e1c39c92 Merge pull request #1215 from Kurt-von-Laven/abort-controller
Declare dependency on `@azure/abort-controller`
2022-10-18 22:30:56 +05:30
Sankalp Kotewar 8e8a93deae Fixed environment variable in the docs. (#1216) 2022-10-18 12:31:00 +05:30
Kurt von Laven 738c849e89 Declare dependency on @azure/abort-controller 2022-10-17 18:05:26 -07:00
Lovepreet Singh 9b58167dc9 Merge pull request #888 from martincostello/Fix-Docs
Fix endColumn documentation
2022-10-14 21:26:17 +05:30
Lovepreet Singh ffb7e3e14e Merge pull request #1206 from actions/pdotl-patch-1
Patch @actions/cache to use @action/core version 1.10.0
2022-10-13 15:39:35 +05:30
Lovepreet Singh ce378c4cec Fix package-lock.json 2022-10-13 09:45:52 +00:00
Lovepreet Singh 3e257b0745 Update RELEASES.md 2022-10-13 09:36:33 +00:00
Lovepreet Singh e5e4491ac5 Patch @actions/cache to use @action/core version 1.10.0 2022-10-13 08:21:23 +00:00
David Bloss 1bc93f3cdf fix README broken link to dep caching (#1202) 2022-10-12 11:45:29 +05:30
Luke Tomlinson 4fbc5c941a Update @actions/github to v5.1.1 (#1189) 2022-09-30 14:04:50 -04:00
Luke Tomlinson ac778acad2 Export default octokit options (#1188) 2022-09-30 12:17:19 -04:00
Francesco Renzi 192c26f865 Merge pull request #1187 from actions/core/1.10
@actions/core 1.10.0 release
2022-09-29 14:59:11 +01:00
Francesco Renzi 295cbcc4da @actions/core 1.10.0 release 2022-09-29 13:53:58 +00:00
Francesco Renzi b00a9fd033 Add save-state and set-output file commands (#1178) 2022-09-29 14:45:02 +01:00
Francesco Renzi 4df45177e4 Merge pull request #1185 from bicstone/bicstone/fix-getMultilineInput-trim
fix(core): `getMultilineInput` not trimming whitespace
2022-09-28 09:23:14 +01:00
Takanori Oishi 33f1d64363 fix: getMultilineInput trims whitespace 2022-09-28 12:54:12 +09:00
Luke Tomlinson ebe4ac336f @actions/github release version 5.1.0 (#1182) 2022-09-23 10:01:00 -04:00
Luke Tomlinson 94de2cf6d4 Add additionalPlugins parameter to getOctokit method (#1181)
* Add additionalPlugins parameter to getOctokit method

* Simplify getOctokit
2022-09-22 16:43:54 -04:00
Francesco Renzi 64c334f0e5 Merge pull request #1180 from actions/rentziass/allow-parse-url 2022-09-16 17:05:24 +01:00
Francesco Renzi e1bb04bace Update internal dependencies 2022-09-16 15:47:36 +00:00
Francesco Renzi 0388e62759 Add parse-url to audit allow list 2022-09-16 13:46:01 +00:00
Cory Miller e6257f1117 Merge pull request #1171 from philip-gai/patch-1
Update proxy-support.md
2022-09-10 10:09:49 -04:00
Philip Gai b7db7552c9 Update docs/proxy-support.md
Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2022-09-09 15:52:51 -05:00
Philip Gai 2c50af36e2 Update docs/proxy-support.md
Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2022-09-09 15:52:45 -05:00
Philip Gai aac665d186 Update proxy-support.md
Fix and update links
2022-09-05 00:59:03 -05:00
Lovepreet Singh bc4be50597 Merge pull request #1152 from actions/pdotl-zstd-win-patch
Fix zstd failing on windows when used with the gnu tar workaround
2022-08-18 19:01:00 +05:30
Lovepreet Singh 0982f1da89 Fix linting issues 2022-08-18 11:44:15 +00:00
Lovepreet Singh ed96e21792 Fix spread operator for getCompressionMethod 2022-08-18 11:22:13 +00:00
Lovepreet Singh 2ae31879b7 Merge remote-tracking branch 'refs/remotes/origin/pdotl-zstd-win-patch' into pdotl-zstd-win-patch 2022-08-18 11:17:36 +00:00
Lovepreet Singh 14d8f65f10 Remove unused constants 2022-08-18 11:10:41 +00:00
Lovepreet Singh f47a9aff5e Merge branch 'main' into pdotl-zstd-win-patch 2022-08-18 16:35:00 +05:30
Lovepreet Singh ce68daa10e Common getCompressionMethod for listTar and extractTar 2022-08-18 11:01:22 +00:00
Sankalp Kotewar a57a4fe011 Merge pull request #1155 from actions/kotewar/custom-cache-download-timeout
Added custom user inputted timeout
2022-08-18 14:59:59 +05:30
Sankalp Kotewar 6c9b023c1b Updated releases.md 2022-08-18 09:16:59 +00:00
Sankalp Kotewar 0be752bc46 Updated readme 2022-08-18 09:14:58 +00:00
Sankalp Kotewar 5c5e91f040 Updated Segment readme and version 2022-08-18 06:46:57 +00:00
Sankalp Kotewar 846a0af6ec corrected environment variable 2022-08-18 06:38:04 +00:00
Sankalp Kotewar 4b6b45fe18 Updated cache download to segment download 2022-08-18 05:32:49 +00:00
Lovepreet Singh 98a4069558 Fix failing test cases on windows 2022-08-17 08:33:23 +00:00
Lovepreet Singh 6e888c882e Fix linting 2022-08-17 07:47:49 +00:00
Sankalp Kotewar c202c38407 Added custom user inputted timeout 2022-08-16 04:14:27 +00:00
Lovepreet Singh d543359fab Bump internal package @actions/cache version to fix #888 and #891 in actions/cache repo 2022-08-13 18:46:24 +00:00
Lovepreet Singh 8bd9e29d3c Use zstd short flag version for win runners. Update comments to reflect the same. Fix --d to -d in comments. 2022-08-13 18:01:07 +00:00
Sankalp Kotewar 63c66cf07e Merge pull request #1151 from actions/kotewar/segment-download-bug-try-2
Updated release info for v3.0.3 for actions/cache
2022-08-11 13:08:14 +05:30
Sankalp Kotewar 556b1c57e7 Updated release info for v3.0.3 for actions/cache 2022-08-11 07:13:04 +00:00
Sankalp Kotewar a4276ac40f Merge pull request #1150 from actions/kotewar/segment-download-bug-try-2
Implemented custom promise as abortController isn't able to stop the workflow in real scenarios
2022-08-11 12:37:43 +05:30
Sankalp Kotewar c7340e91af Reverted to custom promise implementation 2022-08-11 04:43:43 +00:00
Sankalp Kotewar d714ea08d6 Merge pull request #1140 from actions/segment-download-timeout
Introducing timeout in segment download to avoid the download stuck problem
2022-08-09 16:18:25 +05:30
Sankalp Kotewar 3fd7f664a6 Merge remote-tracking branch 'origin/main' into segment-download-timeout 2022-08-09 10:38:08 +00:00
Thomas Boop 30995490f2 Update lerna dependency. (#1149)
* fix audit

* update linter
2022-08-08 14:39:23 -04:00
Cory Miller 4beda9cbc0 Merge pull request from GHSA-7r3h-m5j6-3q42
* use uuid as our multiline env delimiter

* remove extra fn

* Fix version

* also throw error if delimiter is found in name or value

* move delimiter and uuid to global var in test

* upgrade uuid to newest version

* remove spy variable

* Update packages/core/src/core.ts

Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>

* Update packages/core/src/core.ts

Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
2022-08-08 14:16:39 -04:00
Sankalp Kotewar ba462956ea Updated error message and null check 2022-08-08 13:22:11 +00:00
Sankalp Kotewar cf5d2b8fac Added formatting changes 2022-08-08 04:56:02 +00:00
Sankalp Kotewar f9d38b0015 Updated variable names 2022-08-08 04:48:36 +00:00
Sankalp Kotewar 23cfbb3484 Fixed linting issues 2022-08-05 11:43:31 +00:00
Sankalp Kotewar 83becb7900 Removed custom promise and used abort timeout 2022-08-05 11:09:23 +00:00
Sankalp Kotewar ef888588c1 Updated version and Releases.md 2022-08-05 07:20:59 +00:00
Sankalp Kotewar f05c04b173 Merge remote-tracking branch 'origin/main' into segment-download-timeout 2022-08-05 06:10:39 +00:00
Sankalp Kotewar 518f480528 Updated 45 mins abort timeout to 1 hour 2022-08-05 05:44:59 +00:00
Lovepreet Singh 90be12a59c Merge pull request #1144 from actions/pdotl-version-bump-patch
Fix #809 and #833 in actions/cache. Bump version for NPM package actions/cache to v3.0.1
2022-08-04 11:55:07 +05:30
Sankalp Kotewar fe1ee8b6b4 Updated lerna to 5.3.0 due to audit reasons 2022-08-03 14:25:32 +00:00
Sankalp Kotewar c89375df9f Linting fixes 2022-08-03 14:12:16 +00:00
Sankalp Kotewar 7cb82599d4 Reverted node versions to 12.x in workflows 2022-08-03 13:41:19 +00:00
Sankalp Kotewar 8be69a26ed Added custom promise with timeout 2022-08-03 13:25:47 +00:00
Sankalp Kotewar 970264135a Added abort controller for timer 2022-08-03 11:11:30 +00:00
Sankalp Kotewar e5e69a3171 Added abortController to stop download 2022-08-03 10:23:42 +00:00
Lovepreet Singh 567598fdd7 Fix #809 and #833 in actions/cache. Bump version 2022-08-03 07:01:03 +00:00
Shubham Tiwari d8b119ca22 Update unit-tests.yml 2022-07-29 13:12:58 +05:30
Shubham Tiwari a438f61f94 Update cache-tests.yml 2022-07-29 13:12:38 +05:30
Shubham Tiwari 388d774221 Update downloadUtils.ts 2022-07-29 12:52:57 +05:30
Bishal Prasad 9b309c5a32 Hack for timeout for segment download 2022-07-29 12:37:50 +05:30
Lovepreet Singh 01e1ff7bc0 Merge pull request #1135 from actions/pdotl-zstd-alias
Move zstd from flags to equivalent aliases
2022-07-26 16:04:16 +05:30
Lovepreet Singh 74ff60c561 Merge pull request #1132 from actions/pdotl-empty-cache-bugfix
Fix Empty Cache save when the path is github workspace directory
2022-07-26 14:34:01 +05:30
Lovepreet Singh e98bae803b Change testcase to test against github workspace directory instead of current directory 2022-07-20 05:25:47 +00:00
Lovepreet Singh dd553d68ce Fix tar test cases 2022-07-18 12:48:19 +00:00
Lovepreet Singh 74dd6f6817 Move zstd from flags to equivalent aliases 2022-07-18 09:12:07 +00:00
Lovepreet Singh 83bca5cb13 Remove unnecessary import 2022-07-14 08:18:09 +00:00
Lovepreet Singh 2a37ee752b Merge branch 'pdotl-empty-cache-bugfix' of https://github.com/actions/toolkit into pdotl-empty-cache-bugfix 2022-07-14 08:12:45 +00:00
Lovepreet Singh ec95a9b114 Fix failing resolvePaths testcase 2022-07-14 08:10:40 +00:00
Lovepreet Singh 67cb82d99b Fix failing resolvePaths testcase 2022-07-14 07:50:44 +00:00
Lovepreet Singh da6701aea9 Fix linting for changes 2022-07-13 13:37:49 +00:00
Lovepreet Singh 593bc7061c Fix testcase for resolvePaths works on current directory 2022-07-13 11:55:36 +00:00
Lovepreet Singh 120202a68c Fix empty cache save on using or github.workspace(#833 in actions/cache) as path 2022-07-13 11:39:29 +00:00
Shubham Tiwari c5278cdd08 new major version release (#1123) 2022-06-24 15:18:30 +05:30
Shubham Tiwari 46231a7da3 Graceful handling of error (non-validation one) (#1122)
* Initial changes

* added info error as well

* Format

* Unused package

* adding message field

* removed line

* Review comments

* review comment to add validation as errors handling
2022-06-24 10:46:20 +05:30
Thomas Boop 9b7bcb1567 actions/core 1.9.0 release (#1116)
* 1.9.0 release

* add link to pr
2022-06-15 11:34:58 -04:00
Seth Vargo 00282d6145 core: add helpers for working with paths across OSes (#1102) 2022-06-15 11:18:44 -04:00
Sankalp Kotewar b5f31bb5a2 Merge pull request #1108 from actions/users/kotewar/fix-tar-exit-with-code-1
Adding fix for tar exiting with code 1 issue
2022-06-06 14:41:07 +05:30
Sankalp Kotewar 41c667327d Reverted other package-lock.json 2022-06-06 08:03:56 +00:00
Sankalp Kotewar 2fd9a80bc1 Revert "Adding fix for tar exiting with code 1 issue"
This reverts commit 197f5a13a9.
2022-06-06 07:56:27 +00:00
Sankalp Kotewar ebfda315a5 Revert "Adding updated package-lock.json for cache"
This reverts commit 1d5b16aa38.
2022-06-06 07:56:25 +00:00
Sankalp Kotewar fe93288f85 Revert "Fixed test case for tar creation"
This reverts commit 91842768bd.
2022-06-06 07:56:23 +00:00
Sankalp Kotewar 2d6e5ecd7c Revert "Pushing updated package-lock.json for artifact"
This reverts commit 1fc4ec3274.
2022-06-06 07:56:21 +00:00
Sankalp Kotewar 49cd1ccc3f Revert "Fixed test case for Windows env"
This reverts commit a78bb30ca0.
2022-06-06 07:56:18 +00:00
Sankalp Kotewar 3cf35dbd46 Revert "Changed an import in test case to standard import"
This reverts commit 347d2e2a35.
2022-06-06 07:56:16 +00:00
Sankalp Kotewar 845770f824 Revert "Revert "Changed an import in test case to standard import""
This reverts commit c1bb3fb679.
2022-06-06 07:56:13 +00:00
Sankalp Kotewar c1bb3fb679 Revert "Changed an import in test case to standard import"
This reverts commit 347d2e2a35.
2022-06-03 09:05:12 +00:00
Sankalp Kotewar 347d2e2a35 Changed an import in test case to standard import 2022-06-03 07:45:12 +00:00
Sankalp Kotewar a78bb30ca0 Fixed test case for Windows env 2022-06-03 07:33:12 +00:00
Sankalp Kotewar 1fc4ec3274 Pushing updated package-lock.json for artifact 2022-06-03 07:26:28 +00:00
Sankalp Kotewar 91842768bd Fixed test case for tar creation 2022-06-03 07:19:54 +00:00
Sankalp Kotewar 1d5b16aa38 Adding updated package-lock.json for cache 2022-06-01 13:32:34 +00:00
Sankalp Kotewar 197f5a13a9 Adding fix for tar exiting with code 1 issue 2022-06-01 13:18:50 +00:00
Sankalp Kotewar 8263c4d15d Merge pull request #1097 from actions/users/kotewar/avoid-empty-cache-save
Avoid saving empty cache when there are no files to cache.
2022-05-24 13:27:13 +05:30
Sankalp Kotewar 4ee0048304 Updated RELEASES.md with release information 2022-05-24 06:55:11 +00:00
Sankalp Kotewar d618dc457e Added package-lock.json after version upgrade 2022-05-24 05:48:53 +00:00
Sankalp Kotewar 558edc0a3b Patch version bumped from 2.0.4 to 2.0.5 for cache 2022-05-24 05:45:53 +00:00
Sankalp Kotewar 92b210aced Test case fix for warning message changes 2022-05-23 12:05:31 +00:00
Sankalp Kotewar 6f6f4e7588 Enhanced warning description to make more sense. 2022-05-23 12:03:18 +00:00
Sankalp Kotewar 10a3934663 Fixed linting issues 2022-05-23 06:49:26 +00:00
Sankalp Kotewar 6421989639 Standardized test case input 2022-05-23 06:39:22 +00:00
Sankalp Kotewar 07b91eafe5 Added unit test case for #624 2022-05-23 06:32:13 +00:00
Sankalp Kotewar b9fefecf57 Formatting changes 2022-05-23 05:59:56 +00:00
Sankalp Kotewar 9aecf41d21 Updated error type to generic to show warning 2022-05-23 05:39:42 +00:00
Sankalp Kotewar da52b35800 Adding check for cache paths' existence. 2022-05-22 10:09:13 +00:00
Rob Herley 1e0f6285e5 Merge pull request #1095 from actions/robherley/artifact-1.1.0-release
@actions/artifact 1.1.0 release
2022-05-19 14:52:47 -04:00
Rob Herley dd4e856a4e @actions/artifact 1.1.0 release 2022-05-19 18:17:15 +00:00
Rob Herley a70804595b Merge pull request #1063 from actions/robherley/artifact-digest
Add checksum validation on artifact upload
2022-05-19 14:12:50 -04:00
Rob Herley eb7ed88d77 Merge branch 'main' into robherley/artifact-digest 2022-05-19 11:45:42 -04:00
Konrad Pabjan 500d0b42fe Bump all packages that have @actions/http-client as a dependency (#1088)
* bump @actions/artifact

* update @actions/cache

* Update @actions/core

* Update @actions/github

* update @actions/tool-cache
2022-05-13 11:12:58 -04:00
Konrad Pabjan 82efa3d285 Bump @actions/http-client in all packages that use it (#1087) 2022-05-13 10:58:36 -04:00
Konrad Pabjan 2abc7c46f8 Bump to version 2.0.1 (#1086) 2022-05-13 10:29:29 -04:00
Konrad Pabjan e48f1d0c54 Make tunnel a prod dependency for http-client (#1085) 2022-05-13 10:19:06 -04:00
Brian Cristante aa676f3cc7 Update other packages to use http-client v2 (#1082)
We moved `@actions/http-client` to be part of the toolkit in https://github.com/actions/toolkit/pull/1062.  We also made some breaking changes to exported types and released v2.

The biggest change in terms of lines of code affected was to get rid of the `I-` prefix for interfaces since TypeScript doesn't follow this convention.

I bumped the patch version of all packages except for `tool-cache`, where I bumped the major version.  The rationale is explained in the release notes for that package.
2022-05-11 17:14:25 -04:00
Rob Herley 925ae6978b Merge pull request #1074 from actions/robherley/core-1.8.0-release
@actions/core 1.8.0 release
2022-05-05 16:24:45 -04:00
Rob Herley e73063a93c @actions/core 1.8.0 release 2022-05-05 20:17:30 +00:00
Rob Herley c4ae214c26 Merge pull request #1073 from actions/robherley/deprecate-markdownsummary
Add & deprecate old markdownSummary export
2022-05-05 16:07:16 -04:00
Rob Herley 07242b37a4 add & deprecate old markdownSummary export 2022-05-05 19:44:13 +00:00
Rob Herley 01aceeaad6 Merge pull request #1072 from actions/robherley/not-markdown-summaries
Rename core's `markdownSummary` extension to `summary`
2022-05-05 14:17:33 -04:00
Rob Herley 3d29fb91d1 sed 's/markdownSummary/summary/g' 2022-05-05 17:29:20 +00:00
Rob Herley 35e5aac523 actually use md5 not sha256 2022-05-05 10:32:09 -04:00
Rob Herley a3c696e88e add md5 and use b64 for digest encodings 2022-05-05 09:26:38 -04:00
Brian Cristante 91b7bf978c Move @actions/http-client into the toolkit (#1062)
💡 See https://github.com/actions/toolkit/pull/1064 for a better diff!

https://github.com/actions/toolkit contains a variety of packages used for building actions.  https://github.com/actions/http-client is one such package, but lives outside of the toolkit.  Moving it inside of the toolkit will improve discoverability and reduce the number of repos we have to keep track of for maintenance tasks (such as github/c2c-actions-service#2937).

I checked with @bryanmacfarlane on the historical decision here.  Apparently it was just inertia from before we released the toolkit as multiple packages.

The benefits here are:
- Have one fewer repo to keep track of
- Signal that this is an HTTP client meant for building actions, not for general use.

## Notes
- `@actions/http-client` will continue to be released as its own package.
- Bumping the package version to **2.0.0**.  Since we're compiling in strict mode now, there are some breaking changes to the exported types.  This is an improvement because the null-unsafe version of`http-client` is currently breaking the safety of null-safe consumers.
- I'm not updating the other packages to use the new version in this PR.  I plan to do that in a follow-up.  We'll hold off on publishing `http-client` v2 to NPM until that's done just in case other changes shake out of it.
2022-05-03 11:10:13 -04:00
Rob Herley b68735e060 misc pr feedback 2022-04-27 22:24:16 +00:00
Rob Herley d5c547c19f update crc header key 2022-04-27 22:22:35 +00:00
Rob Herley 9e285cc3fa crc: update test header data 2022-04-26 23:21:31 +00:00
Rob Herley 3f95e2ea4f crc: update headers & digest stream 2022-04-26 22:59:56 +00:00
Rob Herley fccc5ee6e6 crc: move tbl out of class, more tests 2022-04-26 17:31:17 +00:00
Rob Herley 3d61fe8000 add crc64 & tests 2022-04-26 17:13:40 +00:00
Rob Herley 9387bd7ded Merge branch 'main' into robherley/artifact-digest 2022-04-26 15:54:22 +00:00
Rob Herley 3e2837ddce Merge pull request #1059 from actions/robherley/core-1.7.0-release
@actions/core 1.7.0 release
2022-04-25 09:14:37 -04:00
Rob Herley 3048a9d72c @actions/core 1.7.0 release 2022-04-20 20:42:50 +00:00
Rob Herley 91f9153ca8 Merge pull request #1014 from actions/robherley/md-summaries
feat: @actions/core extensions for markdown summary
2022-04-20 16:28:27 -04:00
Rob Herley eef3e92175 summary: remove limit validation in client 2022-04-20 20:10:56 +00:00
Rob Herley ed87cc6ce3 summary: increase limit to 1MiB 2022-04-20 19:55:54 +00:00
Thomas Boop af45ad8eaa Glob 0.3.0 release (#1056)
* Revert "Exec 1.2.0 patch"

c9f7927778

* glob 0.3.0 release
2022-04-18 15:49:18 -04:00
Thomas Boop 367a6c2423 Exec 1.2.0 patch (#1055) 2022-04-18 14:52:32 -04:00
ruvceskistefan 8f2bd5d713 Added verbose mode in hashFiles (#1052)
* Added verbose mode in hashFiles

* Code formatting

* Change verboseMode arg to verbose

Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>

* Using verbose instead of verboseMode as arg

Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
2022-04-18 14:29:24 -04:00
Anurag Chauhan 7654d97eb6 Merge pull request #1050 from actions/fix_cache_error_type
Fix error type so that cache size limit violation is shown as warning( similar to previous error)
2022-04-07 14:46:23 +05:30
Anurag Chauhan 0b2505c754 Fix error type so that size limit violation is shown as warning 2022-04-07 09:08:16 +00:00
Rob Herley e3549a9c58 artifact: tests for stream digest util 2022-04-05 09:31:49 -04:00
Rob Herley c5d1911357 add digest header for uploads 2022-04-04 17:54:15 -04:00
Deepak Dahiya f8a69bc473 Added cacheSize in ReserveCache API request (#1044)
* Added cacheSize in ReserveCache API request

* minor

* minor

* minor

* Cleanup

* package-lock revert

* Modified tests

* New Response Type

* cleanup

* Linting

* Lint fix

* Resolved comments

* Added tests

* package-lock

* Resolved package-lock mismatch

* Liniting

* Update packages/cache/src/cache.ts

Co-authored-by: Bishal Prasad <bishal-pdmsft@github.com>

* Linting issue

* Resolved few comments

* version upgrade

* Savecache tests

* RequestUtil test

* test

* test

* test

* test

* test

* test

* test

* test

* test

* test

Co-authored-by: Apple <apple@Apples-MacBook-Pro.local>
Co-authored-by: Bishal Prasad <bishal-pdmsft@github.com>
2022-04-04 16:21:58 +05:30
Deepak Dahiya 03eca1b0c7 Revert "T dedah/cache size" (#1042) 2022-04-01 02:10:08 +05:30
Deepak Dahiya 4b12bd3649 Merge pull request #1041 from t-dedah/t-dedah/cacheSize
T dedah/cache size
2022-04-01 02:07:14 +05:30
Apple 6cd8286138 Resolved comments 2022-04-01 01:41:12 +05:30
Apple 3abbc6c24c Lint fix 2022-04-01 01:16:43 +05:30
Luke Tomlinson d594f1e4b3 Fix npm audit (#1040) 2022-03-31 14:40:06 -04:00
Luke Tomlinson 4a2602dd58 Fix test for windows 2022 (#1039) 2022-03-31 14:39:39 -04:00
Luke Tomlinson 745f129332 Update @actions/github to 5.0.1 (#1038)
* Update @actions/github to 5.0.1

* Fix package-lock.json
2022-03-31 13:53:55 -04:00
Luke Tomlinson 7e7e8d4206 Update octokit dependencies (#1037) 2022-03-31 10:36:40 -04:00
Deepak Dahiya daa24d7958 Linting 2022-03-31 10:41:54 +00:00
Deepak Dahiya bda035c74d cleanup 2022-03-31 09:44:40 +00:00
Deepak Dahiya 79acd5bac4 New Response Type 2022-03-31 09:42:59 +00:00
Apple b602df7c05 Modified tests 2022-03-30 13:27:36 +05:30
Deepak Dahiya 80a66f3298 package-lock revert 2022-03-30 07:33:48 +00:00
Deepak Dahiya 7756e7c4cb Cleanup 2022-03-30 07:22:56 +00:00
Deepak Dahiya 6d774fcb59 minor 2022-03-29 22:21:15 +00:00
Deepak Dahiya f05c940e43 minor 2022-03-29 22:20:22 +00:00
Deepak Dahiya a71585a450 minor 2022-03-29 22:19:10 +00:00
Deepak Dahiya 76ac2fcd59 Added cacheSize in ReserveCache API request 2022-03-29 22:17:04 +00:00
Shubham Tiwari b463992869 Adding support in cache package to check if Artifact Cache service is enabled or not (#1028)
* Added support to check if Artifact cache service is enabled or not.

* enablingForGHES

* added ACTIONS_CACHE_URL in fixtures

* Fix CI

* CI fix

* changed function name

* Function rename

* Updated release

* added test case

* Update RELEASES.md

* Lint errors

* lint

* linting

* lint

* update name to actions service

* Update packages/cache/src/internal/cacheUtils.ts

Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>

* review comments

* linting

* linting

* push to start CI

* Update RELEASES.md

* remove extra spaces

* reverting version update

* Revert "reverting version update"

This reverts commit af84eba61e.

* Update RELEASES.md

Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>
2022-03-25 14:40:02 +05:30
Ashwin Sangem 39b9640642 Merge pull request #1030 from actions/users/ashwinsangem/fix_download_chunk_cap
Cap the cache download chunk to 2 GB
2022-03-24 19:11:52 +05:30
Ashwin Sangem f0a876ab8b bumped up the @action/cache version. 2022-03-24 11:19:52 +00:00
Ashwin Sangem 58406447b5 Fixed toolkit audit by running npm audit fix. 2022-03-23 11:24:15 +00:00
Ashwin Sangem 087191dabd Update downloadUtils.ts 2022-03-23 16:46:52 +05:30
Ashwin Sangem 862c4e9db4 Cap the cache download chunk to 2 GB 2022-03-23 16:44:40 +05:30
Jonathan Tamsut d1abf7dc74 Update lockfileVersion in package-lock.json in tool-cache package (#1025)
* update packages

* update RELEASE

* update RELEASE

* remove extra README line
2022-03-16 11:27:30 -07:00
Jonathan Tamsut 475192a0c3 Update lockfileVersion in package-lock.json in cache package (#1022)
* update versions

* update release notes
2022-03-16 11:25:03 -07:00
Jonathan Tamsut c07c5fc410 Update lockfileVersion in package-lock.json in glob package (#1023)
* update versions

* update RELEASE file
2022-03-16 11:24:24 -07:00
Jonathan Tamsut b820a0ff59 Update lockfileVersion in package-lock.json in exec package (#1024)
* update packages

* update RELEASE
2022-03-16 11:24:01 -07:00
Jonathan Tamsut 72dfadb0c3 Update lockfileVersion in package-lock.json in io package (#1020)
* update lockfileVersion

* Update package
2022-03-16 11:23:44 -07:00
Rob Herley edee7cde32 feedback: add summary write options 2022-03-08 16:37:20 -05:00
Rob Herley 6295f5d25b summary: consistent kB usage and doc links 2022-03-03 11:46:32 -05:00
Rob Herley 339dd63bec summary: method to clear file and buffer 2022-03-02 23:56:30 -05:00
Rob Herley d27bf857e6 add -> addRaw 2022-03-02 23:49:17 -05:00
Rob Herley ec5c955c0a summary: additional check for max size limit 2022-03-02 23:43:51 -05:00
Rob Herley 302a5b31d8 summary: add link/anchor element 2022-03-02 12:10:01 -05:00
Rob Herley ab2b23c50d summary: add tests 2022-03-02 00:58:18 -05:00
Rob Herley 70a01b86d3 summary: self closing tags, additional img attrs & minor fixes 2022-03-02 00:57:46 -05:00
Rob Herley ff80a82f7c Merge branch 'main' into robherley/md-summaries 2022-03-01 21:38:28 -05:00
Rob Herley 0fc0befe24 export markdownSummary singleton from core 2022-03-01 21:32:26 -05:00
Rob Herley 7d95d2cec9 summary.ts -> markdown-summary.ts 2022-03-01 21:16:35 -05:00
Rob Herley c42d30607b add more summary elements, clean up jsdoc 2022-03-01 21:14:58 -05:00
Rob Herley ac58d176ba '\n' -> os.EOL 2022-03-01 20:55:43 -05:00
Rob Herley 518ef1b79e html element wrapper method for md summary 2022-03-01 20:36:04 -05:00
Jonathan Tamsut a502af8759 Merge pull request #1009 from actions/jtamsut/update-artifact-file-version
Update `lockfileVersion` for artifact package
2022-03-01 12:47:16 -08:00
Jonathan Tamsut 5905c6b5c1 Bump major version 2022-03-01 12:36:05 -08:00
Jonathan Tamsut 5e37db2c2b update lockfileVersion for artifact 2022-03-01 12:10:10 -08:00
Rob Herley d496b07cc0 addText -> add, newline by default 2022-02-23 18:15:26 -05:00
Rob Herley 7a2eceac36 initial markdown summary utils 2022-02-23 18:09:05 -05:00
Vipul fcb8c4ca79 Merge pull request #991 from actions/fix-dep-cache
Update ms-rest-js and storage-blog dependencies for cache
2022-02-08 09:58:05 +05:30
vsvipul 4a793fd385 Update RELEASES.md 2022-02-04 14:11:29 +05:30
Brian Cristante 15e2399826 Update CODEOWNERS with new teams (#990)
* Use the actions-cache team as owner of the cache package

* Update CODEOWNERS
2022-02-02 12:43:38 -05:00
vsvipul 39a1ec60b2 Bump up patch version 2022-02-01 17:15:42 +05:30
vsvipul eafa9d39d3 Update ms-rest-js and storage-blog dependencies for cache 2022-02-01 16:24:23 +05:30
Konrad Pabjan daf8bb0060 0.6.1 release (#964) 2021-12-14 16:01:55 -05:00
Zoran Regvart 37f5a85219 fix: drop support for named pipes on Windows (#962)
Seems that folk are having issues with uploading 0-byte files from
Windows agents. This effectively removes the support for Windows for
uploading from named files that, due to `isFIFO` returning `false` on
Windows for named pipes created using MSYS2's `mkfifo` command, resorted
to checking if the file size is 0 - a common trait of named pipes.

See https://github.com/actions/upload-artifact/issues/281
2021-12-14 15:50:50 -05:00
Konrad Pabjan d1a6612b14 Update releases.yml (#960) 2021-12-07 10:38:25 -05:00
Konrad Pabjan 6fcdd6ab0d [Artifacts] Prep for @actions/artifact 0.6.0 release (#958)
* actions-artifact-0.6.0 release

* Fix lint issue

* Update RELEASES.md
2021-12-06 18:39:23 -05:00
Konrad Pabjan 45a3c7bf81 [Artifacts] More detailed information for chunked uploads (#957)
* More detailed information for chunked uploads

* Run npm format
2021-12-06 16:48:14 -05:00
Konrad Pabjan cdd4e107a6 [Artifacts] Exempt certain types of files from gzip compression (#956)
* Exempt certain types of files from gzip compression

* Fix lint issue
2021-12-06 16:47:44 -05:00
Konrad Pabjan 88062ec473 Check for newlines and carriage return in artifact paths and name (#951)
* Check for newlines and carriage return in artifact paths and name

* Fix linting issue

* Update comments

* Add comment about spacing

* Remove extra space
2021-12-01 16:31:37 -05:00
Konrad Pabjan 4df5abb3ee Updates to logging for artifact uploads (#949)
* More details logs during artifact upload

* extra logging

* Updates to artifact logging + clarifications around upload size

* Fix linting errors

* Update packages/artifact/src/internal/artifact-client.ts

Co-authored-by: campersau <buchholz.bastian@googlemail.com>

Co-authored-by: campersau <buchholz.bastian@googlemail.com>
2021-11-30 12:53:24 -05:00
campersau e19e4261da Reset processedCount when downloading all artifacts (#889) 2021-11-29 17:28:03 -05:00
Ichinose Shogo e9b0746ee3 artifact: @types/tmp should be devDependencies (#860) 2021-11-29 17:22:33 -05:00
Zoran Regvart 7932c147a0 Support upload from named pipes (#748)
Named pipes report file size as 0, which leads to reading the whole
content into memory (0 is less than 64K). This adds additional check to
make sure that the passed in path is not a named pipe, and in that case
opts for the create-temp-file-to-gzip code path.

When running on GitHub Actions infrastructure on `windows` node, named
pipes can be created using `mkfifo` from MSYS2. In that case `fs.Stats`s
`isFIFO()` returns `false`, and not `true` as expected. This case is
detected by `process.platform` being `win32` and the passed file having
length of 0.

As a side note, when MSYS2's `mkfifo` is run, a pipe file is created:

```
prw-rw-rw- 1 User None  0 Mar 31 12:58 pipe
```

If `fs.stat` is invoked at this point `ENOENT` error will be thrown. As
soon as the pipe is written to, this pipe file is replaced by two same-
named files:

```
-rw-r--r-- 1 User None  0 Mar 31 13:00 pipe
-rw-r--r-- 1 User None  0 Mar 31 13:00 pipe
```

And at this point `fs.stat` `isFIFO()` returns `false`. Even though the
file acts as a named pipe.
2021-11-29 17:19:02 -05:00
Aparna Ravindra 45d2019161 Cache: Increasing client validation to 10GB (#934)
* increasing client validation limit in cache package to 10gb
2021-11-19 16:34:33 +05:30
Luke Tomlinson e2eeb0a784 Fix high sev in github package (#924) 2021-10-15 15:26:30 -04:00
Luke Tomlinson 6ce349e08c Update High Severity Dev Dependencies (#923)
* Update deps

* More Updates

* Use npm 7

* Update package-lock.json
2021-10-14 09:20:09 -04:00
Thomas Boop 27f76dfe1a Full release of actions/core 1.6.0 with oidc behavior (#919)
* OIDC Client for actions/core

Co-authored-by: Sourav Chanduka <souravchanduka37@gmail.com>
Co-authored-by: Sourav Chanduka <souravchanduka@users.noreply.github.com>
Co-authored-by: Tingluo Huang <tingluohuang@github.com>
2021-09-28 12:55:21 -04:00
Marcono1234 60145e408c Add file property to AnnotationProperties (#896) 2021-09-28 09:47:06 -04:00
martincostello 8b45e1e356 Fix endColumn documentation
Change "start" to "end".
2021-08-20 11:06:49 +01:00
Luke Tomlinson ea81280a4d Update release for core 1.5.0 (#873)
* Update release for core 1.5.0

* Update RELEASES.md

* Run npm audit fix
2021-08-18 09:26:19 -04:00
Luke Tomlinson f0b00fd201 Add notice annotation and support more annotation fields (#855)
* Add support for notice annotation and additional properties

* Add additional tests

* Update readme

* Change casing for endLine and endColumn

* Update utils.ts

* Update README.md

* Rename files to have internal- nomenclature

* Revert "Rename files to have internal- nomenclature"

This reverts commit 7911689f29.

* Update utils.ts
2021-07-28 17:34:31 -04:00
Rob Cowsill 4564768940 Delete temporary archive after cache upload (#792)
This is to avoid filling the SSD while saving multiple large caches
2021-06-28 17:27:09 +02:00
Brian Cristante a31b7eca9e Bump artifact package version to v0.5.2 (#845)
* bump version in package*.json

* changelog
2021-06-16 09:37:06 -04:00
Brian Cristante 9167ce1f3a Resolve vulnerabilities found by npm audit (#846) 2021-06-16 09:20:08 -04:00
Thomas Boop 11601c0d2d Release new version of the tool-cache (#838)
* update to latest version of @actions/io

* Release new version and update dependencies

* add pr number
2021-06-07 15:50:05 -04:00
Thomas Boop b9414eecb3 we really shouldn't warn on these errors, action author can decide what to do (#837) 2021-06-07 15:31:03 -04:00
Thomas Boop 243a8bba07 New versions of toolkit packages (#835) 2021-06-07 15:09:34 -04:00
Thomas Boop c5e1af5dc3 Add HashFiles to the toolkit (#830)
* add hash files to the toolkit
2021-06-07 14:26:00 -04:00
Thomas Boop c9af6bb1b3 Update escaping rules in io's rmRF (#828)
* Better Handling of escaping in rmrf
2021-06-07 14:16:16 -04:00
Luke Tomlinson bf4ce74a0f Update @actions/exec to 1.1.0 (#834) 2021-06-07 10:09:34 -04:00
Brian Cristante db21627995 Retry artifact uploads on HTTP 500 (#833)
* Retry on 500

* bump package version

* fix tests

* Remove spurious change

* fix another test

* Roll back package version
2021-06-04 17:09:30 -04:00
Thomas Boop bb2f39337d Sarpik/get input list support (#829)
* feat(core): Create `getInputList` utility

Signed-off-by: Kipras Melnikovas <kipras@kipras.org>

* chore(core): Document usage of '\n' instead of [] @ `getInputList`

Signed-off-by: Kipras Melnikovas <kipras@kipras.org>

* test(core): Create a very simple test for `getInputList`

Signed-off-by: Kipras Melnikovas <kipras@kipras.org>

* run linter

* update commands/readme

Co-authored-by: Kipras Melnikovas <kipras@kipras.org>
2021-06-04 09:28:49 -04:00
Thomas Boop dc4b4dab1d add the lint-fix script (#831) 2021-06-04 09:25:13 -04:00
Luke Tomlinson 8df94d9879 Add test for large stdline output (#827)
* Add test for large stdline output

* Format/Lint

* Update stdlineoutput.js

* Update stdlineoutput.js
2021-06-03 09:31:48 -04:00
Andrey Savitsky c5035362ab Fix broken line buffers (#773)
* Fix broken line buffers

* Code style
2021-06-02 16:29:46 -04:00
Matisse Hack 439eaced07 Add directory filtering to globber (#728)
Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
2021-06-01 15:57:03 -04:00
Thomas Boop 51dc07a106 Only run codeql on main branch pushes (#826) 2021-06-01 10:11:52 -04:00
dependabot[bot] 36b8c66aec Bump ws from 7.4.5 to 7.4.6 in /packages/github (#824)
Bumps [ws](https://github.com/websockets/ws) from 7.4.5 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.5...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-01 09:50:37 -04:00
dependabot[bot] aa29345ae8 Bump ws from 7.2.3 to 7.4.6 (#823)
Bumps [ws](https://github.com/websockets/ws) from 7.2.3 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.2.3...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-01 09:50:25 -04:00
Sergey Ukustov e1a7863be6 feat: get linux version from os-release file if available (#594) 2021-05-28 15:40:45 -04:00
Thomas Boop c507914181 Fix debug logging link (#820) (#822)
Co-authored-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2021-05-27 14:15:37 -04:00
Thomas Boop a65bca60a1 Tool Cache 1.7.0 release (#821)
* tc 1.7.0 release

* update verbiage
2021-05-27 11:44:59 -04:00
Luke Tomlinson a1b068ec31 Bugfix: Fix issue with interactive unzip on Linux (#807)
* Add new powershell commands for windows unzip

* Test fails to overwrite file

* Add new windows commands for unzip

* Add Test for failing case for both pwsh and powershell

* Modify test to confirm overwrite behavior for xar

* Delete ._test.txt

* Add fallback case for older windows systems

* Remove try

* Run Tests on windows-2016

* Update tar tests to handle existing files

* Lint

* Update tool-cache.test.ts

* Update tool-cache.test.ts

* Update tool-cache.test.ts

* Update tool-cache.test.ts

* Update from PR feedback
2021-05-21 17:01:42 -04:00
Luke Tomlinson 6e33c78c3d Update @actions/glob to 0.1.2 (#818) 2021-05-21 15:50:31 -04:00
Luke Tomlinson 9ac66375a0 Fix flakey test (#817) 2021-05-21 15:32:09 -04:00
Luke Tomlinson ddd04b6997 Add getExecOutput function (#814)
* Add getExecOutput function

* Add tests for exec output

* Modify tests to not rely on buffer size, but only test larger output

* Handle split multi-byte characters + PR feedback

* Fix tests

* Lint

* Update how split byte are sent for tests
2021-05-21 12:12:16 -04:00
Thomas Boop 566ea66979 prep for actions core 1.3.0 release (#816) 2021-05-21 09:19:53 -04:00
Thomas Boop 0d74e9080a Re-enable the audit tools step and update dependencies (#815)
* update package versions

* run audit

* fix eslint config

* linter updates

* re-enable audit

* update timeouts test

* pass done into callback

* fix format
2021-05-21 09:19:40 -04:00
Chris Mc 8dc2d6eb6a Update location of typescript definitions (#743)
https://github.com/octokit/webhooks.js#typescript
2021-05-20 16:49:57 -04:00
rethab 3bd746139f Describe behaviour of getInput (#808) 2021-05-19 11:08:51 -04:00
Thomas Boop f915ace085 add release notes (#809) 2021-05-14 14:43:08 -04:00
dependabot[bot] 1bafbed467 Bump lodash from 4.17.15 to 4.17.21 (#801)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-14 14:39:47 -04:00
Luke Tomlinson 98549fbf21 Prevent accidental file matching when glob contains trailing slash (#805)
* Draft Solution

* Update internal-globber.ts

* Cleanup

* Fix Test

* Cleanup
2021-05-14 14:12:26 -04:00
Luke Tomlinson b33912b7cc Core: Add trimWhitespace to getInput (#802)
* Add option to not trim whitespace from inputs

* Fix typos

* Add doc clarification

* Rename options
2021-05-11 13:51:36 -04:00
dependabot[bot] cac7db2d19 Bump handlebars from 4.5.3 to 4.7.7 (#799)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.5.3 to 4.7.7.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.5.3...v4.7.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-07 16:37:28 -04:00
Luke Tomlinson 1c367e0a26 Export isExplicitVersion and evaluateVersions (#796)
* Export isExplicitVersion and evaluateVersions

* Lint

* Add docs
2021-05-07 16:13:26 -04:00
Luke Tomlinson 09e59b9a5c Exec: throw error when cwd option does not exist (#793)
* Exec: throw error when cwd option does not exist

* Simplify promise rejection
2021-05-07 16:12:40 -04:00
dependabot[bot] fecf6cdd59 Bump hosted-git-info from 2.7.1 to 2.8.9 (#800)
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.7.1 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.7.1...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-07 14:17:30 -04:00
Thomas Boop 2b97eb3192 Include urls in @actions/github context (#794)
* include urls in github context

* fix format
2021-05-07 14:05:08 -04:00
Thomas Boop ed490dc20d Update dependencies of tool-cache to fix npm audit (#795)
* Update dependencies to resolve security issue

* run npm audit fix in `actions/github`

* update jest as well to newest version
2021-05-07 14:04:38 -04:00
Luke Tomlinson 3491e2eeea Add option to cp to only copy contents of directory (#788)
* Add option to not copy source directory

* Cleanup

* Update condition to be consistent
2021-05-05 09:40:12 -04:00
Thomas Boop 208fa83feb Release @actions/github v.5.0.0 (#783)
* update latest octokit definitions

* update package versions

* update link in release notes

* update tsc version
2021-05-04 16:20:38 -04:00
Thomas Boop 393feda10a Runtime is gonna take tool-cache (#787) 2021-05-04 16:19:54 -04:00
Minh Nguyen d972090333 Fix typo in function name (#590) 2021-05-03 11:09:44 -04:00
yi_Xu fbdf27470c feat(core): add getBooleanInput function (#725)
* feat(core): add getBooleanInput function

* docs(core): update readme

* test(core): update the core.test.ts
2021-04-28 16:32:25 -04:00
Chris Gavin ff45a53422 Allow specifying arbitrary headers when downloading tools to the tool cache. (#530) 2021-04-28 14:39:15 -04:00
Thomas Boop 15fef78171 Simplify mkdirP implementation (#781)
Co-authored-by: Linus Unnebäck <linus@folkdatorn.se>
2021-04-28 14:38:41 -04:00
Simran dd046652c3 docs: Fix two typos and add some blank lines to commands.md (#607)
* docs: Fix two typos and add some blank lines to commands.md

* Update docs/commands.md

Co-authored-by: Simran <Simran-B@users.noreply.github.com>

Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
2021-04-27 10:41:51 -04:00
Scott Moeller cf3d93512b Update problem-matchers.md (#735) 2021-04-27 10:38:54 -04:00
dependabot[bot] 3512925c1c Bump ssri from 6.0.1 to 6.0.2 (#776)
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-27 10:06:31 -04:00
eric sciple e76decaf8a Prepend newline for set-output (#772) 2021-04-13 12:01:19 -05:00
Vikas Kedia 8afb976445 Update README.md (#531)
more logical to read save cache before restore cache
2021-04-12 10:18:07 -04:00
Tom Jenkinson b05573d945 fix formatting in core package readme (#563) 2021-04-12 09:50:56 -04:00
David Hadka 634dc61da2 Merge pull request #767 from actions/dhadka/fix-permissions
Fix permissions issues using gtar on mac
2021-04-09 14:34:51 -05:00
David Hadka aad34ab0bc Update RELEASES.md 2021-04-09 14:23:05 -05:00
Dave Hadka fac664b5d0 Fix lint issue 2021-04-09 14:16:19 -05:00
Dave Hadka 74236358e6 Update tests 2021-04-09 14:10:36 -05:00
David Hadka ac7b0e436e Update package-lock.json 2021-04-09 13:58:53 -05:00
David Hadka 440a06ef56 Update package.json 2021-04-09 13:58:35 -05:00
David Hadka 547a77cf75 Fix permissions issues using gtar on mac 2021-04-09 13:38:55 -05:00
Thomas Boop a6966e3148 fix deploy pipeline (#763) 2021-04-06 14:41:33 -04:00
Thomas Boop 92488b8ab2 Update releases.yml (#762) 2021-04-06 14:08:29 -04:00
Konrad Pabjan f628f161c4 Bump artifact package version (#761) 2021-04-06 13:49:15 -04:00
eric sciple ea2465fe63 Update and rename deno.yml to rename.yml (#721)
* Create process to release packages via actions


Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2021-04-06 13:37:17 -04:00
Konrad Pabjan 770dc3a982 @actions/artifact 0.5.1 release (#760)
* Bump @actions/http-client to latest for artifact package

* Remove typescript libs to fix failing imports
2021-04-06 12:44:56 -04:00
Scott Moeller 418978c2e0 Note annotation limits in Problem Matchers documentation (#734)
* Update problem-matchers.md

* Update docs/problem-matchers.md

Fixup text

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2021-04-06 11:11:05 -04:00
dependabot[bot] fc00528337 Bump y18n from 4.0.0 to 4.0.1 (#753)
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-02 12:41:01 -04:00
Sora Morimoto bd9017e99f Add findInPath method to locate all matching executables in the system path (#609)
Signed-off-by: Sora Morimoto <sora@morimoto.io>
2021-04-02 12:22:30 -04:00
Thomas Boop de122731f3 Run update octokit on workflow_dispatch 2021-04-02 12:08:46 -04:00
Sora Morimoto 4dd900dde0 Replace find with which in io package description (#633)
Signed-off-by: Sora Morimoto <sora@morimoto.io>
2021-03-11 09:57:31 -05:00
Konrad Pabjan 383ec9fb03 Update deno.yml 2021-02-18 17:18:59 +01:00
Konrad Pabjan c3478210af Create deno.yml 2021-02-18 17:14:38 +01:00
dependabot[bot] 228a9534d1 Bump ini from 1.3.5 to 1.3.7 (#672)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-05 13:38:54 -05:00
Konrad Pabjan 2202465c69 actions/cache 1.0.6 release (#705) 2021-02-02 20:48:46 +01:00
Benedek Kozma ccd1dd298f Use GNU tar on macOS if available (#701)
* use GNU tar on macOS

* remove unnecessary code

* formatting fix

* fix tests

* fix more tests

* typo fix

* fix test
2021-02-02 20:09:10 +01:00
Yang Cao 825204968b Merge pull request #650 from rosik/main
Make caching more verbose
2021-01-19 15:43:18 -05:00
Robin Neatherway 85f6235ca9 Add on: pull_request trigger to CodeQL workflow (#689)
From February 2021, in order to provide feedback on pull requests, Code Scanning workflows must be configured with both `push` and `pull_request` triggers. This is because Code Scanning compares the results from a pull request against the results for the base branch to tell you only what has changed between the two.

Early in the beta period we supported displaying results on pull requests for workflows with only `push` triggers, but have discontinued support as this proved to be less robust.

See https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#scanning-pull-requests for more information on how best to configure your Code Scanning workflows.
2021-01-15 12:22:00 +01:00
Yaroslav Dynnikov bfdba95ece Make caching more verbose
- Print cache size when saving cache similarly to restoring
- Print restore success similarly to saving
- Print cached file list if debug logging is enabled

See also: https://github.com/actions/cache/issues/471
2021-01-07 23:51:43 +03:00
Konrad Pabjan c861dd8859 Retry all http calls for artifact upload and download (#675)
* Retry all http calls for artifact upload and download

* Extra debug information

* Fix lint

* Always read response body

* PR Feedback

* Change error message if patch call fails

* Add exponential backoff when retrying

* Rework tests and add diagnostic info if exception thrown

* Fix lint

* fix lint error for real this time

* PR cleanup

* 0.5.0 @actions/artifact release

* Display diagnostic info if non-retryable code is hit
2020-12-18 21:40:50 +01:00
Konrad Pabjan 73d5917a6b actions/artifact 0.4.2 release (#673)
* actions/artifact 0.4.2

* Update releases note
2020-12-11 17:43:12 +01:00
Aiqiao Yan 4e1ffd548b Merge pull request #670 from actions/aiqiaoy/path
Fix windows cache path
2020-12-10 16:00:39 -05:00
Aiqiao Yan 42b3ff04b2 Fix windows cache path 2020-12-10 10:59:04 -05:00
Josh Gross 8d11ee5a8c Add CODEOWNERS (#662)
* Add CODEOWNERS

* Update owners of tool-cache
2020-12-07 15:48:38 -05:00
Chris Sidi 7ad5004f87 Merge pull request #661 from yacaovsnc/main
Retry artifact download when response stream is truncated (continued)
2020-12-04 13:10:40 -05:00
Yang Cao b593d1deb4 Close destination steam before reject
Co-authored-by: Chris Sidi <hashtagchris@github.com>
2020-12-04 11:03:17 -05:00
Yang Cao 5be846b72d style change, refactor arg sequence 2020-12-04 09:41:00 -05:00
Yang Cao dc491a61ca pipeResponseToFile already throws when reading truncated stream 2020-12-04 09:19:58 -05:00
Yang Cao a600dd34a5 Try close stream before unlink 2020-12-03 13:34:59 -05:00
Yang Cao d4e990d92f Always print skip validation log 2020-12-03 13:09:43 -05:00
Yang Cao 05b1692026 Add some debugging statements 2020-12-03 12:40:37 -05:00
Yang Cao 8ed9455d68 More styling fix 2020-12-03 10:57:04 -05:00
Yang Cao b55731c11b Fix styling 2020-12-03 10:33:10 -05:00
Yang Cao 6b83f0554a Adding retry when we received 200
If we received 200, we will attempt to download the stream. If the
stream is gzipped, gzip should throw an error when trying to decompress
the stream; or if the stream is truncated, the received bytes should be
different from the value set in content-length header.
2020-12-03 10:15:12 -05:00
Chris Sidi 990647a104 More error handling 2020-12-03 10:12:44 -05:00
Chris Sidi 520206f818 Retry artifact download when response stream is truncated 2020-12-03 10:12:44 -05:00
Chris Sidi ff4308098f Remove spyon, use readable stream to test pipeResponseToFile (#651)
* Remove spyon, use readable stream to test pipeResponseToFile

* Check file contents
2020-11-30 12:12:12 -05:00
Thomas Boop 2bf7365352 Update @actions/core in remaining toolkit packages (#636)
* Update to latest @actions/core version

* Bump release notes for new versions

* Add correct pr #
2020-11-13 16:51:15 -05:00
David Hadka e7eb2c7418 Merge pull request #626 from edburns/patch-1
Explain to the ignorant reader where this `STATE_` prefix comes from.
2020-11-05 08:15:00 -06:00
Ed Burns 0b69311011 Explain to the ignorant reader where this STATE_ prefix comes from.
Explain to the ignorant reader where this `STATE_` prefix comes from.
2020-11-04 13:50:18 -05:00
David Hadka 5e5e1b7aac Merge pull request #624 from actions/dhadka/upload-chunk-error
Handle non-successful responses from uploadChunk
2020-11-03 14:12:06 -06:00
Dave Hadka 5e8657cf12 Bump @actions/cache to 1.0.4 2020-11-03 13:12:34 -06:00
Dave Hadka 678f278caa Handle non-successful responses from uploadChunk 2020-11-03 09:53:44 -06:00
David Hadka f1b118b2a9 Merge pull request #558 from dhadka/dhadka/fix-error-handling
Handle errors representing non-successful http responses in retry logic
2020-10-20 09:54:21 -05:00
Dave Hadka 464aebd43b Update package version and release notes 2020-10-12 13:47:24 -05:00
Dave Hadka c3c81d44c1 Clean up test code 2020-10-12 13:28:50 -05:00
Thomas Boop af82147423 Add -Append flag to powershell workflow commands 2020-10-08 16:43:28 -04:00
Thomas Boop 4f7fb6513a swap to file commands (#587)
* swap to file commands

* swap to require
2020-09-30 15:46:54 +02:00
Konrad Pabjan 2178f0baee Documentation around colored output in logs (#583) 2020-09-24 16:38:19 +02:00
Thomas Boop a5e05630d8 Actions core 1.2.6 release (#582) 2020-09-23 12:10:51 -04:00
Thomas Boop 0759cdc230 Add File Commands (#571)
* Add File Commands

* pr updates w/ feedback

* run format

* fix lint/format

* slight update with an example in the docs

* pr feedback
2020-09-23 11:19:20 -04:00
dependabot[bot] da34bfb74d Bump node-fetch from 2.6.0 to 2.6.1 in /packages/github (#570)
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-21 09:57:23 -04:00
Yang Cao bb290885a3 Release preparation of artifact 0.4.0 (#578) 2020-09-18 19:06:53 +02:00
Yang Cao ace7a82469 Add an option to specify retention days for artifacts (#575)
* Add an option to specify retention days for artifacts

* Validate against settings exposed as env var to give early feedback

* Fix lint

* Add tests and addressing feedback

* Update packages/artifact/__tests__/upload.test.ts

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

* Update packages/artifact/README.md

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

* Update packages/artifact/src/internal/utils.ts

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

* Update packages/artifact/__tests__/util.test.ts

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2020-09-18 11:30:00 -04:00
dependabot[bot] 71b19c1d65 Bump yargs-parser from 18.1.0 to 18.1.3 in /packages/github (#566)
Bumps [yargs-parser](https://github.com/yargs/yargs-parser) from 18.1.0 to 18.1.3.
- [Release notes](https://github.com/yargs/yargs-parser/releases)
- [Changelog](https://github.com/yargs/yargs-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/yargs-parser/compare/v18.1.0...v18.1.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-10 23:36:25 -04:00
Thomas Boop c9819f79d2 Actions/core v1.2.5 release notes (#562) 2020-08-26 15:09:39 -04:00
Thomas Boop c2bc747506 Add License.md to all npm packages (#548)
* Add License.md to all npm packages
2020-08-25 16:26:50 -04:00
github-actions[bot] ea69f13737 Update Dependencies (#561)
Co-authored-by: github-actions[bot] <github-actions@github.com>
2020-08-25 13:44:55 -04:00
Ross Brodbeck 7f7e22a940 zeit renamed to vercel 2020-08-21 07:32:09 -04:00
Dave Hadka de52c861c1 Add retry delay 2020-08-17 20:28:35 -05:00
Dave Hadka 1ef26b2390 Handle errors representing non-successful http responses in retry logic 2020-08-17 15:10:51 -05:00
Sora Morimoto 9ad01e4fd3 Use posix archive format (#533)
* Use posix archive format

Signed-off-by: Sora Morimoto <sora@morimoto.io>

* Update package.json and RELEASES.md

Signed-off-by: Sora Morimoto <sora@morimoto.io>
2020-08-05 17:17:23 +02:00
Konrad Pabjan 6c5508d1fb @actions/artifact 0.3.5 2020-08-04 17:11:50 +02:00
Konrad Pabjan b2cba168a2 Retry on 413 (#540) 2020-08-04 16:57:38 +02:00
Thomas Boop e3c6237940 Update audit.yml 2020-08-03 16:55:53 -04:00
github-actions[bot] fc28be88e4 Update Dependencies (#536)
Co-authored-by: github-actions[bot] <github-actions@github.com>
2020-08-03 11:40:36 -04:00
Konrad Pabjan 905b2c7b06 @actions/artifact 0.3.3 update 2020-07-30 17:30:41 +02:00
Konrad Pabjan 3a9dc00629 Better Artifact Telemetry + Increase Upload chunk size (#535)
* Differentiate user-agents for better internal telemetry

* Bump chunk size from 4 to 8 MB

* Update User-Agent Strings
2020-07-30 17:23:28 +02:00
Thomas Boop ccad19055e Set main as the default branch (#527)
* set main as the default branch

* revert change to tool-cache default branch

* use versions where applicable
2020-07-21 11:33:05 -04:00
Aiqiao Yan cb18a3df6b Merge pull request #528 from dhadka/dhadka/fix-download-calc
Fix bug downloading large files with the Azure SDK
2020-07-21 10:32:24 -04:00
Dave Hadka 781092b1d1 Fix bug downloading large files with the Azure SDK 2020-07-20 15:36:34 -05:00
github-actions[bot] 1cc56db0ff Update Dependencies (#526)
Co-authored-by: github-actions[bot] <github-actions@github.com>
2020-07-20 10:38:14 -04:00
dependabot[bot] 0bf9897205 Bump lodash from 4.17.15 to 4.17.19 (#524)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-16 16:56:22 -04:00
dependabot[bot] b152907c1f Bump lodash from 4.17.15 to 4.17.19 in /packages/github (#522)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-16 15:54:18 -04:00
Thomas Boop 8f6ddeb087 Tool cache 1.6.0 Release Notes (#519)
* Tool-cache 1.6.0 release notes

* Adjust spacing
2020-07-16 15:46:02 -04:00
Thomas Boop 32f15666bd Fix Issue where we can no longer create zip files on windows during cli tests. (#520)
* Try using pwsh instead of powershell
* Fallback to powershell
* Format files correctly
2020-07-16 11:51:00 -04:00
Frederik Wallner 2710592b73 tool-cache: Support for extracting xar compatible archives (#207)
* Test xar extraction

* Support for extracting xar compatible archives

* Only allow extractXar on mac

* Create xar during test instead of using prebuilt

* Update lockfiles

* Add verbose flag if debug

* Add extractXar example to readme

* Revert "Update lockfiles"

This reverts commit a6cbddccf6.

* Use node pkg in example

* Remove and ignore prebuilt xar

* Tests for non-existing dir and without flags

* Better arguments handling

* Make sure that target directory exists

Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
2020-07-15 14:49:23 -04:00
Thomas Boop 7e1c59c51e Update email in octokit upgrade job (#516) 2020-07-14 16:46:07 -04:00
Thomas Boop 95a10d23fa Pipe audit results to a json file so lerna does not overflow (#515)
* Pipe audit results to a json file so lerna does not overflow

* reorder flags and args
2020-07-14 16:05:53 -04:00
Aiqiao Yan 8fdeff41f3 Merge pull request #513 from dhadka/dhadka/download-progress
Display download progress when using Azure Storage SDK
2020-07-14 10:26:43 -04:00
Dave Hadka c4a92b0b60 Update with reviewer feedback 2020-07-13 16:09:37 -05:00
Dave Hadka cc474239c9 Display download progress 2020-07-13 12:46:34 -05:00
David Hadka 4964b0cc7c Use Azure storage SDK to download cache (#497)
* Adds option to download using AzCopy

* Bump version number and add release notes

* Ensure we use at least v10

* Negate env var so it disables AzCopy

* Use Azure storage SDK to download cache

* Use same level of parallelism as AzCopy

* Fix naming of variable

* React to feedback

* Bump Node types to Node 12

* Make linter happy

* Pass options into restoreCache method

* Fix tests

* Restructure files and add tests

* Add method to get the default download and upload options

* Include breaking changes in RELEASES.md

Co-authored-by: Josh Gross <joshmgross@github.com>
2020-07-10 17:09:32 +02:00
github-actions[bot] cee7d92d1d Update Dependencies (#509)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2020-07-06 16:36:08 -04:00
Thomas Boop ea503a235e Add release notes for actions/github 4.0.0 (#507)
* Add release notes for 4.0.0
2020-06-26 13:42:57 -04:00
839 2d47f7b7f6 Add execution state information (#499)
* Add execution state information (#371)

* Type conformance to REST API (#371)

* Changed to get the job name (#371)
2020-06-25 23:25:13 -04:00
Thomas Boop 7a1a0dd6fc Add core.info to Logging section 2020-06-24 10:48:13 -04:00
David Hadka 9e2d61e548 Delete cache folders prior to restore in tests (#486)
* Delete cache folders prior to restore in tests

* Update cache-tests.yml
2020-06-19 14:43:38 -04:00
Aiqiao Yan 66931ff481 Update cache readme to include a link to cache action (#478)
Co-authored-by: Aiqiao Yan <aiqiaoy@aiqiaos-mbp.attlocal.net>
2020-06-19 14:43:10 -04:00
Thomas Boop 8e14ff9f0a Setup Weekly Automation to Update @actions/github (#498)
* create automation to update Octokit for actions toolkit

Co-authored-by: Dependency Update Bot <bot@github.com>
Co-authored-by: Shohei Ueda <30958501+peaceiris@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2020-06-19 14:35:19 -04:00
Thomas Boop 3e40dd39cc Explicitly exclude DS store files (#492) 2020-06-04 15:14:19 -04:00
Thomas Boop c65fe87e33 Minor readme clarification 2020-06-03 13:51:19 -04:00
Ryo Ota d4340966b7 Add type of context.payload.comment (#375) 2020-06-03 11:54:01 -04:00
Thomas Boop d69e699ab9 Update release information for @actions/github 3.0.0 (#489) 2020-06-03 10:12:22 -04:00
Thomas Boop 4a89cf72de @actions/github v3 using Octokit/core (#453)
* Rebuild to use @Octokit/Core
2020-06-02 21:39:46 -04:00
Thomas Boop 9ba7c679ad Update Save State Docs (#467)
* Update Save State Docs
2020-05-27 10:40:32 -04:00
Sora Morimoto c94bc40d84 Remove unnecessary trailing spaces (#474) 2020-05-27 10:33:23 -04:00
Sora Morimoto 8ae8acce72 Update unit-tests.yml (#477) 2020-05-27 10:32:54 -04:00
Aiqiao Yan 30e0a77337 Merge pull request #471 from actions/aiyan/minor-edit
Fix a bug with getCompressionMethod and minor edit to release note
2020-05-19 16:42:40 -04:00
Aiqiao Yan 44a99f6c43 Add section for 0.2.1 2020-05-19 16:36:18 -04:00
Aiqiao Yan f84d1a2ae2 Fix a bug with getCompressionMethod 2020-05-19 16:12:28 -04:00
Thomas Boop 2c693984a8 Update Bug Report Template (#466) 2020-05-19 13:43:20 -04:00
Bryan MacFarlane f4aa824135 bump tool-cache version 2020-05-19 13:38:19 -04:00
Bryan MacFarlane 4e9375da09 Tool cache install from a manifest file (#382) 2020-05-19 13:25:57 -04:00
Aiqiao Yan e3a666f5b7 Minor edit to cache release note 2020-05-19 13:20:27 -04:00
Aiqiao Yan dcf5c88bb3 Merge pull request #469 from actions/users/aiyan/zstd-fixes
Fix two issues related to using zstd compression
2020-05-19 13:05:21 -04:00
Aiqiao Yan 0dea61a3a8 Bump cache package version 2020-05-19 12:59:38 -04:00
Aiqiao Yan fde6221228 React to feedback 2020-05-19 12:38:45 -04:00
Aiqiao Yan 9a3466a094 Fix windows tests 2020-05-19 11:46:50 -04:00
Aiqiao Yan 5112dc231e Only use zstd on windows when gnu tar is installed, otherwise use gzip due to bug #301 2020-05-18 16:35:13 -04:00
Aiqiao Yan 77761a4dc9 Fix issue with using zstd long range mode on ubuntu-16.04 2020-05-18 16:33:15 -04:00
Aiqiao Yan a67b91ea15 Merge pull request #448 from actions/users/aiyan/cache-package
Initial commit to create @actions/cache package
2020-05-15 13:41:32 -04:00
Konrad Pabjan 2fdf3b71f8 @actions/artifact 0.3.2 2020-05-15 18:34:09 +02:00
Aiqiao Yan d2b2399bd2 React to feedback 2020-05-15 12:26:42 -04:00
Konrad Pabjan 628f82f221 Correctly reset chunk during artifact upload on retry (#458)
* Correctly reset chunk during artifact upload on retry

* Update workflow

* Implementation details around the passthrough stream
2020-05-14 22:18:21 +02:00
Konrad Pabjan 6d83c79964 Remove --save in README (#455) 2020-05-14 17:58:46 +02:00
Thomas Boop 36e732155e tool-cache 1.3.5 release (#454)
* tc 1.3.5 release
2020-05-13 14:39:10 -04:00
Aiqiao Yan b3c8e19a7a Attempt to fix the test 2020-05-13 13:43:13 -04:00
Aiqiao Yan 1413cd0e32 Add cache upload options and pull from latest actions/cache master 2020-05-12 12:53:45 -04:00
Aiqiao Yan c534ad2cbd Add docs and tests 2020-05-12 12:02:19 -04:00
Aiqiao Yan 15fefd9336 Fix tests 2020-05-12 12:02:18 -04:00
Aiqiao Yan 7409ad5fae Change variable path to a list 2020-05-12 12:02:18 -04:00
Aiqiao Yan 932779cf58 Initial commit to create @actions/cache package 2020-05-12 12:02:18 -04:00
Konrad Pabjan 0471ed4ad7 artifact header cleanup (#441)
* Update NPM packages for @actions/artifact

* Clarifications around headers

* Revert NPM updates

* Apply suggestions from code review

Co-authored-by: Josh Gross <joshmgross@github.com>

Co-authored-by: Josh Gross <joshmgross@github.com>
2020-05-12 17:48:36 +02:00
Kevin Sawicki d1b52e7168 Update homepage to be tool-cache instead of exec (#452) 2020-05-12 10:22:22 -04:00
eric sciple 83dd3ef0f1 separate audit workflow (#450) 2020-05-07 11:39:38 -04:00
Thomas Boop a5ff692285 Redirect general feedback to the Community Forums (#447) 2020-05-07 10:24:11 -04:00
eric sciple 264e52add6 set base URL for GHES (#449) 2020-05-07 09:41:18 -04:00
Justin Hutchings 11dcc8b313 Add CodeQL Analysis workflow (#434)
* Add CodeQL Analysis workflow

* Rename .github/workflows/workflows/codeql.yml to .github/workflows/codeql.yml

* Remove autobuilder

* Add back autobuilder

* Disable c# analysis
2020-05-06 12:58:36 -04:00
dependabot[bot] 6a744be7ed Bump @actions/http-client from 1.0.3 to 1.0.8 in /packages/github (#438)
Bumps [@actions/http-client](https://github.com/actions/http-client) from 1.0.3 to 1.0.8.
- [Release notes](https://github.com/actions/http-client/releases)
- [Changelog](https://github.com/actions/http-client/blob/master/RELEASES.md)
- [Commits](https://github.com/actions/http-client/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-05-01 09:46:19 -04:00
Thomas Boop 94cd8efa47 Ignore DS_Store files. (#440)
* Ignore DSStore Files

* Simplify Ignore for DS_Store
2020-05-01 09:42:38 -04:00
dependabot[bot] 97cabf0eb9 Bump @actions/http-client from 1.0.7 to 1.0.8 in /packages/artifact (#437)
Bumps [@actions/http-client](https://github.com/actions/http-client) from 1.0.7 to 1.0.8.
- [Release notes](https://github.com/actions/http-client/releases)
- [Changelog](https://github.com/actions/http-client/blob/master/RELEASES.md)
- [Commits](https://github.com/actions/http-client/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-05-01 11:32:41 +02:00
Thomas Boop 187d4aa625 @actions/core 1.2.4 + release notes (#439) 2020-04-30 09:48:16 -04:00
Arthur Baars 57d20b4db4 tool-cache: make extract functions quiet by default and more verbose if core.isDebug is set (#206)
* tool-cache: make unzip and 7z extract quiet by default

This avoids spamming the log when unzipping large archives.

* tool-cache: make tar, unzip and 7z verbose when `core.isDebug`

Make the extract function print the list of extracted file if
the action is run in debug mode.
2020-04-29 11:33:01 -04:00
Bryan MacFarlane 4e734dc4c1 bump exec version 2020-04-28 11:59:04 -04:00
Reinier Timmer 34f71e80ce Check if tool path exists before executing (#385) 2020-04-28 10:36:49 -04:00
Konrad Pabjan 1e88dec883 Update ts-jest to latest versions (#419) 2020-04-27 17:17:31 +02:00
Josh Soref 7257597d73 Spelling (#431)
* spelling: absolute

* spelling: content

* spelling: received

* spelling: sanitizes
2020-04-27 09:13:56 -04:00
per1234 df7e2c13c8 Fix broken links in documentation (#425) 2020-04-24 11:55:31 +02:00
Bryan MacFarlane eec6689a61 bump tool-cache's http-client to 1.0.8 (#429) 2020-04-23 21:12:00 -04:00
Konrad Pabjan 1688b117e1 E2E tests for the @actions/artifact package (#421)
* End-to-end artifact tests

* E2E tests for artifact package
2020-04-23 20:52:53 +02:00
Konrad Pabjan bb1053a8a7 @actions/artifact 0.3.1 update (#420)
* Updates to 0.3.1 package update
2020-04-20 22:58:53 +02:00
Pierre Grimaud a28977e977 Fix typos (#417) 2020-04-20 12:56:03 +02:00
Seth Vargo c4b6011310 Allow specifying stdin (#360)
* Allow specifying stdin
2020-04-13 13:39:42 -04:00
Thomas Boop 05e39f551d Add docs and wrapper for "echo" command (#411)
* Add docs and wrapper for "echo" command

* Update parameter to enabled
2020-04-13 13:25:54 -04:00
Thomas Boop 3c125ce4e0 Update eslint to 2.2.7 (#410) 2020-04-13 10:19:49 -04:00
Thomas Boop 5b940ebda7 Be more lenient in accepting command inputs (#405)
* Be more lenient in accepting command inputs
2020-04-09 17:00:53 -04:00
Linda_pp a6a5d98be8 Expose ExecOptions interface (#322) 2020-04-09 12:52:24 -04:00
Konrad Pabjan c010a271d9 @actions/artifact package updates (#408)
* Clear error message when storage quota has been hit

* Improved download of empty files

* Extra info to RELEASES.md

* PR Feedback
2020-04-09 17:14:12 +02:00
Konrad Pabjan 1b521c4778 Updates to @actions/artifact (#396)
* Add support for 429s and Exponential backoff

* Refactor status-reporter so it can be used with download and upload

* Extra logs

* Fixes around download & gzip

* Cleanup headers and add extra tests

* Improved Docs

* Spelling bloopers

* Improved error messages

* User http client version 1.0.7
2020-04-08 16:55:18 +02:00
Brian Cristante 36a4b7df61 Add screenshot to release instructions (#406) 2020-04-07 09:42:56 -04:00
Konrad Pabjan 905c2aa216 Contribution guidelines for artifact package (#388)
* Contribution guidelines
* PR Feedback
2020-03-24 10:13:06 +01:00
Konrad Pabjan cb7022ea2c Update implementation-details.md 2020-03-20 18:42:18 +01:00
Konrad Pabjan b94f6a1340 Update additional-information.md 2020-03-19 15:56:27 +01:00
Thomas Boop 12f30111a0 Update Contributing.md and add information about ADR's (#383)
* Updating Contributing.md + add adr details
2020-03-17 11:57:32 -04:00
eric sciple 17b97eceec adr: glob (#381) 2020-03-16 16:08:48 -04:00
Konrad Pabjan b0e01b71c0 Update package-lock.json 2020-03-12 20:39:10 +01:00
Konrad Pabjan 3748609c73 Update package.json 2020-03-12 20:36:46 +01:00
Konrad Pabjan 37590cb3ee Update RELEASES.md 2020-03-12 20:36:09 +01:00
Konrad Pabjan dffb5572a9 Updates to @actions/artifact package (#367)
* GZip implementation

* Optimizations and cleanup

* Update tests

* More test updates

* Update packages/artifact/src/internal-utils.ts

Co-Authored-By: Josh Gross <joshmgross@github.com>

* Clarification around Upload Paths

* Refactor to make http clients classes

* GZip fixes

* Documentation around compression

* More detailed status information during large uploads

* Pretty format

* Percentage updates without rounding

* Fix edge cases with formatting numbers

* Update packages/artifact/src/internal-utils.ts

Co-Authored-By: Josh Gross <joshmgross@github.com>

* Cleanup

* Small reorg with status reporter

* PR Feedback

* Cleanup + Simplification

* Test Cleanup

* Mock updates

* More cleanup

* Format fixes

* Overhaul to the http-manager

* Fix tests

* Promisify stats

* Documentation around implementation

* Improvements to documentation

* PR Feedback

* Remove Downloading multiple artifacts concurrently

Co-authored-by: Josh Gross <joshmgross@github.com>
2020-03-12 14:50:27 +01:00
eric sciple 5859d7172e only retry downloadtool on 500s and 408 and 429 (#373) 2020-03-09 14:35:53 -04:00
Thomas Boop 82fbe5da0f Update jest to 25.1 (#374)
* Update jest to 25.1

* Update acorn to 6.4.1

* Update dependencies, run audit on all packages, update packagelock

* Remove package-lock dependencies
2020-03-09 14:17:29 -04:00
eric sciple df0aa9077a generated 2020-03-05 12:07:25 -05:00
eric sciple 259743ae13 update downloadTool to handle errors from response stream and retry (#369) 2020-03-05 12:05:27 -05:00
Bryan MacFarlane 6459481e98 full sha binding in versioning doc 2020-03-03 11:16:15 -05:00
Bryan MacFarlane 3261dd9883 core 1.2.3 release (#366) 2020-03-02 08:02:40 -05:00
Tingluo Huang a649207792 Add core.isDebug() to check whether actions_step_debug is on or not. (#278) 2020-03-02 07:45:27 -05:00
Josh Gross 54bcb7c4f1 Update tool cache docs (#347) 2020-02-26 11:43:55 -05:00
Konrad Pabjan d17d4a9163 Add info about new @actions/artifact package 2020-02-20 15:05:07 -05:00
Thomas Boop 41157b23c7 Release 2.1.1 of @actions/github (#357) 2020-02-20 14:02:42 -05:00
Ryo Ota fa03eb4d22 Use import {Octokit} (#332)
* Use import {Octokit}

* Update @octokit/rest to 16.43.1
2020-02-18 15:43:07 -05:00
Konrad Pabjan f383109dc3 @actions/artifact download artifacts (#340)
* Download Artifacts using @actions/artifact
2020-02-13 18:24:11 -05:00
eric sciple 84f1e31b69 send tar --version to debug log (#342) 2020-02-13 09:54:56 -05:00
eric sciple f90a2dcfd4 temporarily revert guidance for adding matcher from container action 2020-02-12 21:42:14 -05:00
eric sciple 9cfb1604bd troubleshooting problem matchers (#341) 2020-02-12 14:59:01 -05:00
Bryan MacFarlane 2dcdf049a8 proxy guidance 2020-02-12 09:26:59 -05:00
Konrad Pabjan 6cbb8e9bc8 @actions/artifact package (#304)
* Initial commit for @actions/artifact package
2020-02-11 09:49:46 -05:00
Fabio Niephaus 0ecc141d4e await tc.downloadTool (#337) 2020-02-09 22:15:26 -05:00
eric sciple 432a78c48c check proxy bypass before setting proxy agent (#320) 2020-01-23 14:35:41 -05:00
Thomas Boop 80e6ba7033 Update readme with type assertion information (#310)
* Update readme with type assertion information

* PR updates
2020-01-22 11:53:39 -05:00
eric sciple 6072c249ee release notes (#317) 2020-01-21 13:25:05 -05:00
Thomas Boop a9175f3986 Correctly pull issue number for pull request review events (#311) 2020-01-21 10:44:38 -05:00
eric sciple 8b0300129f fix command escaping (#302) 2020-01-18 23:52:44 -05:00
eric sciple ab5bd9d696 octokit client should follow proxy settings (#314) 2020-01-18 14:28:37 -05:00
eric sciple e69833ed16 release notes (#308) 2020-01-14 11:58:44 -05:00
eric sciple 461fc2b9c9 bump checkout to v2, pin setup-node to v1 (#277) 2020-01-14 11:19:06 -05:00
sullis c514e7481a GitHub Actions checkout v2 (#303) 2020-01-14 10:48:34 -05:00
Bryan MacFarlane 2e88402d19 audit fix and update http-client (#298) 2020-01-10 16:37:48 -05:00
eric sciple 058ad6937d remove todo comment (#297) 2020-01-10 12:09:48 -05:00
eric sciple dd64d8c7c9 glob readme (#296) 2020-01-10 12:00:22 -05:00
eric sciple 947ba5b559 bump versions (#295) 2020-01-09 17:31:27 -05:00
eric sciple 03ebc5b885 generated file (#294) 2020-01-09 15:26:22 -05:00
eric sciple 1a2c592903 multiple glob patterns (#287) 2020-01-09 15:05:31 -05:00
Bryan MacFarlane 683245ad5e bump default test timeout 2020-01-07 01:14:32 -05:00
Bryan MacFarlane bfd29dcef8 only audit on ubuntu-latest (#283) 2020-01-04 14:08:05 -05:00
Bryan MacFarlane 803934eca0 audit security vulnerabilities as part of ci (#280) 2020-01-03 17:54:10 -05:00
francisfuzz 4e69ce10e9 package-lock.json: update handlebars & uglify-js (#279) 2020-01-03 15:26:02 -05:00
eric sciple a11539e1db glob (#268) 2019-12-31 10:16:18 -05:00
dependabot[bot] a94e2440cb Bump handlebars from 4.1.2 to 4.5.3 in /packages/github (#276)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-27 19:48:20 -05:00
Josh Gross 8a4134761f Update to latest typescript version (#274) 2019-12-27 19:42:30 -05:00
Josh Gross 60d3096c71 Only run CI on PRs and pushes to master (#275) 2019-12-26 17:00:18 -05:00
Josh Gross 5feb835dff Fix broken doc links (#273) 2019-12-23 15:52:20 -05:00
eric sciple e7cbd693eb fix extractTar on Windows (#264) 2019-12-19 10:44:08 -05:00
eric sciple 81bdf00982 fix Buffer deprecation warnings (#265) 2019-12-18 13:24:01 -05:00
eric sciple 568f12cee6 remove trailing comma from commands (#263) 2019-12-18 13:23:16 -05:00
eric sciple f79897266e fix errors during npm install (#262) 2019-12-17 12:48:13 -05:00
Yusuke Sakurai 606e1f27ac add: "types" to each package.json (#221)
fix es #148
2019-12-17 11:03:58 -05:00
eric sciple 895bdd6dd5 remove misleading verbiage (#258) 2019-12-16 12:43:21 -05:00
eric sciple 61d502068b overload downloadTool to accept destination path (#257) 2019-12-16 11:59:48 -05:00
eric sciple 17acd9c66f update problem matchers doc for fromPath and default severity (#256) 2019-12-14 10:11:59 -05:00
Bryan MacFarlane d4975510fe update illustration 2019-12-12 14:30:31 -05:00
Bryan MacFarlane 871c495487 update versioning docs for new major versions 2019-12-12 14:21:22 -05:00
Bryan MacFarlane 40a502b14b added matchers to readme 2019-12-12 13:43:34 -05:00
Adam Dobrawy fc45b70f30 Remove draft-only comments from README (#215) 2019-12-11 18:07:02 -05:00
Daniel Anechitoaie 9f6c37ac52 Updated tc.cacheFile example (#226) 2019-12-11 18:05:18 -05:00
Barret Schloerke 80e91ee891 Fix typo (#250) 2019-12-11 18:03:17 -05:00
TriangularIT bedf824517 Small typo (#251) 2019-12-11 18:02:44 -05:00
Peter Evans be9f18b69f Fix documentation links (#217) 2019-12-10 09:11:03 -05:00
Tony Brix 1d7e38e56d fix unzip error (#223) 2019-12-09 14:26:48 -05:00
Bryan MacFarlane aa13e110b1 update illustration 2019-12-09 14:02:57 -05:00
eric sciple 15033a1aed commit package-lock.json 2019-12-09 11:21:43 -05:00
Bryan MacFarlane cd47f1e123 update versioning diagram 2019-12-08 14:34:25 -08:00
Bryan MacFarlane 0f1fef3752 versioning update (#246) 2019-12-07 14:26:07 -08:00
Ross Brodbeck 5fdab2aaf2 Update octokit graphql type dependencies (#228)
* Update GraphQL support in base API
2019-12-06 07:52:04 -05:00
eric sciple 1c12ced7ba bump patch version (#239) 2019-12-04 11:03:36 -05:00
eric sciple 211b25966b Unit test (#236) 2019-12-03 14:18:54 -05:00
Ross Brodbeck d98e55434d Fix test timeouts (#235)
* Fix test timeouts
2019-12-03 13:55:39 -05:00
eric sciple 5c894298f2 toolrunner should which tool before invoking (#220) 2019-11-18 16:20:01 -05:00
Jan Jurzitza 9a3c005162 Clarify that extractTar extracts gzipped tars (#134)
The default downloadTool implementation strips the filename so when passing it to the extractTar function, it doesn't have a way of knowing the format without manually specifying it. However what the extractTar function arguments meant and how to specify them wasn't clear before reading the source code, so the documentation here got updated to reflect that.
2019-11-15 16:12:36 -05:00
Brian Surowiec 225370fc48 Fix remove-matcher syntax (#211) 2019-11-15 16:02:47 -05:00
eric sciple 28a7970270 Merge pull request #212 from actions/users/ericsciple/m161warnings
Update jest and lerna to fix npm install warnings
2019-11-12 12:20:32 -05:00
eric sciple 6c824bd448 Update jest and lerna to fix npm install warnings 2019-11-12 12:13:32 -05:00
Thomas Boop 47357ddfee Document Problem Matcher Commands (#198)
* Add Initial Problem Matcher docs
2019-11-06 16:24:16 -05:00
Josh Gross a465bf5e6d Fix slash in example release branch 2019-11-06 10:16:13 -05:00
Jim Hester 0fbdc19f81 Fix typo (#201) 2019-11-06 10:15:14 -05:00
Bryan MacFarlane 4f11810a00 doc tweak 2019-11-03 14:35:12 -05:00
Josh Gross 46c2a7e41a Fix some typos (#200) 2019-11-03 14:32:46 -05:00
Bryan MacFarlane 626bbe7136 doc tweak 2019-11-03 12:34:23 -05:00
Bryan MacFarlane 1e5fc20bfe update versioning guidance 2019-11-03 12:24:13 -05:00
Thomas Boop a9ebfb1a78 Add Warning about multiline secrets (#196) 2019-11-01 10:05:01 -04:00
Thomas Boop 4a3fe0bcd3 Quote the Commands in order to process on default windows (#191) 2019-10-23 11:06:34 -04:00
Thomas Boop 3d556ddb81 Overwrite tag rather then delete and create (#190) 2019-10-21 16:14:05 -04:00
Bryan MacFarlane a65441cf46 bump core for release and docs (#189) 2019-10-18 15:35:13 -04:00
Manuel Muñoz Solera 565d0bbe18 Adding missing curly Brace in Usage example (#150) 2019-10-14 10:59:46 -04:00
Josh Gross e8d384d3af Merge pull request #149 from actions/users/tihuang/statecommand
add core method to saveState and getState.
2019-10-10 20:04:39 -04:00
Josh Gross 55b188b8c6 Merge pull request #179 from dguo/patch-1
Fix a setup-node warning
2019-10-10 10:25:49 -04:00
Danny Guo 747fa4805a Fix a setup-node warning
setup-node currently outputs:

##[warning]Input 'version' has been deprecated with message: The version property will not be supported after October 1, 2019. Use node-version instead
2019-10-10 08:02:02 -04:00
Bryan MacFarlane 9c0a43bda4 Update issue templates 2019-10-09 09:17:19 -04:00
Bryan MacFarlane e984b2b6bb updating readmes 2019-10-09 09:16:07 -04:00
Bryan MacFarlane c2bb007435 Update issue templates 2019-10-09 09:09:24 -04:00
Bryan MacFarlane 2e4712de6f updating readmes 2019-10-09 08:47:27 -04:00
Tingluo Huang ae706665a1 PR feedback. 2019-10-03 14:48:21 -04:00
Bryan MacFarlane 7b46e3ab34 update readme 2019-10-03 13:51:11 -04:00
Bryan MacFarlane b2151226b6 update workflow paths 2019-10-03 13:07:22 -04:00
Bryan MacFarlane 1643ea2734 update readme 2019-10-03 12:45:11 -04:00
Tingluo Huang 5ce4932391 update doc. 2019-10-03 00:41:30 -04:00
Edward Thomson a1c30dfc53 Add a bug report issue template (#160)
Provide an issue template that will help people locate the GitHub Community forum for GitHub Actions.
2019-10-02 18:17:33 -04:00
Bryan MacFarlane f210cdb256 Update readme (#178)
Updating readme
2019-10-02 17:59:33 -04:00
Bryan MacFarlane 531da1858f fix test timeout (#176)
* fix test timeout
2019-10-02 08:18:38 -04:00
Bryan MacFarlane 9d54cd22ea setSecret (#174)
* setSecret
2019-10-01 17:13:05 -04:00
Bryan MacFarlane 713902387e updating core docs and bumping version (#172)
updating core docs and bumping version
2019-10-01 13:53:09 -04:00
Thomas Boop 05b1b08f77 Update command docs to specify a new line is needed (#171) 2019-10-01 12:56:09 -04:00
Harry Marr 47ccfea021 Add 'repository.directory' to package manifests (#143) 2019-09-24 22:30:51 -04:00
Chad Schulz 46bd5e54fd Wrap example in async function (#157)
As someone not too familiar with async/await JavaScript, I was hung up on this for a bit. If this is too distracting from the example itself, I can understand not integrating it.
2019-09-24 22:27:50 -04:00
Bryan MacFarlane 14ac06ecd8 endgroup typo 2019-09-24 22:14:11 -04:00
Bryan MacFarlane 9b019476db update commands doc 2019-09-24 21:08:02 -04:00
Bryan MacFarlane 1f7964519a bump tool-cache version 2019-09-24 17:20:01 -04:00
Bryan MacFarlane 67eeeea9fa use zip and unzip from path (#161) 2019-09-24 17:07:08 -04:00
Chad Schulz 3116829a9b Add missing } to token example (#153) 2019-09-24 13:49:32 -04:00
Even Alander 547d771ca3 Error in yaml (#158)
The word `you're` in the yaml example made the parsing fail, which baffled me for a while. One fix is to use `"` quotes.
2019-09-24 13:49:11 -04:00
Bryan MacFarlane 4897b2cd3b update typescript walkthrough link 2019-09-21 10:44:36 -04:00
Tingluo Huang 81b71dc6e6 fix lint. 2019-09-19 22:18:51 -04:00
Tingluo Huang 4d15218252 fix lint. 2019-09-19 22:14:12 -04:00
Tingluo Huang b62614fa25 add core method to saveState and getState. 2019-09-19 22:02:45 -04:00
Bryan MacFarlane e2358e2973 update core releases.md 2019-09-18 14:47:11 -04:00
Danny McCormick 14d6a0a2d2 Implement set-secret (#141)
* Implement set-secret

* Update RELEASES.md

* Feedback
2019-09-18 14:25:05 -04:00
Marc Nuri 6fcaac5046 actions/toolkit#127: getInput supports variables with multiple spaces (#129)
* actions/toolkit#127: getInput supports variables with multiple spaces

* actions/toolkit#127: PR comment, update changelog
2019-09-12 13:41:11 -04:00
Warren Buckley b297969f56 Update readme to show how to use the secret GITHUB_TOKEN (#131)
* Update readme to show how to use the secret GITHUB_TOKEN

* Adds in link to docs - which I feel seem to be scattered in repos & official docs
2019-09-12 10:50:19 -04:00
Bryan MacFarlane da04d22321 new template doc links 2019-09-11 03:35:39 -04:00
abelsquidhead 5fd70ca47a step 1. was slightly confusing. For someone that doesn't use git all the time, they might not know they need to go into the .gitignore file. The first time I read this I thought the direction was saying to rename the directory !node_modeules (#125) 2019-09-09 12:01:19 -04:00
Danny McCormick 2c6d31be8f Create commands.md (#105)
* Create commands.md

* Feedback

* Update action-debugging.md
2019-09-09 11:58:49 -04:00
Danny McCormick b3bf422391 Update RELEASES.md 2019-09-09 11:58:37 -04:00
damccorm 4ff3b554b8 Fix tests 2019-09-09 11:57:17 -04:00
Danny McCormick 3dcd65e44b Add github context getting started docs (#80)
* WIP - Add github context getting started docs

* Add testing docs

* Update walkthrough after going through it

* Clean up

* Add markdown types

* Env disclaimer

* Fix broken link to Javascript Action (#103)
2019-09-09 11:52:50 -04:00
Danny McCormick ef4525e9dd Add info for completeness (#111)
* Add info for completeness

* Linting

* Missing import
2019-09-09 11:46:48 -04:00
Danny McCormick a6e7249776 Update to use :: instead of ## (#110)
* Update to use :: instead of ##

* Missed test
2019-09-09 11:46:17 -04:00
Jonathan Leitschuh b529540e0c Don't recommend the use of HTTP to download code (#120) 2019-09-09 09:39:43 -04:00
abelsquidhead f689e65c54 added file name of action.yml file. When first starting out, everything is confusing and a first time actions creator might not know which file to update (#122) 2019-09-07 20:39:41 -04:00
Danny McCormick 7bc0d5222f Need right push target (#119) 2019-09-06 12:50:52 -04:00
Danny McCormick 7f17a6e550 Update RELEASES.md 2019-09-05 16:04:32 -04:00
Danny McCormick 6160df50dc Update RELEASES.md 2019-09-05 13:27:22 -04:00
Jonathan Clem a2ab4bcf78 Publish
Main workflow / Run macOS (push) Has been cancelled
Main workflow / Run Windows (push) Has been cancelled
Main workflow / Run Ubuntu (push) Has been cancelled
- @actions/core@1.1.0
 - @actions/exec@1.0.1
 - @actions/github@1.1.0
 - @actions/io@1.0.1
 - @actions/tool-cache@1.1.1
2019-09-05 11:03:19 -04:00
Jonathan Clem 7772d5f810 Merge pull request #113 from actions/client-options
Accept Octokit.Options in the GitHub constructor
2019-09-05 10:58:15 -04:00
Jonathan Clem 1c4866fa48 Add note about constructor options 2019-09-05 10:52:34 -04:00
Jonathan Clem ebace7edd3 Bump TypeScript to 3.6.2 2019-09-05 10:03:10 -04:00
Jonathan Clem e533651251 Accept Octokit.Options in the GitHub constructor 2019-09-05 09:54:27 -04:00
Jonathan Clem eb4c32847c Merge pull request #98 from actions/core-debug
Core debug
2019-09-05 09:47:05 -04:00
Bryan MacFarlane 020f7034f4 JavaScript walk through update (#107)
* update walkthrough

* review feedback
2019-09-04 17:30:45 -04:00
damccorm 2a1b7d5c7e Merge branch 'master' of https://github.com/actions/toolkit 2019-09-04 14:04:40 -04:00
damccorm eaba9217f8 Bump package version 2019-09-04 14:04:31 -04:00
Danny McCormick f2d01998f0 Update RELEASES.md 2019-09-03 14:42:04 -04:00
Danny McCormick 99d3ad0a64 Use readFileSync instead of require (#101)
* Use readFileSync instead of require

* error handling
2019-08-30 13:02:45 -04:00
Guillaume Clochard ac36ca4405 Small fix for the tool-cache extract example (#99)
* Fix tool-cache extract example

* Use extractZip or extract7z in tool-cache example fix
2019-08-29 11:08:06 -04:00
Jonathan Clem 92e6443cf0 End group in core.group regardless of error thrown 2019-08-28 22:47:37 -04:00
Jonathan Clem 8f9992ca17 Add assertion for return value of core.group 2019-08-28 22:38:30 -04:00
Jonathan Clem 80fc75ef9c Fix readme 2019-08-28 22:36:17 -04:00
Jonathan Clem 8b9dfa809b Add group functions to core 2019-08-28 22:35:27 -04:00
dependabot[bot] e35e0e640b Bump mixin-deep from 1.3.1 to 1.3.2 (#95)
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-28 09:45:33 -04:00
dependabot[bot] ccf748b53b Bump lodash.template from 4.4.0 to 4.5.0 (#94)
Bumps [lodash.template](https://github.com/lodash/lodash) from 4.4.0 to 4.5.0.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.4.0...4.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-28 09:35:15 -04:00
dependabot[bot] 8caeee5d56 Bump tar from 2.2.1 to 2.2.2 (#93)
Bumps [tar](https://github.com/npm/node-tar) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Commits](https://github.com/npm/node-tar/compare/v2.2.1...v2.2.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-28 09:34:59 -04:00
dependabot[bot] b26ef29d75 Bump lodash from 4.17.11 to 4.17.15 (#92)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-28 09:34:46 -04:00
dependabot[bot] fba68de49e Bump fstream from 1.0.11 to 1.0.12 (#91)
Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/npm/fstream/releases)
- [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-28 09:34:34 -04:00
dependabot[bot] df04d7dbaf Bump eslint-utils from 1.3.1 to 1.4.2 (#90)
Bumps [eslint-utils](https://github.com/mysticatea/eslint-utils) from 1.3.1 to 1.4.2.
- [Release notes](https://github.com/mysticatea/eslint-utils/releases)
- [Commits](https://github.com/mysticatea/eslint-utils/compare/v1.3.1...v1.4.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-28 09:34:20 -04:00
AEnterprise 37202e8dbc fix syntax error in output example (#84) 2019-08-26 08:41:40 -04:00
Bryan MacFarlane 7cd421b8bc lint fixes 2019-08-25 00:55:22 -04:00
Bryan MacFarlane 17a0aa40f3 taking out some tests 2019-08-25 00:26:39 -04:00
Bryan MacFarlane b7ae833847 bit of branding 2019-08-24 09:24:48 -04:00
Bryan MacFarlane a2078cf37c raising not implemented earlier 2019-08-24 09:22:38 -04:00
Bryan MacFarlane 4ebc9007c0 removing not implemented function from docs 2019-08-24 09:17:35 -04:00
Bryan MacFarlane f66f5629b3 updating keywords 2019-08-23 17:39:40 -04:00
Sven-Hendrik Haase ac007c0698 Fix path (#78)
The current one seems like an uncommon Windows-like notation.
2019-08-23 10:42:51 -04:00
Danny McCormick 6b9630ac94 Add RELEASES.md for each package, bump tool-cache to publish (#67) 2019-08-22 13:14:49 -04:00
Akshay Iyyadurai Balasundaram e54c7a866d Fix: wrong spelling for using action in a workflow (#76) 2019-08-22 13:13:36 -04:00
Scott Brenner 750d949f10 container-action typo fix (#77) 2019-08-22 13:12:47 -04:00
Sven-Hendrik Haase 28803fc3b4 Correct wrong docs (#75)
Docs say it's `using:` but it's actually `uses:`.
2019-08-21 22:31:21 -04:00
Josh Soref ad054c855d Spelling (#72)
* spelling: check in

* spelling: compatibility

* spelling: definitely

* spelling: does not

* spelling: maintaining

* spelling: nonexistent

* spelling: precede

* spelling: response

* spelling: was not
2019-08-21 15:31:44 -04:00
Danny McCormick 7d605994f9 Comment nit 2019-08-21 12:54:24 -04:00
Jason Etcovitch e7914df1c6 Merge pull request #70 from actions/highlight-codeblocks
Highlight codeblocks in markdown files
2019-08-21 07:52:24 -07:00
Jason Etcovitch 1d687b2170 tool-cache/README.md 2019-08-21 01:18:31 -04:00
Jason Etcovitch a796c65f64 io/README.md 2019-08-21 01:18:21 -04:00
Jason Etcovitch 5e3e440c7f exec/README.md 2019-08-21 01:18:00 -04:00
Jason Etcovitch ea2ffbe002 Some more in the docs 2019-08-21 01:16:51 -04:00
Jason Etcovitch db9fd45770 Missed one 2019-08-21 01:16:47 -04:00
Jason Etcovitch 770cf14bde Highlight codeblocks in core/README.md 2019-08-20 22:15:05 -07:00
James M. Greene 00fc8b2580 Fix secrets reference syntax in README (#68) 2019-08-20 15:46:20 -04:00
Sören Wegener e2adf403d6 Typofix in markdown (#63) 2019-08-18 19:38:45 -04:00
Kenny Root 35ed15faaf Fix typo in README.md (#62)
Missed a "k" in "Walkthrough."
2019-08-18 19:28:10 -04:00
James M. Greene 9821b26794 Fix syntax mistake in README (#55) 2019-08-13 18:13:12 -04:00
Danny McCormick 8662b07822 Remove format step 2019-08-13 16:03:45 -04:00
Alif Rachmawadi 2c3e55b8c9 Add more supports for tar extensions (#48)
* added test for extracting .tar.gz

* added ability to extract .tar.xz

* add flags to extract tar

* make use of tempPath

* check file contents and make different content for tar file
2019-08-13 14:26:14 -04:00
Alif Rachmawadi 35cd59e8d5 Added unzip for darwin (#49)
* added unzip for darwin

* add mac builds

* added zip for darwin
2019-08-13 12:39:01 -04:00
Thomas Boop eae6c87114 Add Action Debugging information (#46)
* Add Action Debugging information

* Small verbiage updates

* Update README.md

* minor grammar updates
2019-08-12 17:00:55 -04:00
Danny McCormick 938549d01a Add status badge 2019-08-12 15:09:43 -04:00
Danny McCormick 079812ed8a Add github package to readme 2019-08-12 14:28:37 -04:00
Bryan MacFarlane ac5434c423 update some naming 2019-08-09 15:06:50 -04:00
Danny McCormick 4c46ecfd35 Add debug info 2019-08-09 13:55:59 -04:00
Sascha Wolf 534e4012a4 Docs: Fix link to the versioning file (#45)
The link to `action-versioning.md` was relative which lead to appending an additional `docs` folder to the current path which linked to `docs/docs/action-versioning.md` instead of `docs/action-versioning.md`.

By adding the leading `/` the link now works correctly.
2019-08-09 07:58:16 -04:00
Curtis Gibby 71fe4a8f36 Fix bad apostrophes (#44)
A possessive belonging to an "it" doesn't need an apostrophe. Don't believe me? Ask [the Oatmeal](http://theoatmeal.com/comics/apostrophe) (look for the velociraptor)!
2019-08-08 13:40:24 -04:00
Gregor Martynus aec0ef46e4 [@actions/github] Fix code example, add syntax highlighting (#43)
* [@actions/github] Fix code example, add syntax highlighting

* [@actions/github] add link to @octkit/graphql API

* [@octokit/github] moar syntax highlighting in README
2019-08-07 17:23:44 -04:00
Danny McCormick a40bce7c8d Publish
Main workflow / Run Windows (push) Has been cancelled
Main workflow / Run Ubuntu (push) Has been cancelled
- @actions/core@1.0.0
 - @actions/exec@1.0.0
 - @actions/github@1.0.0
 - @actions/io@1.0.0
 - @actions/tool-cache@1.0.0
2019-08-07 13:33:06 -04:00
Danny McCormick d7f00ea0fd Update package versions to 1.0.0 (#42)
* Update package versions to 1.0.0

* Fix package-lock
2019-08-07 12:56:34 -04:00
Shawn Napora 46b418103a Quick typo fixes (#41) 2019-08-07 09:56:03 -04:00
Danny McCormick 3004de4b40 Remove neutral exit code references 2019-08-06 09:12:30 -04:00
Danny McCormick da76d1fd39 Update versioning guidance (#40)
* Update versioning guidance

* Missing step
2019-08-06 08:17:49 -04:00
Danny McCormick fc9958ec6a Fix exports 2019-08-05 08:53:51 -04:00
Danny McCormick f9ab88cdc3 Fix link 2019-08-04 14:12:04 -04:00
Danny McCormick 293aa1ae02 Update package docs (#38)
* Update README.md

* Add exec guidance

* Add io guidance

* Add tool-cache guidance

* Readability

* Readability

* Readability

* Nit

* Nit

* Nit
2019-08-04 09:00:04 -04:00
Bryan MacFarlane 0bb10220a7 workflow allows for e2e testing 2019-08-04 08:56:16 -04:00
Bryan MacFarlane 3ce161a815 lower case v1 2019-08-03 12:17:54 -04:00
Bryan MacFarlane 571d130f50 Branching Strategy for Production Modules (#39)
* starting walkthrough docs
2019-08-03 12:15:05 -04:00
Danny McCormick 027a230b99 Correct github interfaces 2019-08-02 15:25:51 -04:00
Danny McCormick dfccb207bf Call out node_modules behavior (#37)
* Update node12-action.md

* Update node12-action.md

* Update node12-action.md
2019-08-01 17:08:30 -04:00
Bryan MacFarlane 3977d56fd3 Create Actions Walkthrough (#36)
* starting walkthrough docs

* versioning
2019-08-01 11:26:17 -04:00
Danny McCormick 4a7f2143e6 Get token from input in doc 2019-07-31 16:19:47 -04:00
Danny McCormick 5218a83722 Check the right variables (#35) 2019-07-30 12:31:36 -04:00
Danny McCormick 2a2b51f939 Add github package (#32)
* Add github package

* Docs

* Feedback

* Accidentally added extra

* Allow octokit to be extended

* Respond to feedback

* Feedback
2019-07-29 13:09:32 -04:00
Danny McCormick 4f5cf60872 Update workflow.yml (#34) 2019-07-25 23:08:57 -04:00
Danny McCormick 0a64f32b4e Update workflow.yml 2019-07-25 23:00:31 -04:00
Danny McCormick 9aacf6aeaa Propose github package spec (#31)
* Create github-package.md

* Add getters for issue/repo

* Update github-package.md
2019-07-22 16:26:28 -04:00
Danny McCormick 5a1b82748e Merge branch 'master' of https://github.com/actions/toolkit 2019-07-11 16:14:13 -04:00
Danny McCormick d78ededdcb Remove legacy workflow 2019-07-11 16:14:02 -04:00
Danny McCormick df0101c5c3 v2 workflow (#30)
* Create workflow.yml

* Try lower version of node

* Try running tests serially

* Start jest directly

* Start jest directly

* Start jest directly

* Start jest directly

* Dont test exec on windows right now

* Dont test exec on windows right now
2019-07-11 16:12:50 -04:00
Danny McCormick d293c20cc9 Dont stamp over stdout (#29) 2019-07-11 15:02:45 -04:00
Bryan MacFarlane c4a488fc74 add logo (#27)
add logo
2019-07-10 14:02:56 -04:00
Danny McCormick d919136160 Fix cp and mv (#26) 2019-07-09 09:56:01 -04:00
Danny McCormick e85d20fbb0 Combine exit into core; Remove toolkit (#21)
* Combine exit into core

* Remove toolkit

* Format

* Format

* Try to fix diff

* Try to fix diff

* Format

* Add gitattributes

* Use unix endings

* gitattributes is not a txt file

* Renormalize line endings
2019-06-25 13:54:41 -04:00
268 changed files with 43478 additions and 11077 deletions
+3 -1
View File
@@ -1,3 +1,5 @@
node_modules/
packages/*/node_modules/
packages/*/lib/
packages/*/lib/
packages/glob/__tests__/_temp
packages/*/src/generated/*/
+64 -15
View File
@@ -1,28 +1,76 @@
{
"plugins": ["jest", "@typescript-eslint"],
"extends": ["plugin:github/es6"],
"plugins": [
"jest",
"@typescript-eslint",
"prettier"
],
"extends": [
"plugin:github/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
"project": "./tsconfig.eslint.json"
},
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
],
"eslint-comments/no-use": "off",
"no-constant-condition": ["error", { "checkLoops": false }],
"github/no-then": "off",
"import/no-namespace": "off",
"no-shadow": "off",
"no-unused-vars": "off",
"i18n-text/no-en": "off",
"filenames/match-regex": "off",
"import/no-commonjs": "off",
"import/named": "off",
"no-sequences": "off",
"import/no-unresolved": "off",
"no-undef": "off",
"no-only-tests/no-only-tests": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "no-public"
}
],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-ignore": "error",
"@typescript-eslint/ban-ts-comment": "error",
"camelcase": "off",
"@typescript-eslint/camelcase": "error",
"@typescript-eslint/class-name-casing": "error",
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/consistent-type-assertions": "off",
"@typescript-eslint/explicit-function-return-type": [
"error",
{
"allowExpressions": true
}
],
"@typescript-eslint/func-call-spacing": [
"error",
"never"
],
"@typescript-eslint/naming-convention": [
"error",
{
"format": null,
"filter": {
// you can expand this regex as you find more cases that require quoting that you want to allow
"regex": "^[A-Z][A-Za-z]*$",
"match": true
},
"selector": "memberLike"
}
],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
@@ -32,7 +80,6 @@
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-object-literal-type-assertion": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
@@ -40,19 +87,21 @@
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-interface": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"semi": "off",
"@typescript-eslint/semi": ["error", "never"],
"@typescript-eslint/semi": [
"error",
"never"
],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"ignorePatterns": "packages/glob/__tests__/_temp/**/",
"env": {
"node": true,
"es6": true,
"jest/globals": true
}
}
}
+59
View File
@@ -0,0 +1,59 @@
# Contributions
We welcome contributions in the form of issues and pull requests. We view the contributions and process as the same for internal and external contributors.
## Issues
Log issues for both bugs and enhancement requests. Logging issues are important for the open community.
Issues in this repository should be for the toolkit packages. General feedback for GitHub Actions should be filed in the [community forums.](https://github.community/t5/GitHub-Actions/bd-p/actions) Runner specific issues can be filed [in the runner repository](https://github.com/actions/runner).
## Enhancements and Feature Requests
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
1. Create a feature request.
2. When we agree to take the enhancement, create an ADR to agree on the details of the change.
An ADR is an Architectural Decision Record. This allows consensus on the direction forward and also serves as a record of the change and motivation. [Read more here](../docs/adrs/README.md).
## Development Life Cycle
This repository uses [Lerna](https://github.com/lerna/lerna#readme) to manage multiple packages. Read the documentation there to begin contributing.
Note that before a PR will be accepted, you must ensure:
- all tests are passing
- `npm run format` reports no issues
- `npm run lint` reports no issues
### Useful Scripts
- `npm run bootstrap` This runs `lerna exec -- npm install` which will install dependencies in this repository's packages and cross-link packages where necessary.
- `npm run build` This compiles TypeScript code in each package (this is especially important if one package relies on changes in another when you're running tests). This is just an alias for `lerna run tsc`.
- `npm run format` This checks that formatting has been applied with Prettier.
- `npm test` This runs all Jest tests in all packages in this repository.
- If you need to run tests for only one package, you can pass normal Jest CLI options:
```console
$ npm test -- packages/toolkit
```
- `npm run create-package [name]` This runs a script that automates a couple of parts of creating a new package.
### Creating a Package
1. In a new branch, create a new Lerna package:
```console
$ npm run create-package new-package
```
This will ask you some questions about the new package. Start with `0.0.0` as the first version (look generally at some of the other packages for how the package.json is structured).
2. Add `tsc` script to the new package's package.json file:
```json
"scripts": {
"tsc": "tsc"
}
```
3. Start developing 😄.
+46
View File
@@ -0,0 +1,46 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
Thank you 🙇‍♀ for wanting to create an issue in this repository. Before you do, please ensure you are filing the issue in the right place. Issues should only be opened on if the issue **relates to code in this repository**.
* If you have found a security issue [please submit it here](https://hackerone.com/github)
* If you have questions about writing workflows or action files, then please [visit the GitHub Community Forum's Actions Board](https://github.community/t5/GitHub-Actions/bd-p/actions)
* If you are having an issue or question about GitHub Actions then please [contact customer support](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-github-actions#contacting-support)
If your issue is relevant to this repository, please include the information below:
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
@@ -0,0 +1,25 @@
---
name: Feature Request
about: Create a request to help us improve
title: ''
labels: enhancement
assignees: ''
---
Thank you 🙇‍♀ for wanting to create an issue in this repository. Before you do, please ensure you are filing the issue in the right place. Issues should only be opened on if the issue **relates to code in this repository**.
* If you have found a security issue [please submit it here](https://hackerone.com/github)
* If you have questions about writing workflows or action files, then please [visit the GitHub Community Forum's Actions Board](https://github.community/t5/GitHub-Actions/bd-p/actions)
* If you are having an issue or question about GitHub Actions then please [contact customer support](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-github-actions#contacting-support)
If your issue is relevant to this repository, please include the information below:
**Describe the enhancement**
A clear and concise description of what the features or enhancement you need.
**Code Snippet**
If applicable, add a code snippet to show the api enhancement.
**Additional information**
Add any other context about the feature here.
-39
View File
@@ -1,39 +0,0 @@
workflow "CI" {
on = "push"
resolves = ["Format", "Lint", "Test"]
}
action "Dependencies" {
uses = "actions/npm@v2.0.0"
args = "ci"
}
action "Bootstrap" {
needs = "Dependencies"
uses = "actions/npm@v2.0.0"
args = "run bootstrap"
}
action "Compile" {
needs = "Bootstrap"
uses = "actions/npm@v2.0.0"
args = "run build"
}
action "Format" {
needs = "Dependencies"
uses = "actions/npm@v2.0.0"
args = "run format-check"
}
action "Lint" {
needs = "Dependencies"
uses = "actions/npm@v2.0.0"
args = "run lint"
}
action "Test" {
needs = "Compile"
uses = "actions/npm@v2.0.0"
args = "test"
}
+130
View File
@@ -0,0 +1,130 @@
# Temporarily disabled while v2.0.0 of @actions/artifact is under development
name: artifact-unit-tests
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
build:
name: Build
strategy:
matrix:
runs-on: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false
runs-on: ${{ matrix.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
# without these to just compile the artifacts package
- name: Install root npm packages
run: npm ci
- name: Compile artifact package
run: |
npm ci
npm run tsc
working-directory: packages/artifact
- name: Set artifact file contents
shell: bash
run: |
echo "file1=hello from file 1" >> $GITHUB_ENV
echo "file2=hello from file 2" >> $GITHUB_ENV
- name: Create files that will be uploaded
run: |
mkdir artifact-path
echo '${{ env.file1 }}' > artifact-path/first.txt
echo '${{ env.file2 }}' > artifact-path/second.txt
- name: Upload Artifacts using actions/github-script@v7
uses: actions/github-script@v7
with:
script: |
const {default: artifact} = require('./packages/artifact/lib/artifact')
const artifactName = 'my-artifact-${{ matrix.runs-on }}'
console.log('artifactName: ' + artifactName)
const fileContents = ['artifact-path/first.txt','artifact-path/second.txt']
const uploadResult = await artifact.uploadArtifact(artifactName, fileContents, './')
console.log(uploadResult)
const size = uploadResult.size
const id = uploadResult.id
console.log(`Successfully uploaded artifact ${id}`)
verify:
runs-on: ubuntu-latest
needs: [build]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
# without these to just compile the artifacts package
- name: Install root npm packages
run: npm ci
- name: Compile artifact package
run: |
npm ci
npm run tsc
working-directory: packages/artifact
- name: List artifacts using actions/github-script@v7
uses: actions/github-script@v7
with:
script: |
const {default: artifact} = require('./packages/artifact/lib/artifact')
const workflowRunId = process.env.GITHUB_RUN_ID
const repository = process.env.GITHUB_REPOSITORY
const repositoryOwner = repository.split('/')[0]
const repositoryName = repository.split('/')[1]
const listResult = await artifact.listArtifacts(workflowRunId, repositoryOwner, repositoryName, '${{ secrets.GITHUB_TOKEN }}')
console.log(listResult)
const artifacts = listResult.artifacts
if (artifacts.length !== 3) {
throw new Error('Expected 3 artifacts but only found ' + artifacts.length + ' artifacts')
}
const artifactNames = artifacts.map(artifact => artifact.name)
if (!artifactNames.includes('my-artifact-ubuntu-latest')){
throw new Error("Expected artifact list to contain an artifact named my-artifact-ubuntu-latest but it's missing")
}
if (!artifactNames.includes('my-artifact-windows-latest')){
throw new Error("Expected artifact list to contain an artifact named my-artifact-windows-latest but it's missing")
}
if (!artifactNames.includes('my-artifact-macos-latest')){
throw new Error("Expected artifact list to contain an artifact named my-artifact-macos-latest but it's missing")
}
console.log('Successfully listed artifacts that were uploaded')
+38
View File
@@ -0,0 +1,38 @@
name: toolkit-audit
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
build:
name: Audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: npm install
run: npm install
- name: Bootstrap
run: npm run bootstrap
- name: audit tools (without allow-list)
run: npm audit --audit-level=moderate
- name: audit packages
run: npm run audit-all
+91
View File
@@ -0,0 +1,91 @@
name: cache-unit-tests
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
build:
name: Build
strategy:
matrix:
runs-on: [ubuntu-latest, windows-latest, macOS-latest]
fail-fast: false
runs-on: ${{ matrix.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
# node context. This runs a local action that gets and sets the necessary env variables that are needed
- name: Set env variables
uses: ./packages/cache/__tests__/__fixtures__/
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
# without these to just compile the cache package
- name: Install root npm packages
run: npm ci
- name: Compile cache package
run: |
npm ci
npm run tsc
working-directory: packages/cache
- name: Generate files in working directory
shell: bash
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} test-cache
- name: Generate files outside working directory
shell: bash
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
# We're using node -e to call the functions directly available in the @actions/cache package
- name: Save cache using saveCache()
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').saveCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
- name: Delete cache folders before restoring
shell: bash
run: |
rm -rf test-cache
rm -rf ~/test-cache
- name: Restore cache using restoreCache() with http-client
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}',[],{useAzureSdk: false}))"
- name: Verify cache restored with http-client
shell: bash
run: |
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} test-cache
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
- name: Delete cache folders before restoring
shell: bash
run: |
rm -rf test-cache
rm -rf ~/test-cache
- name: Restore cache using restoreCache() with Azure SDK
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
- name: Verify cache restored with Azure SDK
shell: bash
run: |
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} test-cache
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
+90
View File
@@ -0,0 +1,90 @@
name: cache-windows-bsd-unit-tests
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
build:
name: Build
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- shell: bash
run: |
rm "C:\Program Files\Git\usr\bin\tar.exe"
- name: Set Node.js 20.x
uses: actions/setup-node@v1
with:
node-version: 20.x
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
# node context. This runs a local action that gets and sets the necessary env variables that are needed
- name: Set env variables
uses: ./packages/cache/__tests__/__fixtures__/
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
# without these to just compile the cache package
- name: Install root npm packages
run: npm ci
- name: Compile cache package
run: |
npm ci
npm run tsc
working-directory: packages/cache
- name: Generate files in working directory
shell: bash
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} test-cache
- name: Generate files outside working directory
shell: bash
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
# We're using node -e to call the functions directly available in the @actions/cache package
- name: Save cache using saveCache()
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').saveCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
- name: Delete cache folders before restoring
shell: bash
run: |
rm -rf test-cache
rm -rf ~/test-cache
- name: Restore cache using restoreCache() with http-client
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}',[],{useAzureSdk: false}))"
- name: Verify cache restored with http-client
shell: bash
run: |
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} test-cache
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
- name: Delete cache folders before restoring
shell: bash
run: |
rm -rf test-cache
rm -rf ~/test-cache
- name: Restore cache using restoreCache() with Azure SDK
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
- name: Verify cache restored with Azure SDK
shell: bash
run: |
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} test-cache
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
+37
View File
@@ -0,0 +1,37 @@
name: "Code Scanning - Action"
on:
push:
branches:
- main
pull_request:
schedule:
- cron: '0 0 * * 0'
jobs:
CodeQL-Build:
strategy:
fail-fast: false
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+80
View File
@@ -0,0 +1,80 @@
name: Publish NPM
on:
workflow_dispatch:
inputs:
package:
required: true
description: 'core, artifact, cache, exec, github, glob, http-client, io, tool-cache'
jobs:
test:
runs-on: macos-latest
steps:
- name: setup repo
uses: actions/checkout@v3
- name: verify package exists
run: ls packages/${{ github.event.inputs.package }}
- name: Set Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: npm install
run: npm install
- name: bootstrap
run: npm run bootstrap
- name: build
run: npm run build
- name: test
run: npm run test
- name: pack
run: npm pack
working-directory: packages/${{ github.event.inputs.package }}
- name: upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ github.event.inputs.package }}
path: packages/${{ github.event.inputs.package }}/*.tgz
publish:
runs-on: macos-latest
needs: test
environment: npm-publish
steps:
- name: download artifact
uses: actions/download-artifact@v3
with:
name: ${{ github.event.inputs.package }}
- name: setup authentication
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc
env:
NPM_TOKEN: ${{ secrets.TOKEN }}
- name: publish
run: npm publish *.tgz
- name: notify slack on failure
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' --data '{"text":":pb__failed: Failed to publish a new version of ${{ github.event.inputs.package }}"}' $SLACK_WEBHOOK
env:
SLACK_WEBHOOK: ${{ secrets.SLACK }}
- name: notify slack on success
if: success()
run: |
curl -X POST -H 'Content-type: application/json' --data '{"text":":dance: Successfully published a new version of ${{ github.event.inputs.package }}"}' $SLACK_WEBHOOK
env:
SLACK_WEBHOOK: ${{ secrets.SLACK }}
+51
View File
@@ -0,0 +1,51 @@
name: toolkit-unit-tests
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
build:
name: Build
strategy:
matrix:
runs-on: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: false
runs-on: ${{ matrix.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: npm install
run: npm install
- name: Bootstrap
run: npm run bootstrap
- name: Compile
run: npm run build
- name: npm test
run: npm test -- --runInBand --forceExit
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Lint
run: npm run lint
- name: Format
run: npm run format-check
+45
View File
@@ -0,0 +1,45 @@
name: "UpdateOctokit"
on:
workflow_dispatch:
jobs:
UpdateOctokit:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'actions' }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Update Octokit
working-directory: packages/github
run: |
npx npm-check-updates -u --dep prod
npm install
- name: Check Status
id: status
working-directory: packages/github
run: |
if [[ "$(git status --porcelain)" != "" ]]; then
echo "::set-output name=createPR::true"
git config --global user.email "github-actions@github.com"
git config --global user.name "github-actions[bot]"
git checkout -b bots/updateGitHubDependencies-${{github.run_number}}
git add .
git commit -m "Update Dependencies"
git push --set-upstream origin bots/updateGitHubDependencies-${{github.run_number}}
fi
- name: Create PR
if: ${{steps.status.outputs.createPR}}
uses: actions/github-script@v6
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.pulls.create(
{
base: "main",
owner: "${{github.repository_owner}}",
repo: "toolkit",
title: "Update Octokit dependencies",
body: "Update Octokit dependencies",
head: "bots/updateGitHubDependencies-${{github.run_number}}"
})
+4 -1
View File
@@ -1,4 +1,7 @@
node_modules/
packages/*/node_modules/
packages/*/lib/
packages/*/__tests__/_temp/
packages/*/__tests__/_temp/
.DS_Store
*.xar
packages/*/audit.json
+3 -1
View File
@@ -1,3 +1,5 @@
node_modules/
packages/*/node_modules/
packages/*/lib/
packages/*/lib/
packages/glob/__tests__/_temp/**/
packages/*/src/generated/*/
+2 -1
View File
@@ -7,5 +7,6 @@
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
"parser": "typescript",
"endOfLine": "auto"
}
+4
View File
@@ -0,0 +1,4 @@
* @actions/actions-runtime
/packages/artifact/ @actions/artifacts-actions
/packages/cache/ @actions/actions-cache
+76
View File
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at opensource@github.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+2
View File
@@ -1,3 +1,5 @@
The MIT License (MIT)
Copyright 2019 GitHub
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:
+216 -42
View File
@@ -1,53 +1,227 @@
# Actions Toolkit 🛠
<p align="center">
<img src="res/at-logo.png">
</p>
<p align="center">
<a href="https://github.com/actions/toolkit/actions?query=workflow%3Atoolkit-unit-tests"><img alt="Toolkit unit tests status" src="https://github.com/actions/toolkit/workflows/toolkit-unit-tests/badge.svg"></a>
<a href="https://github.com/actions/toolkit/actions?query=workflow%3Atoolkit-audit"><img alt="Toolkit audit status" src="https://github.com/actions/toolkit/workflows/toolkit-audit/badge.svg"></a>
</p>
## GitHub Actions Toolkit
The GitHub Actions ToolKit provides a set of packages to make creating actions easier.
<br/>
<h3 align="center">Get started with the <a href="https://github.com/actions/javascript-action">javascript-action template</a>!</h3>
<br/>
## Packages
| Package | Description |
| ------- | ----------- |
| [@actions/core](packages/core) | Core functions for setting results, logging, secrets and environment variables |
| [@actions/exec](packages/exec) | Functions necessary for running tools on the command line |
| [@actions/exit](packages/exit) | Provides utilities for exiting from an action |
| [@actions/io](packages/io) | Core functions for CLI filesystem scenarios |
| [@actions/tool-cache](packages/tool-cache) | Functions necessary for downloading and caching tools |
| [@actions/toolkit](packages/toolkit) | A general-purpose toolkit for writing actions |
:heavy_check_mark: [@actions/core](packages/core)
## Development
Provides functions for inputs, outputs, results, logging, secrets and variables. Read more [here](packages/core)
This repository uses [Lerna](https://github.com/lerna/lerna#readme) to manage multiple packages. Read the documentation there to begin contributing.
Note that before a PR will be accepted, you must ensure:
- all tests are passing
- `npm run format` reports no issues
- `npm run lint` reports no issues
### Useful Scripts
- `npm run bootstrap` This runs `lerna bootstrap` which will install dependencies in this repository's packages and cross-link packages where necessary.
- `npm run build` This compiles TypeScript code in each package (this is especially important if one package relies on changes in another when you're running tests). This is just an alias for `lerna run tsc`.
- `npm run format` This checks that formatting has been applied with Prettier.
- `npm test` This runs all Jest tests in all packages in this repository.
- If you need to run tests for only one package, you can pass normal Jest CLI options:
```console
$ npm test -- packages/toolkit
```
- `npm run create-package [name]` This runs a script that automates a couple of parts of creating a new package.
### Creating a Package
1. In a new branch, create a new Lerna package:
```console
$ npm run create-package new-package
```bash
$ npm install @actions/core
```
<br/>
This will ask you some questions about the new package. Start with `0.0.0` as the first version (look generally at some of the other packages for how the package.json is structured).
:runner: [@actions/exec](packages/exec)
2. Add `tsc` script to the new package's package.json file:
Provides functions to exec cli tools and process output. Read more [here](packages/exec)
```json
"scripts": {
"tsc": "tsc"
}
```bash
$ npm install @actions/exec
```
<br/>
3. Start developing 😄 and open a pull request.
:ice_cream: [@actions/glob](packages/glob)
Provides functions to search for files matching glob patterns. Read more [here](packages/glob)
```bash
$ npm install @actions/glob
```
<br/>
:phone: [@actions/http-client](packages/http-client)
A lightweight HTTP client optimized for building actions. Read more [here](packages/http-client)
```bash
$ npm install @actions/http-client
```
<br/>
:pencil2: [@actions/io](packages/io)
Provides disk i/o functions like cp, mv, rmRF, which etc. Read more [here](packages/io)
```bash
$ npm install @actions/io
```
<br/>
:hammer: [@actions/tool-cache](packages/tool-cache)
Provides functions for downloading and caching tools. e.g. setup-* actions. Read more [here](packages/tool-cache)
See @actions/cache for caching workflow dependencies.
```bash
$ npm install @actions/tool-cache
```
<br/>
:octocat: [@actions/github](packages/github)
Provides an Octokit client hydrated with the context that the current action is being run in. Read more [here](packages/github)
```bash
$ npm install @actions/github
```
<br/>
:floppy_disk: [@actions/artifact](packages/artifact)
Provides functions to interact with actions artifacts. Read more [here](packages/artifact)
```bash
$ npm install @actions/artifact
```
<br/>
:dart: [@actions/cache](packages/cache)
Provides functions to cache dependencies and build outputs to improve workflow execution time. Read more [here](packages/cache)
```bash
$ npm install @actions/cache
```
<br/>
## Creating an Action with the Toolkit
:question: [Choosing an action type](docs/action-types.md)
Outlines the differences and why you would want to create a JavaScript or a container based action.
<br/>
<br/>
:curly_loop: [Versioning](docs/action-versioning.md)
Actions are downloaded and run from the GitHub graph of repos. This contains guidance for versioning actions and safe releases.
<br/>
<br/>
:warning: [Problem Matchers](docs/problem-matchers.md)
Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI.
<br/>
<br/>
:warning: [Proxy Server Support](docs/proxy-support.md)
Self-hosted runners can be configured to run behind proxy servers.
<br/>
<br/>
<h3><a href="https://github.com/actions/hello-world-javascript-action">Hello World JavaScript Action</a></h3>
Illustrates how to create a simple hello world javascript action.
```javascript
...
const nameToGreet = core.getInput('who-to-greet');
console.log(`Hello ${nameToGreet}!`);
...
```
<br/>
<h3><a href="https://github.com/actions/javascript-action">JavaScript Action Walkthrough</a></h3>
Walkthrough and template for creating a JavaScript Action with tests, linting, workflow, publishing, and versioning.
```javascript
async function run() {
try {
const ms = core.getInput('milliseconds');
console.log(`Waiting ${ms} milliseconds ...`)
...
```
```javascript
PASS ./index.test.js
throws invalid number
wait 500 ms
test runs
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
```
<br/>
<h3><a href="https://github.com/actions/typescript-action">TypeScript Action Walkthrough</a></h3>
Walkthrough creating a TypeScript Action with compilation, tests, linting, workflow, publishing, and versioning.
```javascript
import * as core from '@actions/core';
async function run() {
try {
const ms = core.getInput('milliseconds');
console.log(`Waiting ${ms} milliseconds ...`)
...
```
```javascript
PASS ./index.test.js
throws invalid number
wait 500 ms
test runs
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
```
<br/>
<br/>
<h3><a href="docs/container-action.md">Docker Action Walkthrough</a></h3>
Create an action that is delivered as a container and run with docker.
```docker
FROM alpine:3.10
COPY LICENSE README.md /
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
```
<br/>
<h3><a href="https://github.com/actions/container-toolkit-action">Docker Action Walkthrough with Octokit</a></h3>
Create an action that is delivered as a container which uses the toolkit. This example uses the GitHub context to construct an Octokit client.
```docker
FROM node:slim
COPY . .
RUN npm install --production
ENTRYPOINT ["node", "/lib/main.js"]
```
```javascript
const myInput = core.getInput('myInput');
core.debug(`Hello ${myInput} from inside a container`);
const context = github.context;
console.log(`We can even get context data, like the repo: ${context.repo.repo}`)
```
<br/>
## Contributing
We welcome contributions. See [how to contribute](.github/CONTRIBUTING.md).
## Code of Conduct
See [our code of conduct](CODE_OF_CONDUCT.md).
+3
View File
@@ -0,0 +1,3 @@
If you discover a security issue in this repo, please submit it through the [GitHub Security Bug Bounty](https://hackerone.com/github)
Thanks for helping make GitHub Actions safe for everyone.
+31
View File
@@ -0,0 +1,31 @@
# Debugging
If the job logs do not provide enough detail on why a job may be failing, some other options exist to assist with troubleshooting.
## Step Debug Logs
This is the primary way for customers to debug job failures caused by failed steps.
Step debug logs increase the verbosity of a job's logs during and after a job's execution to assist with troubleshooting.
Additional log events with the prefix `::debug::` will now also appear in the job's logs, these log events are provided by the Action's author and the runner process.
### How to Access Step Debug Logs
This flag can be enabled by [setting the secret](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#creating-encrypted-secrets) `ACTIONS_STEP_DEBUG` to `true`.
All actions ran while this secret is enabled will show debug events in the [Downloaded Logs](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/managing-a-workflow-run#downloading-logs) and [Web Logs](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/managing-a-workflow-run#viewing-logs-to-diagnose-failures).
## Runner Diagnostic Logs
Runner Diagnostic Logs provide additional log files detailing how the Runner is executing an action.
You need the runner diagnostic logs only if you think there is an infrastructure problem with GitHub Actions and you want the product team to check the logs.
Each file contains different logging information that corresponds to that process:
* The Runner process coordinates setting up workers to execute jobs.
* The Worker process executes the job.
These files contain the prefix `Runner_` or `Worker_` to indicate the log source.
### How to Access Runner Diagnostic Logs
These log files are enabled by [setting the secret](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#creating-encrypted-secrets) `ACTIONS_RUNNER_DEBUG` to `true`.
All actions ran while this secret is enabled contain additional diagnostic log files in the `runner-diagnostic-logs` folder of the [log archive](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/managing-a-workflow-run#downloading-logs).
+45
View File
@@ -0,0 +1,45 @@
# Action Types
There are two types of actions. JavaScript and Docker actions.
- **JavaScript Actions**: JavaScript actions run on the host machine. The unit of work is decoupled from the environment.
- **Docker Actions**: A container action is a container which carries both the unit of work along with the environment and its dependencies packaged up as a container.
Both have access to the workspace and the github event payload and context.
## Why would I choose a Docker action?
Docker actions carry both the unit of work and the environment.
This creates a more consistent and reliable unit of work where the consumer of the action does not need to worry about the toolsets and its dependencies.
Docker actions are currently limited to Linux only.
## Why would I choose a host action?
JavaScript actions decouple the unit of work from the environment and run directly on the host machine or VM.
Consider a simple example of testing a node lib on node 8, 10 and running a custom action. Each job will setup a node version on the host and custom-action will run its unit of work on each environment (node8+ubuntu16, node8+windows-2019, etc.)
```yaml
on: push
jobs:
build:
strategy:
matrix:
node: [8.x, 10.x]
os: [ubuntu-16.04, windows-2019]
runs-on: ${{matrix.os}}
actions:
- uses: actions/setup-node@v3
with:
version: ${{matrix.node}}
- run: |
npm install
- run: |
npm test
- uses: actions/custom-action@v1
```
JavaScript actions work on any environment that host action runtime is supported on which is currently node 12. However, a host action that runs a toolset expects the environment that it's running on to have that toolset in its PATH or using a setup-* action to acquire it on demand.
+63
View File
@@ -0,0 +1,63 @@
# Versioning
Actions are downloaded and run from the GitHub graph of repos. The workflow references an action using a ref.
Examples:
```yaml
steps:
- uses: actions/javascript-action@v1 # recommended. starter workflows use this
- uses: actions/javascript-action@v1.0.0 # if an action offers specific releases
- uses: actions/javascript-action@41775a4da8ffae865553a738ab8ac1cd5a3c0044 # sha
```
# Compatibility
Binding to a major version is the latest of that major version ( e.g. `v1` == "1.*" )
Major versions should guarantee compatibility. A major version can add net new capabilities but should not break existing input compatibility or break existing workflows.
Major version binding allows you to take advantage of bug fixes and critical functionality and security fixes. The `main` branch has the latest code and is unstable to bind to since changes get committed to main and released to the market place by creating a tag. In addition, a new major version carrying breaking changes will get implemented in main after branching off the previous major version.
> Warning: do not reference `main` since that is the latest code and can be carrying breaking changes of the next major version.
```yaml
steps:
- uses: actions/javascript-action@main # do not do this
```
Binding to the immutable full sha1 may offer more reliability. However, note that the hosted images toolsets (e.g. ubuntu-latest) move forward and if there is a tool breaking issue, actions may react with a patch to a major version to compensate so binding to a specific SHA may prevent you from getting fixes.
> Recommendation: bind to major versions to get functionality and fixes but reserve binding to a specific release or SHA as a mitigation strategy for unforeseen breaks.
# Recommendations
1. **Create a GitHub release for each specific version**: Creating a release like [ v1.0.0 ](https://github.com/actions/javascript-action/releases/tag/v1.0.0) allows users to bind back to a specific version if an issue is encountered with the latest major version.
2. **Publish the specific version to the marketplace**: When you release a specific version, choose the option to "Publish this Action to the GitHub Marketplace".
<img src="https://user-images.githubusercontent.com/33549821/78670739-36f5ae00-78ac-11ea-9660-57d5687ce520.png" alt="screenshot" height="250"/>
3. **Make the new release available to those binding to the major version tag**: Move the major version tag (v1, v2, etc.) to point to the ref of the current release. This will act as the stable release for that major version. You should keep this tag updated to the most recent stable minor/patch release.
```
git tag -fa v1 -m "Update v1 tag"
git push origin v1 --force
```
# Major Versions
All releases for a major version should hold compat including input compatibility and behavior compatibility.
Introduce a major version for compatibility breaks and major rewrites of the action.
Ideally, a major version would carry other benefits to the user to entice them to upgrade their workflows. Since updating their workflows will need to be done with an understanding of the changes and what compatibility was broken, introducing a new major version shouldn't be taken lightly.
To get feedback and to set expectations, the new major version can be initially released with `v2-beta` tag to indicate you can try it out but it's still going under some churn. Upon release the `-beta` can be dropped and there's an expectation of compatibility from that point forward.
[An example of v2-beta with checkout](https://github.com/actions/checkout/tree/c170eefc2657d93cc91397be50a299bff978a052#checkout-v2-beta)
# Sample Workflow
This illustrates the versioning workflow covered above.
![versioning](assets/action-releases.png)
+216
View File
@@ -0,0 +1,216 @@
# ADR 381: `glob` module
**Date**: 2019-12-05
**Status**: Accepted
## Context
This ADR proposes adding a `glob` function to the toolkit.
First party actions should have a consistent glob experience.
Related to artifact upload/download v2.
## Decision
### New module
Create a new module `@actions/glob` that can be versioned at it's own pace - not tied to `@actions/io`.
### Signature
```js
/**
* Constructs a globber from patterns
*
* @param patterns Patterns separated by newlines
* @param options Glob options
*/
export function create(
patterns: string,
options?: GlobOptions
): Promise<Globber> {}
/**
* Used to match files and directories
*/
export interface Globber {
/**
* Returns the search path preceding the first glob segment, from each pattern.
* Duplicates and descendants of other paths are filtered out.
*
* Example 1: The patterns `/foo/*` and `/bar/*` returns `/foo` and `/bar`.
*
* Example 2: The patterns `/foo/*` and `/foo/bar/*` returns `/foo`.
*/
getSearchPaths(): string[]
/**
* Returns files and directories matching the glob patterns.
*
* Order of the results is not guaranteed.
*/
glob(): Promise<string[]>
/**
* Returns files and directories matching the glob patterns.
*
* Order of the results is not guaranteed.
*/
globGenerator(): AsyncGenerator<string, void>
}
/**
* Options to control globbing behavior
*/
export interface GlobOptions {
/**
* Indicates whether to follow symbolic links. Generally should set to false
* when deleting files.
*
* @default true
*/
followSymbolicLinks?: boolean
/**
* Indicates whether directories that match a glob pattern, should implicitly
* cause all descendant paths to be matched.
*
* For example, given the directory `my-dir`, the following glob patterns
* would produce the same results: `my-dir/**`, `my-dir/`, `my-dir`
*
* @default true
*/
implicitDescendants?: boolean
/**
* Indicates whether broken symbolic should be ignored and omitted from the
* result set. Otherwise an error will be thrown.
*
* @default true
*/
omitBrokenSymbolicLinks?: boolean
}
```
### Toolkit usage
Example, do not follow symbolic links:
```js
const patterns = core.getInput('path')
const globber = glob.create(patterns, {followSymbolicLinks: false})
const files = globber.glob()
```
Example, iterator:
```js
const patterns = core.getInput('path')
const globber = glob.create(patterns)
for await (const file of this.globGenerator()) {
console.log(file)
}
```
### Action usage
Actions should follow symbolic links by default.
Users can opt-out.
Example:
```yaml
jobs:
build:
steps:
- uses: actions/upload-artifact@v1
with:
path: |
**/*.tar.gz
**/*.pkg
follow-symbolic-links: false # opt out, should default to true
```
### HashFiles function
Hash files should not follow symbolic links by default.
User can opt-in by specifying flag `--follow-symbolic-links`.
Example:
```yaml
jobs:
build:
steps:
- uses: actions/cache@v1
with:
hash: ${{ hashFiles('--follow-symbolic-links', '**/package-lock.json') }}
```
### Glob behavior
Patterns `*`, `?`, `[...]`, `**` (globstar) are supported.
With the following behaviors:
- File names that begin with `.` may be included in the results
- Case insensitive on Windows
- Directory separator `/` and `\` both supported on Windows
Note:
- Refer [here](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching) for more information about Bash glob patterns.
- Refer [here](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) for more information about Bash glob options.
### Tilde expansion
Support basic tilde expansion, for current user HOME replacement only.
For example, on macOS:
- `~` may expand to `/Users/johndoe`
- `~/foo` may expand to `/Users/johndoe/foo`
Note:
- Refer [here](https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html) for more information about Bash tilde expansion.
- All other forms of tilde expansion are not supported.
- Use `os.homedir()` to resolve the HOME path
### Root and normalize paths
An unrooted pattern will be rooted using the current working directory, prior to searching. Additionally the search path will be normalized prior to searching (relative pathing removed, slashes normalized on Windows, extra slashes removed).
The two side effects are:
1. Rooted and normalized paths are always returned
2. The pattern `**` will include the working directory in the results
These side effects diverge from Bash behavior. Whereas Bash is designed to be a shell, we are designing an API. This decision is intended to improve predictability of the API results.
Note:
- In Bash, the results are not rooted when the pattern is relative.
- In Bash, the results are not normalized. For example, the results from `./*` may look like: `./foo ./bar`
- In Bash, the results from the pattern `**` does not include the working directory. However the results from `/foo/**` would include the directory `/foo`. Also the results from `foo/**` would include the directory `foo`.
## Comments
Patterns that begin with `#` are treated as comments.
## Exclude patterns
Leading `!` changes the meaning of an include pattern to exclude.
Note:
- Multiple leading `!` flips the meaning.
## Escaping
Wrapping special characters in `[]` can be used to escape literal glob characters in a file name. For example the literal file name `hello[a-z]` can be escaped as `hello[[]a-z]`.
On Linux/macOS `\` is also treated as an escape character.
## Consequences
- Publish new module `@actions/glob`
- Publish docs for the module (add link from `./README.md` to new doc `./packages/glob/README.md`)
+19
View File
@@ -0,0 +1,19 @@
# ADRs
ADR, short for "Architecture Decision Record" is a way of capturing important architectural decisions, along with their context and consequences.
This folder includes ADRs for the actions toolkit. ADRs are proposed in the form of a pull request, and they commonly follow this format:
* **Title**: short present tense imperative phrase, less than 50 characters, like a git commit message.
* **Status**: proposed, accepted, rejected, deprecated, superseded, etc.
* **Context**: what is the issue that we're seeing that is motivating this decision or change.
* **Decision**: what is the change that we're actually proposing or doing.
* **Consequences**: what becomes easier or more difficult to do because of this change.
---
- More information about ADRs can be found [here](https://github.com/joelparkerhenderson/architecture_decision_record).
+1
View File
@@ -0,0 +1 @@
<mxfile modified="2019-12-12T18:56:00.899Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" etag="CISsL8yLQ-3TSrXBbF_M" version="12.3.8" type="device" pages="1"><diagram name="Page-1" id="ff44883e-f642-bcb2-894b-16b3d25a3f0b">7VvbctsqFP0aP9YjkISkx9hJcx7amZ7mTNs8dYiEZVpZeBC+9esPyMi64UsdW3Ymdh4Mm5tgrbU3AqdnDyfLR46n488sIkkPWtGyZ9/3IASWi+SXsqzWFhf5a0PMaaQrlYYn+ocULbV1RiOS1SoKxhJBp3VjyNKUhKJmw5yzRb3aiCX1Uac4Ji3DU4iTwtp3S/t3GomxtgMUlAX/EBqP9eA+1FN+weHvmLNZqkfsQXuUf9bFE1z0paeajXHEFhWT/dCzh5wxsU5NlkOSqNUtFq5oJ1bF0/bswVhMEpkBMpkXf9zSGBzSWE6Ok1RUh9vW38h6CcMgsC2HoJGLPwSt/kkkV1ZnU5bKr0E443MS6RErg2cCc6HJIJlgD0ga3Sk0ZT5McJbRcG38SJOijcxVW2SCs99kyBLG8+FtK/9sSgos1bRHLN2MBvOuBF/92PQrM88yY0kq6Oy94re1ya2K3JKKH5V0pZXMlY1UpmjTXucCGTbjITEvLtRKwDwmwlxF96IWvdKtxu6RsAmRTy4rcJJgQed1EWCtmnhTb9P0C6PyQaGlFe4UQtX69jyr3sV6GrpVyR+ZqDxGacpZdRjDADo1xfaxaSdnTNjvRH7Dsgqxnquk28Kyoxhjd0MH5NfpgNwGHdaUPQsd1gPNcTIrHFqLHkki44ZixWJMBXma4ny5FjJ01cmRe+2cNTn4hWMGJr+C8k+LI06dI7bqCCc0TpULk8gRripIwlW6GrnqbxfEc8IFWe5EUJfCBhJuIcxFGcSKKuNq+LK2Y15D62+gaUeqa1PqHi99bEQ4Sqtov3eH3cjZDRoksjuTM2zJud/vX1TR4MKKdrzrUbR9Xc720tB4Th0aH14OGucGTQ2apgu7ZBx0bnHwL+Kgsz8Oom7ioGdfLA6im5yrckbO5eQc/+T3377+Gz/Mp9/++5SxT+Hwg/G1AyVy1MGLTMR5guM0lM92V5TIgTaF8htPFE7pS6a+JFMJzkgm68zbZzQSs6lKhjhJ2Ezsh3xKOJUTVbAUjb6UpsGUZVRQlsJcxcA/kc9FjUMBpw0SgF2idNuv1AACln25DYsRoFtk3BUZd3F6V3js6NTHQ6DvAdeDvufK2OgFdW45xtI9B4Tto6XGRg6hs8Vg43L7+x19yAkWZL2eyon3lKoGOUbxVvdvgT7o25u+eCUw1Hvf2UnnsULCeBJXFDjNWAHasQJ1GtGtW7DYhdDlt1xtrr+xYHG80y/IeW6X7lsNbwsbaB7qtv3GqRUC3bptELTUPMGZEk2TQ1IOokmVqkI1r6pK06aWGpW4qHShd7pgQqMo2eYt6i4ip5d+qIbyFVgn2f017uyQZdieewZFg2A7jV6laNh2ubvfg94PVm5jo24f+CrV1OvpsDrkoq28rtfLHuFsbPLGBy/ZXodXWRDXsB6F7ZV+ETSu1bymOzvULwLg7enpdI4xcFf8bjX8NcOfvybsz+Pz/XffcMFysv2s1bfe3H7WLvezLXUaCLn93rVx9uEEBsGeaz9rBNp09nEKoOvnVvAkqLddydtA3XP9K0PddA10HtTBu0U9gAdovWBGJ6i753PqoA/frVNH1rU59fa10ASnqxyoZYmt3D1bhl9NXOPu+fUgOY5bA8kFBpDsM22VjSB5LZCGcs6YpgoXMVbSk5tRkqlt4QT/kgudL0Em+XulmJ0iVDbPcQ3HSYHbIUqG874RVSKi6QamjPA5DWkay7S+zoMWG6mJczKnbJa9JwiDxqtLYFKa6UjwCAxltvwJ/Prdp/xPA/vhfw==</diagram></mxfile>
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

+217
View File
@@ -0,0 +1,217 @@
# :: Commands
The [core toolkit package](https://github.com/actions/toolkit/tree/main/packages/core) offers a number of convenience functions for
setting results, logging, registering secrets and exporting variables across actions. Sometimes, however, its useful to be able to do
these things in a script or other tool.
To allow this, we provide a special `::` syntax which, if logged to `stdout` on a new line, will allow the runner to perform special behavior on
your commands. The following commands are all supported:
### Set outputs
To set an output for the step, use `::set-output`:
```sh
echo "::set-output name=FOO::BAR"
```
Running `steps.[step-id].outputs.FOO` in your Yaml will now give you `BAR`
```yaml
steps:
- name: Set the value
id: step_one
run: echo "::set-output name=FOO::BAR"
- name: Use it
run: echo ${{ steps.step_one.outputs.FOO }}
```
This is wrapped by the core setOutput method:
```javascript
export function setOutput(name: string, value: string): void {}
```
### Register a secret
If a script or action does work to create a secret at runtime, it can be registered with the runner to be masked in logs.
To mask a value in the logs, use `::add-mask`:
```sh
echo "::add-mask::mysecretvalue"
```
This is wrapped by the core setSecret method
```javascript
function setSecret(secret: string): void {}
```
Now, future logs containing BAR will be masked. E.g. running `echo "Hello FOO BAR World"` will now print `Hello FOO **** World`.
**WARNING** The add-mask and setSecret commands only support single-line
secrets or multi-line secrets that have been escaped. `@actions/core`
`setSecret` will escape the string you provide by default. When an escaped
multi-line string is provided the whole string and each of its lines
individually will be masked. For example you can mask `first\nsecond\r\nthird`
using:
```sh
echo "::add-mask::first%0Asecond%0D%0Athird"
```
This will mask `first%0Asecond%0D%0Athird`, `first`, `second` and `third`.
**WARNING** Do **not** mask short values if you can avoid it, it could render your output unreadable (and future steps' output as well).
For example, if you mask the letter `l`, running `echo "Hello FOO BAR World"` will now print `He*********o FOO BAR Wor****d`
### Group and Ungroup Log Lines
Emitting a group with a title will instruct the logs to create a collapsible region up to the next endgroup command.
```bash
echo "::group::my title"
echo "::endgroup::"
```
This is wrapped by the core methods:
```javascript
function startGroup(name: string): void {}
function endGroup(): void {}
```
### Problem Matchers
Problems matchers can be used to scan a build's output to automatically surface lines to the user that matches the provided pattern. A file path to a .json Problem Matcher must be provided. See [Problem Matchers](problem-matchers.md) for more information on how to define a Problem Matcher.
```bash
echo "::add-matcher::eslint-compact-problem-matcher.json"
echo "::remove-matcher owner=eslint-compact::"
```
`add-matcher` takes a path to a Problem Matcher file
`remove-matcher` removes a Problem Matcher by owner
### Save State
Save a state to an environmental variable that can later be used in the main or post action.
```bash
echo "::save-state name=FOO::foovalue"
```
Because `save-state` prepends the string `STATE_` to the name, the environment variable `STATE_FOO` will be available to use in the post or main action. See [Sending Values to the pre and post actions](https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions) for more information.
### Log Level
There are several commands to emit different levels of log output:
| log level | example usage |
|---|---|
| [debug](action-debugging.md) | `echo "::debug::My debug message"` |
| notice | `echo "::notice::My notice message"` |
| warning | `echo "::warning::My warning message"` |
| error | `echo "::error::My error message"` |
Additional syntax options are described at [the workflow command documentation](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message).
### Command Echoing
By default, the echoing of commands to stdout only occurs if [Step Debugging is enabled](./action-debugging.md#How-to-Access-Step-Debug-Logs)
You can enable or disable this for the current step by using the `echo` command.
```bash
echo "::echo::on"
```
You can also disable echoing.
```bash
echo "::echo::off"
```
This is wrapped by the core method:
```javascript
function setCommandEcho(enabled: boolean): void {}
```
The `add-mask`, `debug`, `warning` and `error` commands do not support echoing.
### Command Prompt
CMD processes the `"` character differently from other shells when echoing. In CMD, the above snippets should have the `"` characters removed in order to correctly process. For example, the set output command would be:
```cmd
echo ::set-output name=FOO::BAR
```
## Environment files
During the execution of a workflow, the runner generates temporary files that can be used to perform certain actions. The path to these files are exposed via environment variables. You will need to use the `utf-8` encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, separated by newlines.
### Set an environment variable
To set an environment variable for future out of process steps, write to the file located at `GITHUB_ENV` or use the equivalent `actions/core` function
```sh
echo "FOO=BAR" >> $GITHUB_ENV
```
Running `$FOO` in a future step will now return `BAR`
For multiline strings, you may use a heredoc style syntax with your choice of delimeter. In the below example, we use `EOF`.
```
steps:
- name: Set the value
id: step_one
run: |
echo 'JSON_RESPONSE<<EOF' >> $GITHUB_ENV
curl https://httpbin.org/json >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
```
This would set the value of the `JSON_RESPONSE` env variable to the value of the curl response.
The expected syntax for the heredoc style is:
```
{VARIABLE_NAME}<<{DELIMETER}
{VARIABLE_VALUE}
{DELIMETER}
```
This is wrapped by the core `exportVariable` method which sets for future steps but also updates the variable for this step.
```javascript
export function exportVariable(name: string, val: string): void {}
```
### PATH Manipulation
To prepend a string to PATH write to the file located at `GITHUB_PATH` or use the equivalent `actions/core` function
```sh
echo "/Users/test/.nvm/versions/node/v12.18.3/bin" >> $GITHUB_PATH
```
Running `$PATH` in a future step will now return `/Users/test/.nvm/versions/node/v12.18.3/bin:{Previous Path}`;
This is wrapped by the core addPath method:
```javascript
export function addPath(inputPath: string): void {}
```
### Powershell
Powershell does not use UTF8 by default. You will want to make sure you write in the correct encoding. For example, to set the path:
```
steps:
- run: echo "mypath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
```
+3
View File
@@ -0,0 +1,3 @@
# Creating a Container Action Using the Toolkit
In progress.
+71
View File
@@ -0,0 +1,71 @@
# Creating a Docker Action
The [container-template](https://github.com/actions/container-template) repo contains the base files to create a Docker action.
# Create a Repo from the Template
Navigate to https://github.com/actions/container-template
Click on `Use this template` to create the repo for your action.
![template](assets/node12-template.png)
Complete creating your repo and clone the repo.
> NOTE: The location of the repo will be how users will reference your action in their workflow file with the using keyword.
e.g. To use https://github.com/actions/setup-node, users will author:
```yaml
steps:
using: actions/setup-node@v3
```
# Define Metadata
Your action has a name and a description. Update the author.
Create inputs that your unit of work will need. These will be what workflow authors set with the `with:` keyword.
```yaml
name: 'My Container Action'
description: 'Get started with Container actions'
author: 'GitHub'
inputs:
myInput:
description: 'Input to use'
default: 'world'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.myInput }}
```
It will be run with docker and the input is mapped into the args
# Change Code
The entry point is in entrypoint.sh
```bash
#!/bin/sh -l
echo "hello $1"
```
# Publish
Simply push your action to publish.
```bash
$ git push
```
The runner will download the action and build the docker container on the fly at runtime.
> Consider versioning your actions with tags. See [versioning](/docs/action-versioning.md)
+288
View File
@@ -0,0 +1,288 @@
# Creating an Action using the GitHub Context
## Goal
In this walkthrough we will learn how to build a basic action using GitHub context data to greet users when they open an issue or PR. In the process we will explore how to access this context and how to make authenticated requests to the GitHub API.
Note that a complete version of this action can be found at https://github.com/damccorm/issue-greeter.
## Prerequisites
This walkthrough assumes that you have gone through the basic [javascript action walkthrough](https://github.com/actions/javascript-action) and have a basic action set up. If not, we recommend you go through that first.
## Installing dependencies
All of the dependencies we need should come packaged for us in this library's core and github packages. To install, run the following in your action:
`npm install @actions/core && npm install @actions/github`
## Metadata
Next, we will need a welcome message and a repo token as an input. Recall that inputs are defined in the `action.yml` metadata file - update your `action.yml` file to define `welcome-message` and `repo-token` as inputs.
```yaml
name: "Welcome"
description: "A basic welcome action"
author: "GitHub"
inputs:
welcome-message:
description: "Message to display when a user opens an issue or PR"
default: "Thanks for opening an issue! Make sure you've followed CONTRIBUTING.md"
repo-token:
description: "Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}"
required: true
runs:
using: "node12"
main: "lib/main.js"
```
## Action logic
Now that we've installed our dependencies and defined our inputs, we're ready to start writing the action logic in `src/main.ts`! For clarity, we'll structure our action up as follows:
```ts
import * as core from '@actions/core';
import * as github from '@actions/github';
export async function run() {
try {
const welcomeMessage: string = core.getInput('welcome-message');
// TODO - Get context data
// TODO - make request to the GitHub API to comment on the issue
}
catch (error) {
core.setFailed(error.message);
throw error;
}
}
run();
```
### Getting context data
For the purpose of this walkthrough, we will need the following pieces of context data:
- the name of the repo that the action is being run on
- the organization/owner of that repo
- the number of the issue that has been opened
Fortunately, the GitHub package provides all of this to us with [a single convenience function](https://github.com/actions/toolkit/blob/ac007c06984bc483fae2ba649788dfc858bc6a8b/packages/github/src/context.ts#L34), so we can simply do:
`const issue: {owner: string; repo: string; number: number} = github.context.issue;`
The context object also contains a number of easily accessed properties, as well as easy access to the full [GitHub payload](https://developer.github.com/v3/activity/events/types/). We can use this to check and make sure we're actually looking at a recently opened issue (and not something else, like a comment on an existing issue):
```ts
if (github.context.payload.action !== 'opened') {
console.log('No issue or PR was opened, skipping');
return;
}
```
Our whole `src/main.ts` file now looks like:
```ts
import * as core from '@actions/core';
import * as github from '@actions/github';
export async function run() {
try {
const welcomeMessage: string = core.getInput('welcome-message', {required: true});
const repoToken: string = core.getInput('repo-token', {required: true});
const issue: {owner: string; repo: string; number: number} = github.context.issue;
if (github.context.payload.action !== 'opened') {
console.log('No issue or pull request was opened, skipping');
return;
}
// TODO - make request to the GitHub API to comment on the issue
}
catch (error) {
core.setFailed(error.message);
throw error;
}
}
run();
```
### Sending requests to the GitHub API
Now that we have our context data, we are able to send a request to the GitHub API using the [Octokit REST client](https://github.com/octokit/rest.js). The REST client exposes a number of easy convenience functions, including one for adding comments to issues/PRs (issues and PRs are treated as one concept by the Octokit client):
```ts
const client: github.GitHub = new github.GitHub(repoToken);
await client.issues.createComment({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
body: welcomeMessage
});
```
For more docs on the client, you can visit the [Octokit REST documentation](https://octokit.github.io/rest.js/). Now our action code should be complete:
```ts
import * as core from '@actions/core';
import * as github from '@actions/github';
export async function run() {
try {
const welcomeMessage: string = core.getInput('welcome-message', {required: true});
const repoToken: string = core.getInput('repo-token', {required: true});
const issue: {owner: string; repo: string; number: number} = github.context.issue;
if (github.context.payload.action !== 'opened') {
console.log('No issue or pull request was opened, skipping');
return;
}
const client: github.GitHub = new github.GitHub(repoToken);
await client.issues.createComment({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
body: welcomeMessage
});
}
catch (error) {
core.setFailed(error.message);
throw error;
}
}
run();
```
## Writing unit tests for your action
Next, we're going to write a basic unit test for our action using jest. If you followed the [javascript walkthrough](https://github.com/actions/javascript-action), you should have a file `__tests__/main.test.ts` that runs tests when `npm test` is called. We're going to start by populating that with one test:
```ts
const nock = require('nock');
const path = require('path');
describe('action test suite', () => {
it('It posts a comment on an opened issue', async () => {
// TODO
});
});
```
For the purposes of this walkthrough, we'll focus on populating this test and leave the remaining test coverage as an exercise for the reader.
### Mocking inputs
First, we want to make sure that we can mock our inputs (welcome-message, and repo-token). Actions handles inputs by populating process.env.INPUT_${input name in all caps}, so we can mock that simply by setting those environment variables:
```ts
const nock = require('nock');
const path = require('path');
describe('action test suite', () => {
it('It posts a comment on an opened issue', async () => {
const welcomeMessage = 'hello';
const repoToken = 'token';
process.env['INPUT_WELCOME-MESSAGE'] = welcomeMessage;
process.env['INPUT_REPO-TOKEN'] = repoToken;
// TODO
});
});
```
### Mocking the GitHub context
Mocking the GitHub context is relatively straightforward. Since most of it is simply populated by environment variables, you can just set the corresponding environment variables defined [here](https://github.com/actions/toolkit/blob/ac007c06984bc483fae2ba649788dfc858bc6a8b/packages/github/src/context.ts#L23) and test that it works in that environment. In this case, we can setup our test with:
```ts
const nock = require('nock');
const path = require('path');
describe('action test suite', () => {
it('It posts a comment on an opened issue', async () => {
const welcomeMessage = 'hello';
const repoToken = 'token';
process.env['INPUT_WELCOME-MESSAGE'] = welcomeMessage;
process.env['INPUT_REPO-TOKEN'] = repoToken;
process.env['GITHUB_REPOSITORY'] = 'foo/bar';
process.env['GITHUB_EVENT_PATH'] = path.join(__dirname, 'payload.json');
// TODO
});
});
```
Note that the payload is loaded from GITHUB_EVENT_PATH. Since we set that to `path.join(__dirname, 'payload.json')`, we need to go save our payload there. For the purposes of this test, we can simply save the following to `__tests__/payload.json`:
```json
{
"issue": {
"number": 10
},
"action": "opened"
}
```
Now, calling `github.context.issue` should return `{owner: foo, repo: bar, number: 10}`, and `github.context.payload.action` should get set to 'opened'
> One important detail here is that because the GitHub context loads these environment variables as soon as it is required, you should set them before you require your action. In most cases, this means you need to rerequire your action in every test. If this is a problem, you can get around it by mocking the class directly using jest (or whatever framework you choose).
### Mocking the Octokit Client
To mock the client calls, we recommend using [nock](https://github.com/nock/nock) which allows you to mock the http requests made by the client. First, install nock with `npm install nock --save-dev`.
For this test, we expect the following call:
```ts
client.issues.createComment({
owner: 'foo',
repo: 'bar',
issue_number: 10,
body: 'you posted your first issue'
});
```
From [the GitHub endpoint docs](https://developer.github.com/v3/issues/comments/#create-a-comment), we expect this to get make a POST request to `https://api.github.com/repos/foo/bar/issues/10/comments` with body of `{"body":"hello"}`
We can mock this with:
```ts
const nock = require('nock');
const path = require('path');
describe('action test suite', () => {
it('It posts a comment on an opened issue', async () => {
const welcomeMessage = 'hello';
const repoToken = 'token';
process.env['INPUT_WELCOME-MESSAGE'] = welcomeMessage;
process.env['INPUT_REPO-TOKEN'] = repoToken;
process.env['GITHUB_REPOSITORY'] = 'foo/bar';
process.env['GITHUB_EVENT_PATH'] = path.join(__dirname, 'payload.json');
nock('https://api.github.com')
.persist()
.post('/repos/foo/bar/issues/10/comments', '{\"body\":\"hello\"}')
.reply(200);
const main = require('../src/main');
await main.run();
});
});
```
This will fail if the url or body doesn't exactly match the parameters passed into the nock function. We can now run `npm test` and the test should succeed.
## Build and publish
Now that we've written and unit tested our action, we can build our action with `npm run build` and push it to a repo where it can be consumed by workflows. For more info on versioning your action, see [our versioning docs](./action-versioning.md).
## Next steps
If you're interested in building out this action further, try extending your action to only run on a user's first issue. See our [first-contribution action](https://github.com/actions/first-interaction) for inspiration.
+149
View File
@@ -0,0 +1,149 @@
# Problem Matchers
Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI. Both [GitHub Annotations](https://developer.github.com/v3/checks/runs/#annotations-object-1) and log file decorations are created when a match is detected.
## Limitations
Currently, GitHub Actions limit the annotation count in a workflow run.
- 10 warning annotations, 10 error annotations, and 10 notice annotations per step
- 50 annotations per job (sum of annotations from all the steps)
- 50 annotations per run (separate from the job annotations, these annotations arent created by users)
If your workflow may exceed these annotation counts, consider filtering of the log messages which the Problem Matcher is exposed to (e.g. by PR touched files, lines, or other).
## Single Line Matchers
Let's consider the ESLint compact output:
```
badFile.js: line 50, col 11, Error - 'myVar' is defined but never used. (no-unused-vars)
```
We can define a problem matcher in json that detects input in that format:
```json
{
"problemMatcher": [
{
"owner": "eslint-compact",
"pattern": [
{
"regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s(Error|Warning|Info)\\s-\\s(.+)\\s\\((.+)\\)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5,
"code": 6
}
]
}
]
}
```
The following fields are available for problem matchers:
```
{
owner: an ID field that can be used to remove or replace the problem matcher. **required**
severity: indicates the default severity, either 'warning' or 'error' case-insensitive. Defaults to 'error'
pattern: [
{
regexp: the regex pattern that provides the groups to match against **required**
file: a group number containing the file name
fromPath: a group number containing a filepath used to root the file (e.g. a project file)
line: a group number containing the line number
column: a group number containing the column information
severity: a group number containing either 'warning' or 'error' case-insensitive. Defaults to `error`
code: a group number containing the error code
message: a group number containing the error message. **required** at least one pattern must set the message
loop: whether to loop until a match is not found, only valid on the last pattern of a multipattern matcher
}
]
}
```
## Multiline Matching
Consider the following output:
```
test.js
1:0 error Missing "use strict" statement strict
5:10 error 'addOne' is defined but never used no-unused-vars
✖ 2 problems (2 errors, 0 warnings)
```
The file name is printed once, yet multiple error lines are printed. The `loop` keyword provides a way to discover multiple errors in outputs.
The eslint-stylish problem matcher defined below catches that output, and creates two annotations from it.
```
{
"problemMatcher": [
{
"owner": "eslint-stylish",
"pattern": [
{
// Matches the 1st line in the output
"regexp": "^([^\\s].*)$",
"file": 1
},
{
// Matches the 2nd and 3rd line in the output
"regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$",
// File is carried through from above, so we define the rest of the groups
"line": 1,
"column": 2,
"severity": 3,
"message": 4,
"code": 5,
"loop": true
}
]
}
]
}
```
The first pattern matches the `test.js` line and records the file information. This line is not decorated in the UI.
The second pattern loops through the remaining lines with `loop: true` until it fails to find a match, and surfaces these lines prominently in the UI.
Note that the pattern matches must be on consecutive lines. The following would not result in any match findings.
```
test.js
extraneous log line of no interest
1:0 error Missing "use strict" statement strict
5:10 error 'addOne' is defined but never used no-unused-vars
✖ 2 problems (2 errors, 0 warnings)
```
## Adding and Removing Problem Matchers
Problem Matchers are enabled and removed via the toolkit [commands](commands.md#problem-matchers).
## Duplicate Problem Matchers
Registering two problem-matchers with the same owner will result in only the problem matcher registered last running.
## Examples
Some of the starter actions are already using problem matchers, for example:
- [setup-node](https://github.com/actions/setup-node/tree/main/.github)
- [setup-python](https://github.com/actions/setup-python/tree/main/.github)
- [setup-go](https://github.com/actions/setup-go/tree/main/.github)
- [setup-dotnet](https://github.com/actions/setup-dotnet/tree/main/.github)
## Troubleshooting
### Regular expression not matching
Use ECMAScript regular expression syntax when testing patterns.
### File property getting dropped
[Enable debug logging](https://docs.github.com/en/actions/managing-workflow-runs/enabling-debug-logging) to determine why the file is getting dropped.
This usually happens when the file does not exist or is not under the workflow repo.
+10
View File
@@ -0,0 +1,10 @@
# Proxy Server Support
Self-hosted runners [can be configured](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners) to run behind a proxy server in enterprises.
For actions to **just work** behind a proxy server:
1. Use [tool-cache](/packages/tool-cache) version >= 1.3.1
2. Optionally use [actions/http-client](/packages/http-client)
If you are using other http clients, refer to the [environment variables set by the runner](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners).
+100
View File
@@ -0,0 +1,100 @@
# Github Package
In order to support using actions to interact with GitHub, I propose adding a `github` package to the toolkit.
Its main purpose will be to provide a hydrated GitHub context/Octokit client with some convenience functions. It is largely pulled from the GitHub utilities provided in https://github.com/JasonEtco/actions-toolkit, though it has been condensed.
### Spec
##### interfaces.ts
```ts
/*
* Interfaces
*/
export interface PayloadRepository {
[key: string]: any
full_name?: string
name: string
owner: {
[key: string]: any
login: string
name?: string
}
html_url?: string
}
export interface WebhookPayloadWithRepository {
[key: string]: any
repository?: PayloadRepository
issue?: {
[key: string]: any
number: number
html_url?: string
body?: string
}
pull_request?: {
[key: string]: any
number: number
html_url?: string
body?: string
}
sender?: {
[key: string]: any
type: string
}
action?: string
installation?: {
id: number
[key: string]: any
}
}
```
##### context.ts
Contains a GitHub context
```ts
export class Context {
/**
* Webhook payload object that triggered the workflow
*/
public payload: WebhookPayloadWithRepository
/**
* Name of the event that triggered the workflow
*/
public event: string
public sha: string
public ref: string
public workflow: string
public action: string
public actor: string
/**
* Hydrate the context from the environment
*/
constructor ()
public get issue ()
public get repo ()
}
```
##### github.ts
Contains a hydrated Octokit client
```ts
export class GithubClient extends Octokit {
// For making GraphQL requests
public graphql: (query: string, variables?: Variables) => Promise<GraphQlQueryResponse>
// Calls super and initializes graphql
constructor (token: string)
}
```
@@ -6,7 +6,7 @@ In order to support the node-config action, I propose adding the following into
Holds all the functions necessary for interacting with the runner/environment.
```
```ts
// Logging functions
export function debug(message: string): void
export function warning(message: string): void
@@ -66,7 +66,7 @@ export function setFailed(message: string): void
Holds all the functions necessary for file system manipulation (cli scenarios, not fs replacements):
```
```ts
/**
* Interface for cp/mv options
*/
@@ -132,7 +132,7 @@ export function which(tool: string, options?: WhichOptions): Promise<string>
Holds all the functions necessary for running the tools node-config depends on (aka 7-zip and tar)
```
```ts
/**
* Interface for exec options
*/
@@ -155,7 +155,7 @@ export function exec(commandLine: string, args?: string[], options?: IExecOption
Holds all the functions necessary for downloading and caching node.
```
```ts
/**
* Download a tool from an url and stream it into a file
*
-1
View File
@@ -4,7 +4,6 @@ module.exports = {
roots: ['<rootDir>/packages'],
testEnvironment: 'node',
testMatch: ['**/__tests__/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
+2 -2
View File
@@ -1,6 +1,6 @@
{
"packages": [
"packages/*"
"packages/**/*"
],
"version": "independent"
}
}
+24
View File
@@ -0,0 +1,24 @@
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": []
}
}
},
"affected": {
"defaultBase": "master"
},
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"namedInputs": {
"default": [
"{projectRoot}/**/*",
"sharedGlobals"
],
"sharedGlobals": [],
"production": [
"default"
]
}
}
+11838 -8977
View File
File diff suppressed because it is too large Load Diff
+23 -17
View File
@@ -2,29 +2,35 @@
"name": "root",
"private": true,
"scripts": {
"bootstrap": "lerna bootstrap",
"audit-all": "lerna run audit-moderate",
"bootstrap": "lerna exec -- npm install",
"build": "lerna run tsc",
"clean": "lerna clean",
"repair": "lerna repair",
"check-all": "concurrently \"npm:format-check\" \"npm:lint\" \"npm:test\" \"npm:build -- -- --noEmit\"",
"format": "prettier --write packages/**/*.ts",
"format-check": "prettier --check packages/**/*.ts",
"lint": "eslint packages/**/*.ts",
"lint-fix": "eslint packages/**/*.ts --fix",
"new-package": "scripts/create-package",
"test": "jest"
"test": "jest --testTimeout 10000"
},
"devDependencies": {
"@types/jest": "^24.0.11",
"@types/node": "^11.13.5",
"@types/signale": "^1.2.1",
"@typescript-eslint/parser": "^1.9.0",
"concurrently": "^4.1.0",
"eslint": "^5.16.0",
"eslint-plugin-github": "^2.0.0",
"eslint-plugin-jest": "^22.5.1",
"jest": "^24.7.1",
"jest-circus": "^24.7.1",
"lerna": "^3.13.3",
"prettier": "^1.17.0",
"ts-jest": "^24.0.2",
"typescript": "^3.4.4"
"@types/jest": "^29.5.4",
"@types/node": "^20.5.7",
"@types/signale": "^1.4.1",
"concurrently": "^6.1.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.9.0",
"eslint-plugin-github": "^4.9.2",
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-prettier": "^5.0.0",
"flow-bin": "^0.115.0",
"jest": "^29.6.4",
"lerna": "^7.1.4",
"nx": "16.6.0",
"prettier": "^3.0.0",
"ts-jest": "^29.1.1",
"typescript": "^5.2.2"
}
}
}
+43
View File
@@ -0,0 +1,43 @@
# Contributions
This package is used internally by the v4 versions of [upload-artifact](https://github.com/actions/upload-artifact) and [download-artifact](https://github.com/actions/download-artifact). This package can also be used by other actions to interact with artifacts. Any changes or updates to this package will propagate updates to these actions so it is important that major changes or updates get properly tested.
Any issues or feature requests that are related to the artifact actions should be filled in the appropriate repo.
A limited range of unit tests run as part of each PR when making changes to the artifact packages. For small contributions and fixes, they should be sufficient.
If making large changes, there are a few scenarios that should be tested:
- Uploading very large artifacts
- Uploading artifacts with lots of small files
- Uploading artifacts using a self-hosted runner (uploads and downloads behave differently due to extra latency)
- Downloading a single artifact (large and small, if lots of small files are part of an artifact, timeouts and non-success HTTP responses can be expected)
- Downloading all artifacts at once
Large architectural changes can impact upload/download performance so it is important to separately run extra tests. We request that any large contributions/changes have extra detailed testing so we can verify performance and possible regressions.
Tests will run for every push/pull_request [via Actions](https://github.com/actions/toolkit/blob/main/.github/workflows/artifact-tests.yml).
# Testing
## Package tests
To run unit tests for the `@actions/artifact` package:
1. Clone `actions/toolkit` locally
2. Install dependencies: `npm bootstrap`
3. Change working directory to `packages/artifact`
4. Run jest tests: `npm run test`
## Within upload-artifact or download-artifact actions
Any easy way to test changes for the official upload/download actions is to fork them, compile changes and run them.
1. For your local `actions/toolkit` changes:
1. Change directory to `packages/artifact`
2. Compile the changes: `npm run tsc`
3. Symlink your package change: `npm link`
2. Fork and clone either [upload-artifact](https://github.com/actions/upload-artifact) and [download-artifact](https://github.com/actions/download-artifact)
1. In the locally cloned fork, link to your local toolkit changes: `npm link @actions/artifact`
2. Then, compile your changes with: `npm run release`. The local `dist/index.js` should be updated with your changes.
3. Commit and push to your fork, you can then test with a `uses:` in your workflow pointed at your fork.
@@ -1,3 +1,5 @@
The MIT License (MIT)
Copyright 2019 GitHub
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:
+150
View File
@@ -0,0 +1,150 @@
# `@actions/artifact`
Interact programmatically with [Actions Artifacts](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts).
This is the core library that powers the [`@actions/upload-artifact`](https://github.com/actions/upload-artifact) and [`@actions/download-artifact`](https://github.com/actions/download-artifact) actions.
- [`@actions/artifact`](#actionsartifact)
- [v2 - What's New](#v2---whats-new)
- [Improvements](#improvements)
- [Breaking changes](#breaking-changes)
- [Quick Start](#quick-start)
- [Examples](#examples)
- [Upload and Download](#upload-and-download)
- [Downloading from other workflow runs or repos](#downloading-from-other-workflow-runs-or-repos)
- [Speeding up large uploads](#speeding-up-large-uploads)
- [Additional Resources](#additional-resources)
## v2 - What's New
> [!IMPORTANT]
> @actions/artifact v2+, upload-artifact@v4+ download-artifact@v4+ are not currently supported on GHES yet. The previous version of this package can be found at [this tag](https://github.com/actions/toolkit/tree/@actions/artifact@1.1.2/packages/artifact) and [on npm](https://www.npmjs.com/package/@actions/artifact/v/1.1.2).
The release of `@actions/artifact@v2` (including `upload-artifact@v4` and `download-artifact@v4`) are major changes to the backend architecture of Artifacts. They have numerous performance and behavioral improvements.
### Improvements
1. All upload and download operations are much quicker, up to 80% faster download times and 96% faster upload times in worst case scenarios.
2. Once uploaded, an Artifact ID is returned and Artifacts are immediately available in the UI and [REST API](https://docs.github.com/en/rest/actions/artifacts). Previously, you would have to wait for the run to be completed before an ID was available or any APIs could be utilized.
3. Artifacts can now be downloaded and deleted from the UI _before_ the entire workflow run finishes.
4. The contents of an Artifact are uploaded together into an _immutable_ archive. They cannot be altered by subsequent jobs. Both of these factors help reduce the possibility of accidentally corrupting Artifact files. (Digest/integrity hash coming soon in the API!)
5. This library (and `actions/download-artifact`) now support downloading Artifacts from _other_ repositories and runs if a `GITHUB_TOKEN` with sufficient `actions:read` permissions are provided.
### Breaking changes
1. Firewall rules required for self-hosted runners.
If you are using self-hosted runners behind a firewall, you must have flows open to [Actions endpoints](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#communication-between-self-hosted-runners-and-github). If you cannot use wildcard rules for your firewall, see the GitHub [meta endpoint](https://api.github.com/meta) for specific endpoints.
e.g.
```bash
curl https://api.github.com/meta | jq .domains.actions
```
2. Uploading to the same named Artifact multiple times.
Due to how Artifacts are created in this new version, it is no longer possible to upload to the same named Artifact multiple times. You must either split the uploads into multiple Artifacts with different names, or only upload once.
3. Limit of Artifacts for an individual job.
Each job in a workflow run now has a limit of 10 artifacts.
## Quick Start
Install the package:
```bash
npm i @actions/artifact
```
Import the module:
```js
// ES6 module
import artifact from '@actions/artifact'
// CommonJS
const {default: artifact} = require('@actions/artifact')
```
️ For a comprehensive list of classes, interfaces, functions and more, see the [generated documentation](./docs/generated/README.md).
## Examples
### Upload and Download
The most basic scenario is uploading one or more files to an Artifact, then downloading that Artifact. Downloads are based on the Artifact ID, which can be obtained in the response of `uploadArtifact`, `getArtifact`, `listArtifacts` or via the [REST API](https://docs.github.com/en/rest/actions/artifacts).
```js
const {id, size} = await artifact.uploadArtifact(
// name of the artifact
'my-artifact',
// files to include (supports absolute and relative paths)
['/absolute/path/file1.txt', './relative/file2.txt'],
{
// optional: how long to retain the artifact
// if unspecified, defaults to repository/org retention settings (the limit of this value)
retentionDays: 10
}
)
console.log(`Created artifact with id: ${id} (bytes: ${size}`)
const {downloadPath} = await artifact.downloadArtifact(id, {
// optional: download destination path. otherwise defaults to $GITHUB_WORKSPACE
path: '/tmp/dst/path',
})
console.log(`Downloaded artifact ${id} to: ${downloadPath}`)
```
### Downloading from other workflow runs or repos
It may be useful to download Artifacts from other workflow runs, or even other repositories. By default, the permissions are scoped so they can only download Artifacts within the current workflow run. To elevate permissions for this scenario, you must specify `options.findBy` to `downloadArtifact`.
```ts
const findBy = {
// must have actions:read permission on target repository
token: process.env['GITHUB_TOKEN'],
workflowRunId: 123,
repositoryOwner: 'actions',
repositoryName: 'toolkit'
}
await artifact.downloadArtifact(1337, {
findBy
})
// can also be used in other methods
await artifact.getArtifact('my-artifact', {
findBy
})
await artifact.listArtifacts({
findBy
})
```
### Speeding up large uploads
If you have large files that need to be uploaded (or file types that don't compress well), you may benefit from changing the compression level of the Artifact archive. NOTE: This is a tradeoff between artifact upload time and stored data size.
```ts
await artifact.uploadArtifact('my-massive-artifact', ['big_file.bin'], {
// The level of compression for Zlib to be applied to the artifact archive.
// - 0: No compression
// - 1: Best speed
// - 6: Default compression (same as GNU Gzip)
// - 9: Best compression
compressionLevel: 0
})
```
## Additional Resources
- [Releases](./RELEASES.md)
- [Contribution Guide](./CONTRIBUTIONS.md)
- [Frequently Asked Questions](./docs/faq.md)
+103
View File
@@ -0,0 +1,103 @@
# @actions/artifact Releases
### 0.1.0
- Initial release
### 0.2.0
- Fixes to TCP connections not closing
- GZip file compression to speed up downloads
- Improved logging and output
- Extra documentation
### 0.3.0
- Fixes to gzip decompression when downloading artifacts
- Support handling 429 response codes
- Improved download experience when dealing with empty files
- Exponential backoff when retryable status codes are encountered
- Clearer error message if storage quota has been reached
- Improved logging and output during artifact download
### 0.3.1
- Fix to ensure temporary gzip files get correctly deleted during artifact upload
- Remove spaces as a forbidden character during upload
### 0.3.2
- Fix to ensure readstreams get correctly reset in the event of a retry
### 0.3.3
- Increase chunk size during upload from 4MB to 8MB
- Improve user-agent strings during API calls to help internally diagnose issues
### 0.3.5
- Retry in the event of a 413 response
### 0.4.0
- Add option to specify custom retentions on artifacts
### 0.4.1
- Update to latest @actions/core version
### 0.4.2
- Improved retry-ability when a partial artifact download is encountered
### 0.5.0
- Improved retry-ability for all http calls during artifact upload and download if an error is encountered
### 0.5.1
- Bump @actions/http-client to version 1.0.11 to fix proxy related issues during artifact upload and download
### 0.5.2
- Add HTTP 500 as a retryable status code for artifact upload and download.
### 0.6.0
- Support upload from named pipes [#748](https://github.com/actions/toolkit/pull/748)
- Fixes to percentage values being greater than 100% when downloading all artifacts [#889](https://github.com/actions/toolkit/pull/889)
- Improved logging and output during artifact upload [#949](https://github.com/actions/toolkit/pull/949)
- Improvements to client-side validation for certain invalid characters not allowed during upload: [#951](https://github.com/actions/toolkit/pull/951)
- Faster upload speeds for certain types of large files by exempting gzip compression [#956](https://github.com/actions/toolkit/pull/956)
- More detailed logging when dealing with chunked uploads [#957](https://github.com/actions/toolkit/pull/957)
### 0.6.1
- Fix for failing 0 byte file uploads on Windows [#962](https://github.com/actions/toolkit/pull/962)
### 1.0.0
- Update `lockfileVersion` to `v2` in `package-lock.json` [#1009](https://github.com/actions/toolkit/pull/1009)
### 1.0.1
- Update to v2.0.0 of `@actions/http-client`
### 1.0.2
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 1.1.0
- Add `x-actions-results-crc64` and `x-actions-results-md5` checksum headers on upload [#1063](https://github.com/actions/toolkit/pull/1063)
### 1.1.1
- Fixed a bug in Node16 where if an HTTP download finished too quickly (<1ms, e.g. when it's mocked) we attempt to delete a temp file that has not been created yet [#1278](https://github.com/actions/toolkit/pull/1278/commits/b9de68a590daf37c6747e38d3cb4f1dd2cfb791c)
### 2.0.0
Major release. Supports new Artifact backend for improved speed, reliability and behavior.
Numerous API changes, [some breaking](./README.md#breaking-changes).
Blog post with more info: TBD
@@ -0,0 +1,300 @@
import * as http from 'http'
import * as net from 'net'
import {HttpClient} from '@actions/http-client'
import * as config from '../src/internal/shared/config'
import {internalArtifactTwirpClient} from '../src/internal/shared/artifact-twirp-client'
import {noopLogs} from './common'
import {NetworkError, UsageError} from '../src/internal/shared/errors'
jest.mock('@actions/http-client')
const clientOptions = {
maxAttempts: 5,
retryIntervalMs: 1,
retryMultiplier: 1.5
}
describe('artifact-http-client', () => {
beforeAll(() => {
noopLogs()
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('http://localhost:8080')
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('token')
})
beforeEach(() => {
jest.clearAllMocks()
})
it('should successfully create a client', () => {
const client = internalArtifactTwirpClient()
expect(client).toBeDefined()
})
it('should make a request', async () => {
const mockPost = jest.fn(() => {
const msg = new http.IncomingMessage(new net.Socket())
msg.statusCode = 200
return {
message: msg,
readBody: async () => {
return Promise.resolve(
`{"ok": true, "signedUploadUrl": "http://localhost:8080/upload"}`
)
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient()
const artifact = await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(mockPost).toHaveBeenCalledTimes(1)
expect(artifact).toBeDefined()
expect(artifact.ok).toBe(true)
expect(artifact.signedUploadUrl).toBe('http://localhost:8080/upload')
})
it('should retry if the request fails', async () => {
const mockPost = jest
.fn(() => {
const msgSucceeded = new http.IncomingMessage(new net.Socket())
msgSucceeded.statusCode = 200
return {
message: msgSucceeded,
readBody: async () => {
return Promise.resolve(
`{"ok": true, "signedUploadUrl": "http://localhost:8080/upload"}`
)
}
}
})
.mockImplementationOnce(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
msgFailed.statusCode = 500
msgFailed.statusMessage = 'Internal Server Error'
return {
message: msgFailed,
readBody: async () => {
return Promise.resolve(`{"ok": false}`)
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient(clientOptions)
const artifact = await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(artifact).toBeDefined()
expect(artifact.ok).toBe(true)
expect(artifact.signedUploadUrl).toBe('http://localhost:8080/upload')
expect(mockPost).toHaveBeenCalledTimes(2)
})
it('should fail if the request fails 5 times', async () => {
const mockPost = jest.fn(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
msgFailed.statusCode = 500
msgFailed.statusMessage = 'Internal Server Error'
return {
message: msgFailed,
readBody: async () => {
return Promise.resolve(`{"ok": false}`)
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient(clientOptions)
await expect(async () => {
await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
}).rejects.toThrowError(
'Failed to make request after 5 attempts: Failed request: (500) Internal Server Error'
)
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(mockPost).toHaveBeenCalledTimes(5)
})
it('should fail immediately if there is a non-retryable error', async () => {
const mockPost = jest.fn(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
msgFailed.statusCode = 401
msgFailed.statusMessage = 'Unauthorized'
return {
message: msgFailed,
readBody: async () => {
return Promise.resolve(`{"ok": false}`)
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient(clientOptions)
await expect(async () => {
await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
}).rejects.toThrowError(
'Received non-retryable error: Failed request: (401) Unauthorized'
)
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(mockPost).toHaveBeenCalledTimes(1)
})
it('should fail with a descriptive error', async () => {
// 409 duplicate error
const mockPost = jest.fn(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
msgFailed.statusCode = 409
msgFailed.statusMessage = 'Conflict'
return {
message: msgFailed,
readBody: async () => {
return Promise.resolve(
`{"msg": "an artifact with this name already exists on the workflow run"}`
)
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient(clientOptions)
await expect(async () => {
await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
}).rejects.toThrowError(
'Failed to CreateArtifact: Received non-retryable error: Failed request: (409) Conflict: an artifact with this name already exists on the workflow run'
)
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(mockPost).toHaveBeenCalledTimes(1)
})
it('should properly describe a network failure', async () => {
class FakeNodeError extends Error {
code: string
constructor(code: string) {
super()
this.code = code
}
}
const mockPost = jest.fn(() => {
throw new FakeNodeError('ENOTFOUND')
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient()
await expect(async () => {
await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
}).rejects.toThrowError(new NetworkError('ENOTFOUND').message)
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(mockPost).toHaveBeenCalledTimes(1)
})
it('should properly describe a usage error', async () => {
const mockPost = jest.fn(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
msgFailed.statusCode = 403
msgFailed.statusMessage = 'Forbidden'
return {
message: msgFailed,
readBody: async () => {
return Promise.resolve(
`{"msg": "insufficient usage to create artifact"}`
)
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient()
await expect(async () => {
await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
}).rejects.toThrowError(new UsageError().message)
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(mockPost).toHaveBeenCalledTimes(1)
})
})
+9
View File
@@ -0,0 +1,9 @@
import * as core from '@actions/core'
// noopLogs mocks the console.log and core.* functions to prevent output in the console while testing
export const noopLogs = (): void => {
jest.spyOn(console, 'log').mockImplementation(() => {})
jest.spyOn(core, 'debug').mockImplementation(() => {})
jest.spyOn(core, 'info').mockImplementation(() => {})
jest.spyOn(core, 'warning').mockImplementation(() => {})
}
@@ -0,0 +1,468 @@
import fs from 'fs'
import * as http from 'http'
import * as net from 'net'
import * as path from 'path'
import * as github from '@actions/github'
import {HttpClient} from '@actions/http-client'
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
import archiver from 'archiver'
import {
downloadArtifactInternal,
downloadArtifactPublic
} from '../src/internal/download/download-artifact'
import {getUserAgentString} from '../src/internal/shared/user-agent'
import {noopLogs} from './common'
import * as config from '../src/internal/shared/config'
import {ArtifactServiceClientJSON} from '../src/generated'
import * as util from '../src/internal/shared/util'
type MockedDownloadArtifact = jest.MockedFunction<
RestEndpointMethods['actions']['downloadArtifact']
>
const testDir = path.join(__dirname, '_temp', 'download-artifact')
const fixtures = {
workspaceDir: path.join(testDir, 'workspace'),
exampleArtifact: {
path: path.join(testDir, 'artifact.zip'),
files: [
{
path: 'hello.txt',
content: 'Hello World!'
},
{
path: 'goodbye.txt',
content: 'Goodbye World!'
}
]
},
artifactID: 1234,
artifactName: 'my-artifact',
artifactSize: 123456,
repositoryOwner: 'actions',
repositoryName: 'toolkit',
token: 'ghp_1234567890',
blobStorageUrl: 'https://blob-storage.local?signed=true',
backendIds: {
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
}
}
jest.mock('@actions/github', () => ({
getOctokit: jest.fn().mockReturnValue({
rest: {
actions: {
downloadArtifact: jest.fn()
}
}
})
}))
jest.mock('@actions/http-client')
// Create a zip archive with the contents of the example artifact
const createTestArchive = async (): Promise<void> => {
const archive = archiver('zip', {
zlib: {level: 9}
})
for (const file of fixtures.exampleArtifact.files) {
archive.append(file.content, {name: file.path})
}
archive.finalize()
return new Promise((resolve, reject) => {
archive.pipe(fs.createWriteStream(fixtures.exampleArtifact.path))
archive.on('error', reject)
archive.on('finish', resolve)
})
}
const expectExtractedArchive = async (dir: string): Promise<void> => {
for (const file of fixtures.exampleArtifact.files) {
const filePath = path.join(dir, file.path)
expect(fs.readFileSync(filePath, 'utf8')).toEqual(file.content)
}
}
const setup = async (): Promise<void> => {
noopLogs()
await fs.promises.mkdir(testDir, {recursive: true})
await createTestArchive()
process.env['GITHUB_WORKSPACE'] = fixtures.workspaceDir
}
const cleanup = async (): Promise<void> => {
jest.restoreAllMocks()
await fs.promises.rm(testDir, {recursive: true})
delete process.env['GITHUB_WORKSPACE']
}
const mockGetArtifactSuccess = jest.fn(() => {
const message = new http.IncomingMessage(new net.Socket())
message.statusCode = 200
message.push(fs.readFileSync(fixtures.exampleArtifact.path))
message.push(null)
return {
message
}
})
const mockGetArtifactFailure = jest.fn(() => {
const message = new http.IncomingMessage(new net.Socket())
message.statusCode = 500
message.push('Internal Server Error')
message.push(null)
return {
message
}
})
describe('download-artifact', () => {
describe('public', () => {
beforeEach(setup)
afterEach(cleanup)
it('should successfully download an artifact to $GITHUB_WORKSPACE', async () => {
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
.actions.downloadArtifact as MockedDownloadArtifact
downloadArtifactMock.mockResolvedValueOnce({
headers: {
location: fixtures.blobStorageUrl
},
status: 302,
url: '',
data: Buffer.from('')
})
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
() => {
return {
get: mockGetArtifactSuccess
}
}
)
const response = await downloadArtifactPublic(
fixtures.artifactID,
fixtures.repositoryOwner,
fixtures.repositoryName,
fixtures.token
)
expect(downloadArtifactMock).toHaveBeenCalledWith({
owner: fixtures.repositoryOwner,
repo: fixtures.repositoryName,
artifact_id: fixtures.artifactID,
archive_format: 'zip',
request: {
redirect: 'manual'
}
})
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
expect(mockGetArtifactSuccess).toHaveBeenCalledWith(
fixtures.blobStorageUrl
)
expectExtractedArchive(fixtures.workspaceDir)
expect(response.downloadPath).toBe(fixtures.workspaceDir)
})
it('should successfully download an artifact to user defined path', async () => {
const customPath = path.join(testDir, 'custom')
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
.actions.downloadArtifact as MockedDownloadArtifact
downloadArtifactMock.mockResolvedValueOnce({
headers: {
location: fixtures.blobStorageUrl
},
status: 302,
url: '',
data: Buffer.from('')
})
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
() => {
return {
get: mockGetArtifactSuccess
}
}
)
const response = await downloadArtifactPublic(
fixtures.artifactID,
fixtures.repositoryOwner,
fixtures.repositoryName,
fixtures.token,
{
path: customPath
}
)
expect(downloadArtifactMock).toHaveBeenCalledWith({
owner: fixtures.repositoryOwner,
repo: fixtures.repositoryName,
artifact_id: fixtures.artifactID,
archive_format: 'zip',
request: {
redirect: 'manual'
}
})
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
expect(mockGetArtifactSuccess).toHaveBeenCalledWith(
fixtures.blobStorageUrl
)
expectExtractedArchive(customPath)
expect(response.downloadPath).toBe(customPath)
})
it('should fail if download artifact API does not respond with location', async () => {
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
.actions.downloadArtifact as MockedDownloadArtifact
downloadArtifactMock.mockResolvedValueOnce({
headers: {},
status: 302,
url: '',
data: Buffer.from('')
})
await expect(
downloadArtifactPublic(
fixtures.artifactID,
fixtures.repositoryOwner,
fixtures.repositoryName,
fixtures.token
)
).rejects.toBeInstanceOf(Error)
expect(downloadArtifactMock).toHaveBeenCalledWith({
owner: fixtures.repositoryOwner,
repo: fixtures.repositoryName,
artifact_id: fixtures.artifactID,
archive_format: 'zip',
request: {
redirect: 'manual'
}
})
})
it('should fail if blob storage response is non-200', async () => {
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
.actions.downloadArtifact as MockedDownloadArtifact
downloadArtifactMock.mockResolvedValueOnce({
headers: {
location: fixtures.blobStorageUrl
},
status: 302,
url: '',
data: Buffer.from('')
})
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
() => {
return {
get: mockGetArtifactFailure
}
}
)
await expect(
downloadArtifactPublic(
fixtures.artifactID,
fixtures.repositoryOwner,
fixtures.repositoryName,
fixtures.token
)
).rejects.toBeInstanceOf(Error)
expect(downloadArtifactMock).toHaveBeenCalledWith({
owner: fixtures.repositoryOwner,
repo: fixtures.repositoryName,
artifact_id: fixtures.artifactID,
archive_format: 'zip',
request: {
redirect: 'manual'
}
})
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
expect(mockGetArtifactFailure).toHaveBeenCalledWith(
fixtures.blobStorageUrl
)
})
})
describe('internal', () => {
beforeEach(async () => {
await setup()
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(util, 'getBackendIdsFromToken')
.mockReturnValue(fixtures.backendIds)
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://results.local')
})
afterEach(async () => {
await cleanup()
})
it('should successfully download an artifact to $GITHUB_WORKSPACE', async () => {
const mockListArtifacts = jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: [
{
...fixtures.backendIds,
databaseId: fixtures.artifactID.toString(),
name: fixtures.artifactName,
size: fixtures.artifactSize.toString()
}
]
})
const mockGetSignedArtifactURL = jest
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
.mockReturnValue(
Promise.resolve({
signedUrl: fixtures.blobStorageUrl
})
)
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
() => {
return {
get: mockGetArtifactSuccess
}
}
)
const response = await downloadArtifactInternal(fixtures.artifactID)
expectExtractedArchive(fixtures.workspaceDir)
expect(response.downloadPath).toBe(fixtures.workspaceDir)
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
expect(mockListArtifacts).toHaveBeenCalledWith({
idFilter: {
value: fixtures.artifactID.toString()
},
...fixtures.backendIds
})
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
...fixtures.backendIds,
name: fixtures.artifactName
})
})
it('should successfully download an artifact to user defined path', async () => {
const customPath = path.join(testDir, 'custom')
const mockListArtifacts = jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: [
{
...fixtures.backendIds,
databaseId: fixtures.artifactID.toString(),
name: fixtures.artifactName,
size: fixtures.artifactSize.toString()
}
]
})
const mockGetSignedArtifactURL = jest
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
.mockReturnValue(
Promise.resolve({
signedUrl: fixtures.blobStorageUrl
})
)
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
() => {
return {
get: mockGetArtifactSuccess
}
}
)
const response = await downloadArtifactInternal(fixtures.artifactID, {
path: customPath
})
expectExtractedArchive(customPath)
expect(response.downloadPath).toBe(customPath)
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
expect(mockListArtifacts).toHaveBeenCalledWith({
idFilter: {
value: fixtures.artifactID.toString()
},
...fixtures.backendIds
})
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
...fixtures.backendIds,
name: fixtures.artifactName
})
})
it('should fail if download artifact API does not respond with location', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockRejectedValue(new Error('boom'))
await expect(
downloadArtifactInternal(fixtures.artifactID)
).rejects.toBeInstanceOf(Error)
})
it('should fail if blob storage response is non-200', async () => {
const mockListArtifacts = jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: [
{
...fixtures.backendIds,
databaseId: fixtures.artifactID.toString(),
name: fixtures.artifactName,
size: fixtures.artifactSize.toString()
}
]
})
const mockGetSignedArtifactURL = jest
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
.mockReturnValue(
Promise.resolve({
signedUrl: fixtures.blobStorageUrl
})
)
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
() => {
return {
get: mockGetArtifactFailure
}
}
)
await expect(
downloadArtifactInternal(fixtures.artifactID)
).rejects.toBeInstanceOf(Error)
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
expect(mockListArtifacts).toHaveBeenCalledWith({
idFilter: {
value: fixtures.artifactID.toString()
},
...fixtures.backendIds
})
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
...fixtures.backendIds,
name: fixtures.artifactName
})
})
})
})
@@ -0,0 +1,239 @@
import * as github from '@actions/github'
import type {RequestInterface} from '@octokit/types'
import {
getArtifactInternal,
getArtifactPublic
} from '../src/internal/find/get-artifact'
import * as config from '../src/internal/shared/config'
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
import * as util from '../src/internal/shared/util'
import {noopLogs} from './common'
import {
ArtifactNotFoundError,
InvalidResponseError
} from '../src/internal/shared/errors'
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
jest.mock('@actions/github', () => ({
getOctokit: jest.fn().mockReturnValue({
request: jest.fn()
})
}))
const fixtures = {
repo: 'toolkit',
owner: 'actions',
token: 'ghp_1234567890',
runId: 123,
backendIds: {
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
},
artifacts: [
{
id: 1,
name: 'my-artifact',
size: 456,
createdAt: new Date('2023-12-01')
},
{
id: 2,
name: 'my-artifact',
size: 456,
createdAt: new Date('2023-12-02')
}
]
}
describe('get-artifact', () => {
beforeAll(() => {
noopLogs()
})
describe('public', () => {
it('should return the artifact if it is found', async () => {
const mockRequest = github.getOctokit(fixtures.token)
.request as MockedRequest
mockRequest.mockResolvedValueOnce({
status: 200,
headers: {},
url: '',
data: {
artifacts: [
{
name: fixtures.artifacts[0].name,
id: fixtures.artifacts[0].id,
size_in_bytes: fixtures.artifacts[0].size,
created_at: fixtures.artifacts[0].createdAt.toISOString()
}
]
}
})
const response = await getArtifactPublic(
fixtures.artifacts[0].name,
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token
)
expect(response).toEqual({
artifact: fixtures.artifacts[0]
})
})
it('should return the latest artifact if multiple are found', async () => {
const mockRequest = github.getOctokit(fixtures.token)
.request as MockedRequest
mockRequest.mockResolvedValueOnce({
status: 200,
headers: {},
url: '',
data: {
artifacts: fixtures.artifacts.map(artifact => ({
name: artifact.name,
id: artifact.id,
size_in_bytes: artifact.size,
created_at: artifact.createdAt.toISOString()
}))
}
})
const response = await getArtifactPublic(
fixtures.artifacts[0].name,
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token
)
expect(response).toEqual({
artifact: fixtures.artifacts[1]
})
})
it('should fail if no artifacts are found', async () => {
const mockRequest = github.getOctokit(fixtures.token)
.request as MockedRequest
mockRequest.mockResolvedValueOnce({
status: 200,
headers: {},
url: '',
data: {
artifacts: []
}
})
const response = getArtifactPublic(
fixtures.artifacts[0].name,
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token
)
expect(response).rejects.toThrowError(ArtifactNotFoundError)
})
it('should fail if non-200 response', async () => {
const mockRequest = github.getOctokit(fixtures.token)
.request as MockedRequest
mockRequest.mockResolvedValueOnce({
status: 404,
headers: {},
url: '',
data: {}
})
const response = getArtifactPublic(
fixtures.artifacts[0].name,
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token
)
expect(response).rejects.toThrowError(InvalidResponseError)
})
})
describe('internal', () => {
beforeEach(() => {
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(util, 'getBackendIdsFromToken')
.mockReturnValue(fixtures.backendIds)
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://results.local')
})
it('should return the artifact if it is found', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: [
{
...fixtures.backendIds,
databaseId: fixtures.artifacts[0].id.toString(),
name: fixtures.artifacts[0].name,
size: fixtures.artifacts[0].size.toString(),
createdAt: Timestamp.fromDate(fixtures.artifacts[0].createdAt)
}
]
})
const response = await getArtifactInternal(fixtures.artifacts[0].name)
expect(response).toEqual({
artifact: fixtures.artifacts[0]
})
})
it('should return the latest artifact if multiple are found', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: fixtures.artifacts.map(artifact => ({
...fixtures.backendIds,
databaseId: artifact.id.toString(),
name: artifact.name,
size: artifact.size.toString(),
createdAt: Timestamp.fromDate(artifact.createdAt)
}))
})
const response = await getArtifactInternal(fixtures.artifacts[0].name)
expect(response).toEqual({
artifact: fixtures.artifacts[1]
})
})
it('should fail if no artifacts are found', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: []
})
const response = getArtifactInternal(fixtures.artifacts[0].name)
expect(response).rejects.toThrowError(ArtifactNotFoundError)
})
it('should fail if non-200 response', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockRejectedValue(new Error('boom'))
const response = getArtifactInternal(fixtures.artifacts[0].name)
expect(response).rejects.toThrow()
})
})
})
@@ -0,0 +1,242 @@
import * as github from '@actions/github'
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
import type {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types'
import {
listArtifactsInternal,
listArtifactsPublic
} from '../src/internal/find/list-artifacts'
import * as config from '../src/internal/shared/config'
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
import * as util from '../src/internal/shared/util'
import {noopLogs} from './common'
import {Artifact} from '../src/internal/shared/interfaces'
type MockedListWorkflowRunArtifacts = jest.MockedFunction<
RestEndpointMethods['actions']['listWorkflowRunArtifacts']
>
jest.mock('@actions/github', () => ({
getOctokit: jest.fn().mockReturnValue({
rest: {
actions: {
listWorkflowRunArtifacts: jest.fn()
}
}
})
}))
const artifactsToListResponse = (
artifacts: Artifact[]
): RestEndpointMethodTypes['actions']['listWorkflowRunArtifacts']['response']['data'] => {
return {
total_count: artifacts.length,
artifacts: artifacts.map(artifact => ({
name: artifact.name,
id: artifact.id,
size_in_bytes: artifact.size,
created_at: artifact.createdAt?.toISOString() || '',
run_id: fixtures.runId,
// unused fields for tests
url: '',
archive_download_url: '',
expired: false,
expires_at: '',
node_id: '',
run_url: '',
type: '',
updated_at: ''
}))
}
}
const fixtures = {
repo: 'toolkit',
owner: 'actions',
token: 'ghp_1234567890',
runId: 123,
backendIds: {
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
},
artifacts: [
{
id: 1,
name: 'my-artifact',
size: 456,
createdAt: new Date('2023-12-01')
},
{
id: 2,
name: 'my-artifact',
size: 456,
createdAt: new Date('2023-12-02')
}
]
}
describe('list-artifact', () => {
beforeAll(() => {
noopLogs()
})
describe('public', () => {
it('should return a list of artifacts', async () => {
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
mockListArtifacts.mockResolvedValueOnce({
status: 200,
headers: {},
url: '',
data: artifactsToListResponse(fixtures.artifacts)
})
const response = await listArtifactsPublic(
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token,
false
)
expect(response).toEqual({
artifacts: fixtures.artifacts
})
})
it('should return the latest artifact when latest is specified', async () => {
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
mockListArtifacts.mockResolvedValueOnce({
status: 200,
headers: {},
url: '',
data: artifactsToListResponse(fixtures.artifacts)
})
const response = await listArtifactsPublic(
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token,
true
)
expect(response).toEqual({
artifacts: [fixtures.artifacts[1]]
})
})
it('can return empty artifacts', async () => {
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
mockListArtifacts.mockResolvedValueOnce({
status: 200,
headers: {},
url: '',
data: {
total_count: 0,
artifacts: []
}
})
const response = await listArtifactsPublic(
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token,
true
)
expect(response).toEqual({
artifacts: []
})
})
it('should fail if non-200 response', async () => {
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
mockListArtifacts.mockRejectedValue(new Error('boom'))
await expect(
listArtifactsPublic(
fixtures.runId,
fixtures.owner,
fixtures.repo,
fixtures.token,
false
)
).rejects.toThrow('boom')
})
})
describe('internal', () => {
beforeEach(() => {
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(util, 'getBackendIdsFromToken')
.mockReturnValue(fixtures.backendIds)
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://results.local')
})
it('should return a list of artifacts', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: fixtures.artifacts.map(artifact => ({
...fixtures.backendIds,
databaseId: artifact.id.toString(),
name: artifact.name,
size: artifact.size.toString(),
createdAt: Timestamp.fromDate(artifact.createdAt)
}))
})
const response = await listArtifactsInternal(false)
expect(response).toEqual({
artifacts: fixtures.artifacts
})
})
it('should return the latest artifact when latest is specified', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: fixtures.artifacts.map(artifact => ({
...fixtures.backendIds,
databaseId: artifact.id.toString(),
name: artifact.name,
size: artifact.size.toString(),
createdAt: Timestamp.fromDate(artifact.createdAt)
}))
})
const response = await listArtifactsInternal(true)
expect(response).toEqual({
artifacts: [fixtures.artifacts[1]]
})
})
it('can return empty artifacts', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockResolvedValue({
artifacts: []
})
const response = await listArtifactsInternal(false)
expect(response).toEqual({
artifacts: []
})
})
it('should fail if non-200 response', async () => {
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
.mockRejectedValue(new Error('boom'))
await expect(listArtifactsInternal(false)).rejects.toThrow('boom')
})
})
})
@@ -0,0 +1,75 @@
import {
validateArtifactName,
validateFilePath
} from '../src/internal/upload/path-and-artifact-name-validation'
import {noopLogs} from './common'
describe('Path and artifact name validation', () => {
beforeAll(() => {
noopLogs()
})
it('Check Artifact Name for any invalid characters', () => {
const invalidNames = [
'my\\artifact',
'my/artifact',
'my"artifact',
'my:artifact',
'my<artifact',
'my>artifact',
'my|artifact',
'my*artifact',
'my?artifact',
''
]
for (const invalidName of invalidNames) {
expect(() => {
validateArtifactName(invalidName)
}).toThrow()
}
const validNames = [
'my-normal-artifact',
'myNormalArtifact',
'm¥ñðrmålÄr†ï£å¢†'
]
for (const validName of validNames) {
expect(() => {
validateArtifactName(validName)
}).not.toThrow()
}
})
it('Check Artifact File Path for any invalid characters', () => {
const invalidNames = [
'some/invalid"artifact/path',
'some/invalid:artifact/path',
'some/invalid<artifact/path',
'some/invalid>artifact/path',
'some/invalid|artifact/path',
'some/invalid*artifact/path',
'some/invalid?artifact/path',
'some/invalid\rartifact/path',
'some/invalid\nartifact/path',
'some/invalid\r\nartifact/path',
''
]
for (const invalidName of invalidNames) {
expect(() => {
validateFilePath(invalidName)
}).toThrow()
}
const validNames = [
'my/perfectly-normal/artifact-path',
'my/perfectly\\Normal/Artifact-path',
'm¥/ñðrmål/Är†ï£å¢†'
]
for (const validName of validNames) {
expect(() => {
validateFilePath(validName)
}).not.toThrow()
}
})
})
@@ -0,0 +1,65 @@
import {Timestamp} from '../src/generated'
import * as retention from '../src/internal/upload/retention'
describe('retention', () => {
beforeEach(() => {
delete process.env['GITHUB_RETENTION_DAYS']
})
it('should return the inputted retention days if it is less than the max retention days', () => {
// setup
const mockDate = new Date('2020-01-01')
jest.useFakeTimers().setSystemTime(mockDate)
process.env['GITHUB_RETENTION_DAYS'] = '90'
const exp = retention.getExpiration(30)
expect(exp).toBeDefined()
if (exp) {
const expDate = Timestamp.toDate(exp)
const expected = new Date()
expected.setDate(expected.getDate() + 30)
expect(expDate).toEqual(expected)
}
})
it('should return the max retention days if the inputted retention days is greater than the max retention days', () => {
// setup
const mockDate = new Date('2020-01-01')
jest.useFakeTimers().setSystemTime(mockDate)
process.env['GITHUB_RETENTION_DAYS'] = '90'
const exp = retention.getExpiration(120)
expect(exp).toBeDefined()
if (exp) {
const expDate = Timestamp.toDate(exp) // we check whether exp is defined above
const expected = new Date()
expected.setDate(expected.getDate() + 90)
expect(expDate).toEqual(expected)
}
})
it('should return undefined if the inputted retention days is undefined', () => {
const exp = retention.getExpiration()
expect(exp).toBeUndefined()
})
it('should return the inputted retention days if there is no max retention days', () => {
// setup
const mockDate = new Date('2020-01-01')
jest.useFakeTimers().setSystemTime(mockDate)
const exp = retention.getExpiration(30)
expect(exp).toBeDefined()
if (exp) {
const expDate = Timestamp.toDate(exp) // we check whether exp is defined above
const expected = new Date()
expected.setDate(expected.getDate() + 30)
expect(expDate).toEqual(expected)
}
})
})
@@ -0,0 +1,354 @@
import * as uploadZipSpecification from '../src/internal/upload/upload-zip-specification'
import * as zip from '../src/internal/upload/zip'
import * as util from '../src/internal/shared/util'
import * as retention from '../src/internal/upload/retention'
import * as config from '../src/internal/shared/config'
import {Timestamp, ArtifactServiceClientJSON} from '../src/generated'
import * as blobUpload from '../src/internal/upload/blob-upload'
import {uploadArtifact} from '../src/internal/upload/upload-artifact'
import {noopLogs} from './common'
import {FilesNotFoundError} from '../src/internal/shared/errors'
describe('upload-artifact', () => {
beforeEach(() => {
noopLogs()
})
afterEach(() => {
jest.restoreAllMocks()
})
it('should successfully upload an artifact', () => {
const mockDate = new Date('2020-01-01')
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([
{
sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt'
},
{
sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt'
},
{
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt'
}
])
jest
.spyOn(zip, 'createZipUploadStream')
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678'
})
jest
.spyOn(retention, 'getExpiration')
.mockReturnValue(Timestamp.fromDate(mockDate))
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
.mockReturnValue(
Promise.resolve({
ok: true,
signedUploadUrl: 'https://signed-upload-url.com'
})
)
jest.spyOn(blobUpload, 'uploadZipToBlobStorage').mockReturnValue(
Promise.resolve({
uploadSize: 1234,
sha256Hash: 'test-sha256-hash'
})
)
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'FinalizeArtifact')
.mockReturnValue(Promise.resolve({ok: true, artifactId: '1'}))
// ArtifactHttpClient mocks
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://test-url.com')
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).resolves.toEqual({size: 1234, id: 1})
})
it('should throw an error if the root directory is invalid', () => {
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockImplementation(() => {
throw new Error('Invalid root directory')
})
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrow('Invalid root directory')
})
it('should reject if there are no files to upload', () => {
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([])
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrowError(FilesNotFoundError)
})
it('should reject if no backend IDs are found', () => {
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([
{
sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt'
},
{
sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt'
},
{
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt'
}
])
jest
.spyOn(zip, 'createZipUploadStream')
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrow()
})
it('should return false if the creation request fails', () => {
const mockDate = new Date('2020-01-01')
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([
{
sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt'
},
{
sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt'
},
{
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt'
}
])
jest
.spyOn(zip, 'createZipUploadStream')
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678'
})
jest
.spyOn(retention, 'getExpiration')
.mockReturnValue(Timestamp.fromDate(mockDate))
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
.mockReturnValue(Promise.resolve({ok: false, signedUploadUrl: ''}))
// ArtifactHttpClient mocks
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://test-url.com')
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrow()
})
it('should return false if blob storage upload is unsuccessful', () => {
const mockDate = new Date('2020-01-01')
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([
{
sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt'
},
{
sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt'
},
{
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt'
}
])
jest
.spyOn(zip, 'createZipUploadStream')
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678'
})
jest
.spyOn(retention, 'getExpiration')
.mockReturnValue(Timestamp.fromDate(mockDate))
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
.mockReturnValue(
Promise.resolve({
ok: true,
signedUploadUrl: 'https://signed-upload-url.com'
})
)
jest
.spyOn(blobUpload, 'uploadZipToBlobStorage')
.mockReturnValue(Promise.reject(new Error('boom')))
// ArtifactHttpClient mocks
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://test-url.com')
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrow()
})
it('should reject if finalize artifact fails', () => {
const mockDate = new Date('2020-01-01')
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([
{
sourcePath: '/home/user/files/plz-upload/file1.txt',
destinationPath: 'file1.txt'
},
{
sourcePath: '/home/user/files/plz-upload/file2.txt',
destinationPath: 'file2.txt'
},
{
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
destinationPath: 'dir/file3.txt'
}
])
jest
.spyOn(zip, 'createZipUploadStream')
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678'
})
jest
.spyOn(retention, 'getExpiration')
.mockReturnValue(Timestamp.fromDate(mockDate))
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
.mockReturnValue(
Promise.resolve({
ok: true,
signedUploadUrl: 'https://signed-upload-url.com'
})
)
jest.spyOn(blobUpload, 'uploadZipToBlobStorage').mockReturnValue(
Promise.resolve({
uploadSize: 1234,
sha256Hash: 'test-sha256-hash'
})
)
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'FinalizeArtifact')
.mockReturnValue(Promise.resolve({ok: false, artifactId: ''}))
// ArtifactHttpClient mocks
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://test-url.com')
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrow()
})
})
@@ -0,0 +1,308 @@
import * as io from '../../io/src/io'
import * as path from 'path'
import {promises as fs} from 'fs'
import {
getUploadZipSpecification,
validateRootDirectory
} from '../src/internal/upload/upload-zip-specification'
import {noopLogs} from './common'
const root = path.join(__dirname, '_temp', 'upload-specification')
const goodItem1Path = path.join(
root,
'folder-a',
'folder-b',
'folder-c',
'good-item1.txt'
)
const goodItem2Path = path.join(root, 'folder-d', 'good-item2.txt')
const goodItem3Path = path.join(root, 'folder-d', 'good-item3.txt')
const goodItem4Path = path.join(root, 'folder-d', 'good-item4.txt')
const goodItem5Path = path.join(root, 'good-item5.txt')
const badItem1Path = path.join(
root,
'folder-a',
'folder-b',
'folder-c',
'bad-item1.txt'
)
const badItem2Path = path.join(root, 'folder-d', 'bad-item2.txt')
const badItem3Path = path.join(root, 'folder-f', 'bad-item3.txt')
const badItem4Path = path.join(root, 'folder-h', 'folder-i', 'bad-item4.txt')
const badItem5Path = path.join(root, 'folder-h', 'folder-i', 'bad-item5.txt')
const extraFileInFolderCPath = path.join(
root,
'folder-a',
'folder-b',
'folder-c',
'extra-file-in-folder-c.txt'
)
const amazingFileInFolderHPath = path.join(root, 'folder-h', 'amazing-item.txt')
const artifactFilesToUpload = [
goodItem1Path,
goodItem2Path,
goodItem3Path,
goodItem4Path,
goodItem5Path,
extraFileInFolderCPath,
amazingFileInFolderHPath
]
describe('Search', () => {
beforeAll(async () => {
noopLogs()
// clear temp directory
await io.rmRF(root)
await fs.mkdir(path.join(root, 'folder-a', 'folder-b', 'folder-c'), {
recursive: true
})
await fs.mkdir(path.join(root, 'folder-a', 'folder-b', 'folder-e'), {
recursive: true
})
await fs.mkdir(path.join(root, 'folder-d'), {
recursive: true
})
await fs.mkdir(path.join(root, 'folder-f'), {
recursive: true
})
await fs.mkdir(path.join(root, 'folder-g'), {
recursive: true
})
await fs.mkdir(path.join(root, 'folder-h', 'folder-i'), {
recursive: true
})
await fs.writeFile(goodItem1Path, 'good item1 file')
await fs.writeFile(goodItem2Path, 'good item2 file')
await fs.writeFile(goodItem3Path, 'good item3 file')
await fs.writeFile(goodItem4Path, 'good item4 file')
await fs.writeFile(goodItem5Path, 'good item5 file')
await fs.writeFile(badItem1Path, 'bad item1 file')
await fs.writeFile(badItem2Path, 'bad item2 file')
await fs.writeFile(badItem3Path, 'bad item3 file')
await fs.writeFile(badItem4Path, 'bad item4 file')
await fs.writeFile(badItem5Path, 'bad item5 file')
await fs.writeFile(extraFileInFolderCPath, 'extra file')
await fs.writeFile(amazingFileInFolderHPath, 'amazing file')
/*
Directory structure of files that get created:
root/
folder-a/
folder-b/
folder-c/
good-item1.txt
bad-item1.txt
extra-file-in-folder-c.txt
folder-e/
folder-d/
good-item2.txt
good-item3.txt
good-item4.txt
bad-item2.txt
folder-f/
bad-item3.txt
folder-g/
folder-h/
amazing-item.txt
folder-i/
bad-item4.txt
bad-item5.txt
good-item5.txt
*/
})
it('Upload Specification - Fail non-existent rootDirectory', async () => {
const invalidRootDirectory = path.join(
__dirname,
'_temp',
'upload-specification-invalid'
)
expect(() => {
validateRootDirectory(invalidRootDirectory)
}).toThrow(
`The provided rootDirectory ${invalidRootDirectory} does not exist`
)
})
it('Upload Specification - Fail invalid rootDirectory', async () => {
expect(() => {
validateRootDirectory(goodItem1Path)
}).toThrow(
`The provided rootDirectory ${goodItem1Path} is not a valid directory`
)
})
it('Upload Specification - File does not exist', async () => {
const fakeFilePath = path.join(
'folder-a',
'folder-b',
'non-existent-file.txt'
)
expect(() => {
getUploadZipSpecification([fakeFilePath], root)
}).toThrow(`File ${fakeFilePath} does not exist`)
})
it('Upload Specification - Non parent directory', async () => {
const folderADirectory = path.join(root, 'folder-a')
const artifactFiles = [
goodItem1Path,
badItem1Path,
extraFileInFolderCPath,
goodItem5Path
]
expect(() => {
getUploadZipSpecification(artifactFiles, folderADirectory)
}).toThrow(
`The rootDirectory: ${folderADirectory} is not a parent directory of the file: ${goodItem5Path}`
)
})
it('Upload Specification - Success', async () => {
const specifications = getUploadZipSpecification(
artifactFilesToUpload,
root
)
expect(specifications.length).toEqual(7)
const absolutePaths = specifications.map(item => item.sourcePath)
expect(absolutePaths).toContain(goodItem1Path)
expect(absolutePaths).toContain(goodItem2Path)
expect(absolutePaths).toContain(goodItem3Path)
expect(absolutePaths).toContain(goodItem4Path)
expect(absolutePaths).toContain(goodItem5Path)
expect(absolutePaths).toContain(extraFileInFolderCPath)
expect(absolutePaths).toContain(amazingFileInFolderHPath)
for (const specification of specifications) {
if (specification.sourcePath === goodItem1Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
)
} else if (specification.sourcePath === goodItem2Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-d', 'good-item2.txt')
)
} else if (specification.sourcePath === goodItem3Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-d', 'good-item3.txt')
)
} else if (specification.sourcePath === goodItem4Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-d', 'good-item4.txt')
)
} else if (specification.sourcePath === goodItem5Path) {
expect(specification.destinationPath).toEqual(
path.join('/good-item5.txt')
)
} else if (specification.sourcePath === extraFileInFolderCPath) {
expect(specification.destinationPath).toEqual(
path.join(
'/folder-a',
'folder-b',
'folder-c',
'extra-file-in-folder-c.txt'
)
)
} else if (specification.sourcePath === amazingFileInFolderHPath) {
expect(specification.destinationPath).toEqual(
path.join('/folder-h', 'amazing-item.txt')
)
} else {
throw new Error(
'Invalid specification found. This should never be reached'
)
}
}
})
it('Upload Specification - Success with extra slash', async () => {
const rootWithSlash = `${root}/`
const specifications = getUploadZipSpecification(
artifactFilesToUpload,
rootWithSlash
)
expect(specifications.length).toEqual(7)
const absolutePaths = specifications.map(item => item.sourcePath)
expect(absolutePaths).toContain(goodItem1Path)
expect(absolutePaths).toContain(goodItem2Path)
expect(absolutePaths).toContain(goodItem3Path)
expect(absolutePaths).toContain(goodItem4Path)
expect(absolutePaths).toContain(goodItem5Path)
expect(absolutePaths).toContain(extraFileInFolderCPath)
expect(absolutePaths).toContain(amazingFileInFolderHPath)
for (const specification of specifications) {
if (specification.sourcePath === goodItem1Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
)
} else if (specification.sourcePath === goodItem2Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-d', 'good-item2.txt')
)
} else if (specification.sourcePath === goodItem3Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-d', 'good-item3.txt')
)
} else if (specification.sourcePath === goodItem4Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-d', 'good-item4.txt')
)
} else if (specification.sourcePath === goodItem5Path) {
expect(specification.destinationPath).toEqual(
path.join('/good-item5.txt')
)
} else if (specification.sourcePath === extraFileInFolderCPath) {
expect(specification.destinationPath).toEqual(
path.join(
'/folder-a',
'folder-b',
'folder-c',
'extra-file-in-folder-c.txt'
)
)
} else if (specification.sourcePath === amazingFileInFolderHPath) {
expect(specification.destinationPath).toEqual(
path.join('/folder-h', 'amazing-item.txt')
)
} else {
throw new Error(
'Invalid specification found. This should never be reached'
)
}
}
})
it('Upload Specification - Empty Directories are included', async () => {
const folderEPath = path.join(root, 'folder-a', 'folder-b', 'folder-e')
const filesWithDirectory = [goodItem1Path, folderEPath]
const specifications = getUploadZipSpecification(filesWithDirectory, root)
expect(specifications.length).toEqual(2)
const absolutePaths = specifications.map(item => item.sourcePath)
expect(absolutePaths).toContain(goodItem1Path)
expect(absolutePaths).toContain(null)
for (const specification of specifications) {
if (specification.sourcePath === goodItem1Path) {
expect(specification.destinationPath).toEqual(
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
)
} else if (specification.sourcePath === null) {
expect(specification.destinationPath).toEqual(
path.join('/folder-a', 'folder-b', 'folder-e')
)
} else {
throw new Error(
'Invalid specification found. This should never be reached'
)
}
}
})
})
+61
View File
@@ -0,0 +1,61 @@
import * as config from '../src/internal/shared/config'
import * as util from '../src/internal/shared/util'
export const testRuntimeToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwic2NwIjoiQWN0aW9ucy5FeGFtcGxlIEFjdGlvbnMuQW5vdGhlckV4YW1wbGU6dGVzdCBBY3Rpb25zLlJlc3VsdHM6Y2U3ZjU0YzctNjFjNy00YWFlLTg4N2YtMzBkYTQ3NWY1ZjFhOmNhMzk1MDg1LTA0MGEtNTI2Yi0yY2U4LWJkYzg1ZjY5Mjc3NCIsImlhdCI6MTUxNjIzOTAyMn0.XYnI_wHPBlUi1mqYveJnnkJhp4dlFjqxzRmISPsqfw8'
describe('get-backend-ids-from-token', () => {
it('should return backend ids when the token is valid', () => {
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(testRuntimeToken)
const backendIds = util.getBackendIdsFromToken()
expect(backendIds.workflowRunBackendId).toBe(
'ce7f54c7-61c7-4aae-887f-30da475f5f1a'
)
expect(backendIds.workflowJobRunBackendId).toBe(
'ca395085-040a-526b-2ce8-bdc85f692774'
)
})
it("should throw an error when the token doesn't have the right scope", () => {
jest
.spyOn(config, 'getRuntimeToken')
.mockReturnValue(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwic2NwIjoiQWN0aW9ucy5FeGFtcGxlIEFjdGlvbnMuQW5vdGhlckV4YW1wbGU6dGVzdCIsImlhdCI6MTUxNjIzOTAyMn0.K0IEoULZteGevF38G94xiaA8zcZ5UlKWfGfqE6q3dhw'
)
expect(util.getBackendIdsFromToken).toThrowError(
'Failed to get backend IDs: The provided JWT token is invalid'
)
})
it('should throw an error when the token has a malformed scope', () => {
jest
.spyOn(config, 'getRuntimeToken')
.mockReturnValue(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwic2NwIjoiQWN0aW9ucy5FeGFtcGxlIEFjdGlvbnMuQW5vdGhlckV4YW1wbGU6dGVzdCBBY3Rpb25zLlJlc3VsdHM6Y2U3ZjU0YzctNjFjNy00YWFlLTg4N2YtMzBkYTQ3NWY1ZjFhIiwiaWF0IjoxNTE2MjM5MDIyfQ.7D0_LRfRFRZFImHQ7GxH2S6ZyFjjZ5U0ujjGCfle1XE'
)
expect(util.getBackendIdsFromToken).toThrowError(
'Failed to get backend IDs: The provided JWT token is invalid'
)
})
it('should throw an error when the token is in an invalid format', () => {
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('token')
expect(util.getBackendIdsFromToken).toThrowError('Invalid token specified')
})
it("should throw an error when the token doesn't have the right field", () => {
jest
.spyOn(config, 'getRuntimeToken')
.mockReturnValue(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
)
expect(util.getBackendIdsFromToken).toThrowError(
'Failed to get backend IDs: The provided JWT token is invalid'
)
})
})
+35
View File
@@ -0,0 +1,35 @@
# Frequently Asked Questions
- [Frequently Asked Questions](#frequently-asked-questions)
- [Supported Characters](#supported-characters)
- [Compression? ZIP? How is my artifact stored?](#compression-zip-how-is-my-artifact-stored)
## Supported Characters
When uploading an artifact, the inputted `name` parameter along with the files specified in `files` cannot contain any of the following characters. If they are present in `name` or `files`, the Artifact will be rejected by the server and the upload will fail. These characters are not allowed due to limitations and restrictions with certain file systems such as NTFS. To maintain platform-agnostic behavior, characters that are not supported by an individual filesystem/platform will not be supported on all filesystems/platforms.
- "
- :
- <
- \>
- |
- \*
- ?
In addition to the aforementioned characters, the inputted `name` also cannot include the following
- \
- /
## Compression? ZIP? How is my artifact stored?
When creating an Artifact, the files are dynamically compressed and streamed into a ZIP archive. Since they are stored in a ZIP, they can be compressed by Zlib in varying levels.
The value can range from 0 to 9:
- 0: No compression
- 1: Best speed
- 6: Default compression (same as GNU Gzip)
- 9: Best compression
Higher levels will result in better compression, but will take longer to complete.
For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
@@ -0,0 +1,40 @@
@actions/artifact
# @actions/artifact
## Table of contents
### Classes
- [ArtifactNotFoundError](classes/ArtifactNotFoundError.md)
- [DefaultArtifactClient](classes/DefaultArtifactClient.md)
- [FilesNotFoundError](classes/FilesNotFoundError.md)
- [GHESNotSupportedError](classes/GHESNotSupportedError.md)
- [InvalidResponseError](classes/InvalidResponseError.md)
### Interfaces
- [Artifact](interfaces/Artifact.md)
- [ArtifactClient](interfaces/ArtifactClient.md)
- [DownloadArtifactOptions](interfaces/DownloadArtifactOptions.md)
- [DownloadArtifactResponse](interfaces/DownloadArtifactResponse.md)
- [FindOptions](interfaces/FindOptions.md)
- [GetArtifactResponse](interfaces/GetArtifactResponse.md)
- [ListArtifactsOptions](interfaces/ListArtifactsOptions.md)
- [ListArtifactsResponse](interfaces/ListArtifactsResponse.md)
- [UploadArtifactOptions](interfaces/UploadArtifactOptions.md)
- [UploadArtifactResponse](interfaces/UploadArtifactResponse.md)
### Variables
- [default](README.md#default)
## Variables
### default
`Const` **default**: [`ArtifactClient`](interfaces/ArtifactClient.md)
#### Defined in
[src/artifact.ts:7](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/artifact.ts#L7)
@@ -0,0 +1,169 @@
[@actions/artifact](../README.md) / ArtifactNotFoundError
# Class: ArtifactNotFoundError
## Hierarchy
- `Error`
**`ArtifactNotFoundError`**
## Table of contents
### Constructors
- [constructor](ArtifactNotFoundError.md#constructor)
### Properties
- [message](ArtifactNotFoundError.md#message)
- [name](ArtifactNotFoundError.md#name)
- [stack](ArtifactNotFoundError.md#stack)
- [prepareStackTrace](ArtifactNotFoundError.md#preparestacktrace)
- [stackTraceLimit](ArtifactNotFoundError.md#stacktracelimit)
### Methods
- [captureStackTrace](ArtifactNotFoundError.md#capturestacktrace)
## Constructors
### constructor
**new ArtifactNotFoundError**(`message?`): [`ArtifactNotFoundError`](ArtifactNotFoundError.md)
#### Parameters
| Name | Type | Default value |
| :------ | :------ | :------ |
| `message` | `string` | `'Artifact not found'` |
#### Returns
[`ArtifactNotFoundError`](ArtifactNotFoundError.md)
#### Overrides
Error.constructor
#### Defined in
[src/internal/shared/errors.ts:24](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/errors.ts#L24)
## Properties
### message
**message**: `string`
#### Inherited from
Error.message
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1068
___
### name
**name**: `string`
#### Inherited from
Error.name
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1067
___
### stack
`Optional` **stack**: `string`
#### Inherited from
Error.stack
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1069
___
### prepareStackTrace
`Static` `Optional` **prepareStackTrace**: (`err`: `Error`, `stackTraces`: `CallSite`[]) => `any`
#### Type declaration
▸ (`err`, `stackTraces`): `any`
Optional override for formatting stack traces
##### Parameters
| Name | Type |
| :------ | :------ |
| `err` | `Error` |
| `stackTraces` | `CallSite`[] |
##### Returns
`any`
**`See`**
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
#### Inherited from
Error.prepareStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:11
___
### stackTraceLimit
`Static` **stackTraceLimit**: `number`
#### Inherited from
Error.stackTraceLimit
#### Defined in
node_modules/@types/node/globals.d.ts:13
## Methods
### captureStackTrace
**captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
Create .stack property on a target object
#### Parameters
| Name | Type |
| :------ | :------ |
| `targetObject` | `object` |
| `constructorOpt?` | `Function` |
#### Returns
`void`
#### Inherited from
Error.captureStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:4
@@ -0,0 +1,161 @@
[@actions/artifact](../README.md) / DefaultArtifactClient
# Class: DefaultArtifactClient
The default artifact client that is used by the artifact action(s).
## Implements
- [`ArtifactClient`](../interfaces/ArtifactClient.md)
## Table of contents
### Constructors
- [constructor](DefaultArtifactClient.md#constructor)
### Methods
- [downloadArtifact](DefaultArtifactClient.md#downloadartifact)
- [getArtifact](DefaultArtifactClient.md#getartifact)
- [listArtifacts](DefaultArtifactClient.md#listartifacts)
- [uploadArtifact](DefaultArtifactClient.md#uploadartifact)
## Constructors
### constructor
**new DefaultArtifactClient**(): [`DefaultArtifactClient`](DefaultArtifactClient.md)
#### Returns
[`DefaultArtifactClient`](DefaultArtifactClient.md)
## Methods
### downloadArtifact
**downloadArtifact**(`artifactId`, `options?`): `Promise`\<[`DownloadArtifactResponse`](../interfaces/DownloadArtifactResponse.md)\>
Downloads an artifact and unzips the content.
If `options.findBy` is specified, this will use the public Download Artifact API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `artifactId` | `number` | The name of the artifact to download |
| `options?` | [`DownloadArtifactOptions`](../interfaces/DownloadArtifactOptions.md) & [`FindOptions`](../interfaces/FindOptions.md) | Extra options that allow for the customization of the download behavior |
#### Returns
`Promise`\<[`DownloadArtifactResponse`](../interfaces/DownloadArtifactResponse.md)\>
single DownloadArtifactResponse object
#### Implementation of
[ArtifactClient](../interfaces/ArtifactClient.md).[downloadArtifact](../interfaces/ArtifactClient.md#downloadartifact)
#### Defined in
[src/internal/client.ts:119](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L119)
___
### getArtifact
**getArtifact**(`artifactName`, `options?`): `Promise`\<[`GetArtifactResponse`](../interfaces/GetArtifactResponse.md)\>
Finds an artifact by name.
If there are multiple artifacts with the same name in the same workflow run, this will return the latest.
If the artifact is not found, it will throw.
If `options.findBy` is specified, this will use the public List Artifacts API with a name filter which can get artifacts from other runs.
https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
`@actions/artifact` v2+ does not allow for creating multiple artifacts with the same name in the same workflow run.
It is possible to have multiple artifacts with the same name in the same workflow run by using old versions of upload-artifact (v1,v2 and v3), @actions/artifact < v2 or it is a rerun.
If there are multiple artifacts with the same name in the same workflow run this function will return the first artifact that matches the name.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `artifactName` | `string` | The name of the artifact to find |
| `options?` | [`FindOptions`](../interfaces/FindOptions.md) | Extra options that allow for the customization of the get behavior |
#### Returns
`Promise`\<[`GetArtifactResponse`](../interfaces/GetArtifactResponse.md)\>
#### Implementation of
[ArtifactClient](../interfaces/ArtifactClient.md).[getArtifact](../interfaces/ArtifactClient.md#getartifact)
#### Defined in
[src/internal/client.ts:193](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L193)
___
### listArtifacts
**listArtifacts**(`options?`): `Promise`\<[`ListArtifactsResponse`](../interfaces/ListArtifactsResponse.md)\>
Lists all artifacts that are part of the current workflow run.
This function will return at most 1000 artifacts per workflow run.
If `options.findBy` is specified, this will call the public List-Artifacts API which can list from other runs.
https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `options?` | [`ListArtifactsOptions`](../interfaces/ListArtifactsOptions.md) & [`FindOptions`](../interfaces/FindOptions.md) | Extra options that allow for the customization of the list behavior |
#### Returns
`Promise`\<[`ListArtifactsResponse`](../interfaces/ListArtifactsResponse.md)\>
ListArtifactResponse object
#### Implementation of
[ArtifactClient](../interfaces/ArtifactClient.md).[listArtifacts](../interfaces/ArtifactClient.md#listartifacts)
#### Defined in
[src/internal/client.ts:157](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L157)
___
### uploadArtifact
**uploadArtifact**(`name`, `files`, `rootDirectory`, `options?`): `Promise`\<[`UploadArtifactResponse`](../interfaces/UploadArtifactResponse.md)\>
Uploads an artifact.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the artifact, required |
| `files` | `string`[] | A list of absolute or relative paths that denote what files should be uploaded |
| `rootDirectory` | `string` | An absolute or relative file path that denotes the root parent directory of the files being uploaded |
| `options?` | [`UploadArtifactOptions`](../interfaces/UploadArtifactOptions.md) | Extra options for customizing the upload behavior |
#### Returns
`Promise`\<[`UploadArtifactResponse`](../interfaces/UploadArtifactResponse.md)\>
single UploadArtifactResponse object
#### Implementation of
[ArtifactClient](../interfaces/ArtifactClient.md).[uploadArtifact](../interfaces/ArtifactClient.md#uploadartifact)
#### Defined in
[src/internal/client.ts:94](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L94)
@@ -0,0 +1,180 @@
[@actions/artifact](../README.md) / FilesNotFoundError
# Class: FilesNotFoundError
## Hierarchy
- `Error`
**`FilesNotFoundError`**
## Table of contents
### Constructors
- [constructor](FilesNotFoundError.md#constructor)
### Properties
- [files](FilesNotFoundError.md#files)
- [message](FilesNotFoundError.md#message)
- [name](FilesNotFoundError.md#name)
- [stack](FilesNotFoundError.md#stack)
- [prepareStackTrace](FilesNotFoundError.md#preparestacktrace)
- [stackTraceLimit](FilesNotFoundError.md#stacktracelimit)
### Methods
- [captureStackTrace](FilesNotFoundError.md#capturestacktrace)
## Constructors
### constructor
**new FilesNotFoundError**(`files?`): [`FilesNotFoundError`](FilesNotFoundError.md)
#### Parameters
| Name | Type | Default value |
| :------ | :------ | :------ |
| `files` | `string`[] | `[]` |
#### Returns
[`FilesNotFoundError`](FilesNotFoundError.md)
#### Overrides
Error.constructor
#### Defined in
[src/internal/shared/errors.ts:4](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/errors.ts#L4)
## Properties
### files
**files**: `string`[]
#### Defined in
[src/internal/shared/errors.ts:2](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/errors.ts#L2)
___
### message
**message**: `string`
#### Inherited from
Error.message
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1068
___
### name
**name**: `string`
#### Inherited from
Error.name
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1067
___
### stack
`Optional` **stack**: `string`
#### Inherited from
Error.stack
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1069
___
### prepareStackTrace
`Static` `Optional` **prepareStackTrace**: (`err`: `Error`, `stackTraces`: `CallSite`[]) => `any`
#### Type declaration
▸ (`err`, `stackTraces`): `any`
Optional override for formatting stack traces
##### Parameters
| Name | Type |
| :------ | :------ |
| `err` | `Error` |
| `stackTraces` | `CallSite`[] |
##### Returns
`any`
**`See`**
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
#### Inherited from
Error.prepareStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:11
___
### stackTraceLimit
`Static` **stackTraceLimit**: `number`
#### Inherited from
Error.stackTraceLimit
#### Defined in
node_modules/@types/node/globals.d.ts:13
## Methods
### captureStackTrace
**captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
Create .stack property on a target object
#### Parameters
| Name | Type |
| :------ | :------ |
| `targetObject` | `object` |
| `constructorOpt?` | `Function` |
#### Returns
`void`
#### Inherited from
Error.captureStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:4
@@ -0,0 +1,169 @@
[@actions/artifact](../README.md) / GHESNotSupportedError
# Class: GHESNotSupportedError
## Hierarchy
- `Error`
**`GHESNotSupportedError`**
## Table of contents
### Constructors
- [constructor](GHESNotSupportedError.md#constructor)
### Properties
- [message](GHESNotSupportedError.md#message)
- [name](GHESNotSupportedError.md#name)
- [stack](GHESNotSupportedError.md#stack)
- [prepareStackTrace](GHESNotSupportedError.md#preparestacktrace)
- [stackTraceLimit](GHESNotSupportedError.md#stacktracelimit)
### Methods
- [captureStackTrace](GHESNotSupportedError.md#capturestacktrace)
## Constructors
### constructor
**new GHESNotSupportedError**(`message?`): [`GHESNotSupportedError`](GHESNotSupportedError.md)
#### Parameters
| Name | Type | Default value |
| :------ | :------ | :------ |
| `message` | `string` | `'@actions/artifact v2.0.0+, upload-artifact@v4+ and download-artifact@v4+ are not currently supported on GHES.'` |
#### Returns
[`GHESNotSupportedError`](GHESNotSupportedError.md)
#### Overrides
Error.constructor
#### Defined in
[src/internal/shared/errors.ts:31](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/errors.ts#L31)
## Properties
### message
**message**: `string`
#### Inherited from
Error.message
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1068
___
### name
**name**: `string`
#### Inherited from
Error.name
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1067
___
### stack
`Optional` **stack**: `string`
#### Inherited from
Error.stack
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1069
___
### prepareStackTrace
`Static` `Optional` **prepareStackTrace**: (`err`: `Error`, `stackTraces`: `CallSite`[]) => `any`
#### Type declaration
▸ (`err`, `stackTraces`): `any`
Optional override for formatting stack traces
##### Parameters
| Name | Type |
| :------ | :------ |
| `err` | `Error` |
| `stackTraces` | `CallSite`[] |
##### Returns
`any`
**`See`**
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
#### Inherited from
Error.prepareStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:11
___
### stackTraceLimit
`Static` **stackTraceLimit**: `number`
#### Inherited from
Error.stackTraceLimit
#### Defined in
node_modules/@types/node/globals.d.ts:13
## Methods
### captureStackTrace
**captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
Create .stack property on a target object
#### Parameters
| Name | Type |
| :------ | :------ |
| `targetObject` | `object` |
| `constructorOpt?` | `Function` |
#### Returns
`void`
#### Inherited from
Error.captureStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:4
@@ -0,0 +1,169 @@
[@actions/artifact](../README.md) / InvalidResponseError
# Class: InvalidResponseError
## Hierarchy
- `Error`
**`InvalidResponseError`**
## Table of contents
### Constructors
- [constructor](InvalidResponseError.md#constructor)
### Properties
- [message](InvalidResponseError.md#message)
- [name](InvalidResponseError.md#name)
- [stack](InvalidResponseError.md#stack)
- [prepareStackTrace](InvalidResponseError.md#preparestacktrace)
- [stackTraceLimit](InvalidResponseError.md#stacktracelimit)
### Methods
- [captureStackTrace](InvalidResponseError.md#capturestacktrace)
## Constructors
### constructor
**new InvalidResponseError**(`message`): [`InvalidResponseError`](InvalidResponseError.md)
#### Parameters
| Name | Type |
| :------ | :------ |
| `message` | `string` |
#### Returns
[`InvalidResponseError`](InvalidResponseError.md)
#### Overrides
Error.constructor
#### Defined in
[src/internal/shared/errors.ts:17](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/errors.ts#L17)
## Properties
### message
**message**: `string`
#### Inherited from
Error.message
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1068
___
### name
**name**: `string`
#### Inherited from
Error.name
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1067
___
### stack
`Optional` **stack**: `string`
#### Inherited from
Error.stack
#### Defined in
node_modules/typescript/lib/lib.es5.d.ts:1069
___
### prepareStackTrace
`Static` `Optional` **prepareStackTrace**: (`err`: `Error`, `stackTraces`: `CallSite`[]) => `any`
#### Type declaration
▸ (`err`, `stackTraces`): `any`
Optional override for formatting stack traces
##### Parameters
| Name | Type |
| :------ | :------ |
| `err` | `Error` |
| `stackTraces` | `CallSite`[] |
##### Returns
`any`
**`See`**
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
#### Inherited from
Error.prepareStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:11
___
### stackTraceLimit
`Static` **stackTraceLimit**: `number`
#### Inherited from
Error.stackTraceLimit
#### Defined in
node_modules/@types/node/globals.d.ts:13
## Methods
### captureStackTrace
**captureStackTrace**(`targetObject`, `constructorOpt?`): `void`
Create .stack property on a target object
#### Parameters
| Name | Type |
| :------ | :------ |
| `targetObject` | `object` |
| `constructorOpt?` | `Function` |
#### Returns
`void`
#### Inherited from
Error.captureStackTrace
#### Defined in
node_modules/@types/node/globals.d.ts:4
@@ -0,0 +1,62 @@
[@actions/artifact](../README.md) / Artifact
# Interface: Artifact
An Actions Artifact
## Table of contents
### Properties
- [createdAt](Artifact.md#createdat)
- [id](Artifact.md#id)
- [name](Artifact.md#name)
- [size](Artifact.md#size)
## Properties
### createdAt
`Optional` **createdAt**: `Date`
The time when the artifact was created
#### Defined in
[src/internal/shared/interfaces.ts:123](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L123)
___
### id
**id**: `number`
The ID of the artifact
#### Defined in
[src/internal/shared/interfaces.ts:113](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L113)
___
### name
**name**: `string`
The name of the artifact
#### Defined in
[src/internal/shared/interfaces.ts:108](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L108)
___
### size
**size**: `number`
The size of the artifact in bytes
#### Defined in
[src/internal/shared/interfaces.ts:118](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L118)
@@ -0,0 +1,131 @@
[@actions/artifact](../README.md) / ArtifactClient
# Interface: ArtifactClient
Generic interface for the artifact client.
## Implemented by
- [`DefaultArtifactClient`](../classes/DefaultArtifactClient.md)
## Table of contents
### Methods
- [downloadArtifact](ArtifactClient.md#downloadartifact)
- [getArtifact](ArtifactClient.md#getartifact)
- [listArtifacts](ArtifactClient.md#listartifacts)
- [uploadArtifact](ArtifactClient.md#uploadartifact)
## Methods
### downloadArtifact
**downloadArtifact**(`artifactId`, `options?`): `Promise`\<[`DownloadArtifactResponse`](DownloadArtifactResponse.md)\>
Downloads an artifact and unzips the content.
If `options.findBy` is specified, this will use the public Download Artifact API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `artifactId` | `number` | The name of the artifact to download |
| `options?` | [`DownloadArtifactOptions`](DownloadArtifactOptions.md) & [`FindOptions`](FindOptions.md) | Extra options that allow for the customization of the download behavior |
#### Returns
`Promise`\<[`DownloadArtifactResponse`](DownloadArtifactResponse.md)\>
single DownloadArtifactResponse object
#### Defined in
[src/internal/client.ts:84](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L84)
___
### getArtifact
**getArtifact**(`artifactName`, `options?`): `Promise`\<[`GetArtifactResponse`](GetArtifactResponse.md)\>
Finds an artifact by name.
If there are multiple artifacts with the same name in the same workflow run, this will return the latest.
If the artifact is not found, it will throw.
If `options.findBy` is specified, this will use the public List Artifacts API with a name filter which can get artifacts from other runs.
https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
`@actions/artifact` v2+ does not allow for creating multiple artifacts with the same name in the same workflow run.
It is possible to have multiple artifacts with the same name in the same workflow run by using old versions of upload-artifact (v1,v2 and v3), @actions/artifact < v2 or it is a rerun.
If there are multiple artifacts with the same name in the same workflow run this function will return the first artifact that matches the name.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `artifactName` | `string` | The name of the artifact to find |
| `options?` | [`FindOptions`](FindOptions.md) | Extra options that allow for the customization of the get behavior |
#### Returns
`Promise`\<[`GetArtifactResponse`](GetArtifactResponse.md)\>
#### Defined in
[src/internal/client.ts:70](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L70)
___
### listArtifacts
**listArtifacts**(`options?`): `Promise`\<[`ListArtifactsResponse`](ListArtifactsResponse.md)\>
Lists all artifacts that are part of the current workflow run.
This function will return at most 1000 artifacts per workflow run.
If `options.findBy` is specified, this will call the public List-Artifacts API which can list from other runs.
https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `options?` | [`ListArtifactsOptions`](ListArtifactsOptions.md) & [`FindOptions`](FindOptions.md) | Extra options that allow for the customization of the list behavior |
#### Returns
`Promise`\<[`ListArtifactsResponse`](ListArtifactsResponse.md)\>
ListArtifactResponse object
#### Defined in
[src/internal/client.ts:52](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L52)
___
### uploadArtifact
**uploadArtifact**(`name`, `files`, `rootDirectory`, `options?`): `Promise`\<[`UploadArtifactResponse`](UploadArtifactResponse.md)\>
Uploads an artifact.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the artifact, required |
| `files` | `string`[] | A list of absolute or relative paths that denote what files should be uploaded |
| `rootDirectory` | `string` | An absolute or relative file path that denotes the root parent directory of the files being uploaded |
| `options?` | [`UploadArtifactOptions`](UploadArtifactOptions.md) | Extra options for customizing the upload behavior |
#### Returns
`Promise`\<[`UploadArtifactResponse`](UploadArtifactResponse.md)\>
single UploadArtifactResponse object
#### Defined in
[src/internal/client.ts:35](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/client.ts#L35)
@@ -0,0 +1,23 @@
[@actions/artifact](../README.md) / DownloadArtifactOptions
# Interface: DownloadArtifactOptions
Options for downloading an artifact
## Table of contents
### Properties
- [path](DownloadArtifactOptions.md#path)
## Properties
### path
`Optional` **path**: `string`
Denotes where the artifact will be downloaded to. If not specified then the artifact is download to GITHUB_WORKSPACE
#### Defined in
[src/internal/shared/interfaces.ts:98](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L98)
@@ -0,0 +1,23 @@
[@actions/artifact](../README.md) / DownloadArtifactResponse
# Interface: DownloadArtifactResponse
Response from the server when downloading an artifact
## Table of contents
### Properties
- [downloadPath](DownloadArtifactResponse.md#downloadpath)
## Properties
### downloadPath
`Optional` **downloadPath**: `string`
The path where the artifact was downloaded to
#### Defined in
[src/internal/shared/interfaces.ts:88](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L88)
@@ -0,0 +1,30 @@
[@actions/artifact](../README.md) / FindOptions
# Interface: FindOptions
## Table of contents
### Properties
- [findBy](FindOptions.md#findby)
## Properties
### findBy
`Optional` **findBy**: `Object`
The criteria for finding Artifact(s) out of the scope of the current run.
#### Type declaration
| Name | Type | Description |
| :------ | :------ | :------ |
| `repositoryName` | `string` | Repository owner (eg. 'toolkit') |
| `repositoryOwner` | `string` | Repository owner (eg. 'actions') |
| `token` | `string` | Token with actions:read permissions |
| `workflowRunId` | `number` | WorkflowRun of the artifact(s) to lookup |
#### Defined in
[src/internal/shared/interfaces.ts:131](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L131)
@@ -0,0 +1,23 @@
[@actions/artifact](../README.md) / GetArtifactResponse
# Interface: GetArtifactResponse
Response from the server when getting an artifact
## Table of contents
### Properties
- [artifact](GetArtifactResponse.md#artifact)
## Properties
### artifact
**artifact**: [`Artifact`](Artifact.md)
Metadata about the artifact that was found
#### Defined in
[src/internal/shared/interfaces.ts:57](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L57)
@@ -0,0 +1,24 @@
[@actions/artifact](../README.md) / ListArtifactsOptions
# Interface: ListArtifactsOptions
Options for listing artifacts
## Table of contents
### Properties
- [latest](ListArtifactsOptions.md#latest)
## Properties
### latest
`Optional` **latest**: `boolean`
Filter the workflow run's artifacts to the latest by name
In the case of reruns, this can be useful to avoid duplicates
#### Defined in
[src/internal/shared/interfaces.ts:68](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L68)
@@ -0,0 +1,23 @@
[@actions/artifact](../README.md) / ListArtifactsResponse
# Interface: ListArtifactsResponse
Response from the server when listing artifacts
## Table of contents
### Properties
- [artifacts](ListArtifactsResponse.md#artifacts)
## Properties
### artifacts
**artifacts**: [`Artifact`](Artifact.md)[]
A list of artifacts that were found
#### Defined in
[src/internal/shared/interfaces.ts:78](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L78)
@@ -0,0 +1,55 @@
[@actions/artifact](../README.md) / UploadArtifactOptions
# Interface: UploadArtifactOptions
Options for uploading an artifact
## Table of contents
### Properties
- [compressionLevel](UploadArtifactOptions.md#compressionlevel)
- [retentionDays](UploadArtifactOptions.md#retentiondays)
## Properties
### compressionLevel
`Optional` **compressionLevel**: `number`
The level of compression for Zlib to be applied to the artifact archive.
The value can range from 0 to 9:
- 0: No compression
- 1: Best speed
- 6: Default compression (same as GNU Gzip)
- 9: Best compression
Higher levels will result in better compression, but will take longer to complete.
For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
#### Defined in
[src/internal/shared/interfaces.ts:47](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L47)
___
### retentionDays
`Optional` **retentionDays**: `number`
Duration after which artifact will expire in days.
By default artifact expires after 90 days:
https://docs.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts#downloading-and-deleting-artifacts-after-a-workflow-run-is-complete
Use this option to override the default expiry.
Min value: 1
Max value: 90 unless changed by repository setting
If this is set to a greater value than the retention settings allowed, the retention on artifacts
will be reduced to match the max value allowed on server, and the upload process will continue. An
input of 0 assumes default retention setting.
#### Defined in
[src/internal/shared/interfaces.ts:36](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L36)
@@ -0,0 +1,37 @@
[@actions/artifact](../README.md) / UploadArtifactResponse
# Interface: UploadArtifactResponse
Response from the server when an artifact is uploaded
## Table of contents
### Properties
- [id](UploadArtifactResponse.md#id)
- [size](UploadArtifactResponse.md#size)
## Properties
### id
`Optional` **id**: `number`
The id of the artifact that was created. Not provided if no artifact was uploaded
This ID can be used as input to other APIs to download, delete or get more information about an artifact: https://docs.github.com/en/rest/actions/artifacts
#### Defined in
[src/internal/shared/interfaces.ts:14](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L14)
___
### size
`Optional` **size**: `number`
Total size of the artifact in bytes. Not provided if no artifact was uploaded
#### Defined in
[src/internal/shared/interfaces.ts:8](https://github.com/actions/toolkit/blob/e3764a5/packages/artifact/src/internal/shared/interfaces.ts#L8)
+1527
View File
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
{
"name": "@actions/artifact",
"version": "2.0.0",
"preview": true,
"description": "Actions artifact lib",
"keywords": [
"github",
"actions",
"artifact"
],
"homepage": "https://github.com/actions/toolkit/tree/main/packages/artifact",
"license": "MIT",
"main": "lib/artifact.js",
"types": "lib/artifact.d.ts",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib",
"!.DS_Store"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/toolkit.git",
"directory": "packages/artifact"
},
"scripts": {
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
"test": "cd ../../ && npm run test ./packages/artifact",
"bootstrap": "cd ../../ && npm run bootstrap",
"tsc-run": "tsc",
"tsc": "npm run bootstrap && npm run tsc-run",
"gen:docs": "typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"
},
"bugs": {
"url": "https://github.com/actions/toolkit/issues"
},
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
"@actions/http-client": "^2.1.0",
"@azure/storage-blob": "^12.15.0",
"@octokit/core": "^3.5.1",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-retry": "^3.0.9",
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^5.3.1",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
},
"devDependencies": {
"@types/archiver": "^5.3.2",
"@types/unzip-stream": "^0.3.4",
"typedoc": "^0.25.4",
"typedoc-plugin-markdown": "^3.17.1",
"typescript": "^5.2.2"
}
}
+8
View File
@@ -0,0 +1,8 @@
import {ArtifactClient, DefaultArtifactClient} from './internal/client'
export * from './internal/shared/interfaces'
export * from './internal/shared/errors'
export * from './internal/client'
const client: ArtifactClient = new DefaultArtifactClient()
export default client
@@ -0,0 +1,277 @@
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
// @generated from protobuf file "google/protobuf/timestamp.proto" (package "google.protobuf", syntax proto3)
// tslint:disable
//
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
import type { IBinaryWriter } from "@protobuf-ts/runtime";
import { WireType } from "@protobuf-ts/runtime";
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
import type { IBinaryReader } from "@protobuf-ts/runtime";
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
import type { PartialMessage } from "@protobuf-ts/runtime";
import { reflectionMergePartial } from "@protobuf-ts/runtime";
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
import { typeofJsonValue } from "@protobuf-ts/runtime";
import type { JsonValue } from "@protobuf-ts/runtime";
import type { JsonReadOptions } from "@protobuf-ts/runtime";
import type { JsonWriteOptions } from "@protobuf-ts/runtime";
import { PbLong } from "@protobuf-ts/runtime";
import { MessageType } from "@protobuf-ts/runtime";
/**
* A Timestamp represents a point in time independent of any time zone
* or calendar, represented as seconds and fractions of seconds at
* nanosecond resolution in UTC Epoch time. It is encoded using the
* Proleptic Gregorian Calendar which extends the Gregorian calendar
* backwards to year one. It is encoded assuming all minutes are 60
* seconds long, i.e. leap seconds are "smeared" so that no leap second
* table is needed for interpretation. Range is from
* 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
* By restricting to that range, we ensure that we can convert to
* and from RFC 3339 date strings.
* See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
*
* # Examples
*
* Example 1: Compute Timestamp from POSIX `time()`.
*
* Timestamp timestamp;
* timestamp.set_seconds(time(NULL));
* timestamp.set_nanos(0);
*
* Example 2: Compute Timestamp from POSIX `gettimeofday()`.
*
* struct timeval tv;
* gettimeofday(&tv, NULL);
*
* Timestamp timestamp;
* timestamp.set_seconds(tv.tv_sec);
* timestamp.set_nanos(tv.tv_usec * 1000);
*
* Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
*
* FILETIME ft;
* GetSystemTimeAsFileTime(&ft);
* UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
*
* // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
* // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
* Timestamp timestamp;
* timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
* timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
*
* Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
*
* long millis = System.currentTimeMillis();
*
* Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
* .setNanos((int) ((millis % 1000) * 1000000)).build();
*
*
* Example 5: Compute Timestamp from current time in Python.
*
* timestamp = Timestamp()
* timestamp.GetCurrentTime()
*
* # JSON Mapping
*
* In JSON format, the Timestamp type is encoded as a string in the
* [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
* format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
* where {year} is always expressed using four digits while {month}, {day},
* {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
* seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
* are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
* is required. A proto3 JSON serializer should always use UTC (as indicated by
* "Z") when printing the Timestamp type and a proto3 JSON parser should be
* able to accept both UTC and other timezones (as indicated by an offset).
*
* For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
* 01:30 UTC on January 15, 2017.
*
* In JavaScript, one can convert a Date object to this format using the
* standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
* method. In Python, a standard `datetime.datetime` object can be converted
* to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
* with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
* can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
* http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--
* ) to obtain a formatter capable of generating timestamps in this format.
*
*
*
* @generated from protobuf message google.protobuf.Timestamp
*/
export interface Timestamp {
/**
* Represents seconds of UTC time since Unix epoch
* 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
* 9999-12-31T23:59:59Z inclusive.
*
* @generated from protobuf field: int64 seconds = 1;
*/
seconds: string;
/**
* Non-negative fractions of a second at nanosecond resolution. Negative
* second values with fractions must still have non-negative nanos values
* that count forward in time. Must be from 0 to 999,999,999
* inclusive.
*
* @generated from protobuf field: int32 nanos = 2;
*/
nanos: number;
}
// @generated message type with reflection information, may provide speed optimized methods
class Timestamp$Type extends MessageType<Timestamp> {
constructor() {
super("google.protobuf.Timestamp", [
{ no: 1, name: "seconds", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
{ no: 2, name: "nanos", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
]);
}
/**
* Creates a new `Timestamp` for the current time.
*/
now(): Timestamp {
const msg = this.create();
const ms = Date.now();
msg.seconds = PbLong.from(Math.floor(ms / 1000)).toString();
msg.nanos = (ms % 1000) * 1000000;
return msg;
}
/**
* Converts a `Timestamp` to a JavaScript Date.
*/
toDate(message: Timestamp): Date {
return new Date(PbLong.from(message.seconds).toNumber() * 1000 + Math.ceil(message.nanos / 1000000));
}
/**
* Converts a JavaScript Date to a `Timestamp`.
*/
fromDate(date: Date): Timestamp {
const msg = this.create();
const ms = date.getTime();
msg.seconds = PbLong.from(Math.floor(ms / 1000)).toString();
msg.nanos = (ms % 1000) * 1000000;
return msg;
}
/**
* In JSON format, the `Timestamp` type is encoded as a string
* in the RFC 3339 format.
*/
internalJsonWrite(message: Timestamp, options: JsonWriteOptions): JsonValue {
let ms = PbLong.from(message.seconds).toNumber() * 1000;
if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z"))
throw new Error("Unable to encode Timestamp to JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
if (message.nanos < 0)
throw new Error("Unable to encode invalid Timestamp to JSON. Nanos must not be negative.");
let z = "Z";
if (message.nanos > 0) {
let nanosStr = (message.nanos + 1000000000).toString().substring(1);
if (nanosStr.substring(3) === "000000")
z = "." + nanosStr.substring(0, 3) + "Z";
else if (nanosStr.substring(6) === "000")
z = "." + nanosStr.substring(0, 6) + "Z";
else
z = "." + nanosStr + "Z";
}
return new Date(ms).toISOString().replace(".000Z", z);
}
/**
* In JSON format, the `Timestamp` type is encoded as a string
* in the RFC 3339 format.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Timestamp): Timestamp {
if (typeof json !== "string")
throw new Error("Unable to parse Timestamp from JSON " + typeofJsonValue(json) + ".");
let matches = json.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:Z|\.([0-9]{3,9})Z|([+-][0-9][0-9]:[0-9][0-9]))$/);
if (!matches)
throw new Error("Unable to parse Timestamp from JSON. Invalid format.");
let ms = Date.parse(matches[1] + "-" + matches[2] + "-" + matches[3] + "T" + matches[4] + ":" + matches[5] + ":" + matches[6] + (matches[8] ? matches[8] : "Z"));
if (Number.isNaN(ms))
throw new Error("Unable to parse Timestamp from JSON. Invalid value.");
if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z"))
throw new globalThis.Error("Unable to parse Timestamp from JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
if (!target)
target = this.create();
target.seconds = PbLong.from(ms / 1000).toString();
target.nanos = 0;
if (matches[7])
target.nanos = (parseInt("1" + matches[7] + "0".repeat(9 - matches[7].length)) - 1000000000);
return target;
}
create(value?: PartialMessage<Timestamp>): Timestamp {
const message = { seconds: "0", nanos: 0 };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<Timestamp>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Timestamp): Timestamp {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* int64 seconds */ 1:
message.seconds = reader.int64().toString();
break;
case /* int32 nanos */ 2:
message.nanos = reader.int32();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: Timestamp, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* int64 seconds = 1; */
if (message.seconds !== "0")
writer.tag(1, WireType.Varint).int64(message.seconds);
/* int32 nanos = 2; */
if (message.nanos !== 0)
writer.tag(2, WireType.Varint).int32(message.nanos);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.Timestamp
*/
export const Timestamp = new Timestamp$Type();
@@ -0,0 +1,748 @@
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
// @generated from protobuf file "google/protobuf/wrappers.proto" (package "google.protobuf", syntax proto3)
// tslint:disable
//
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Wrappers for primitive (non-message) types. These types are useful
// for embedding primitives in the `google.protobuf.Any` type and for places
// where we need to distinguish between the absence of a primitive
// typed field and its default value.
//
import { ScalarType } from "@protobuf-ts/runtime";
import { LongType } from "@protobuf-ts/runtime";
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
import type { IBinaryWriter } from "@protobuf-ts/runtime";
import { WireType } from "@protobuf-ts/runtime";
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
import type { IBinaryReader } from "@protobuf-ts/runtime";
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
import type { PartialMessage } from "@protobuf-ts/runtime";
import { reflectionMergePartial } from "@protobuf-ts/runtime";
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
import type { JsonValue } from "@protobuf-ts/runtime";
import type { JsonReadOptions } from "@protobuf-ts/runtime";
import type { JsonWriteOptions } from "@protobuf-ts/runtime";
import { MessageType } from "@protobuf-ts/runtime";
/**
* Wrapper message for `double`.
*
* The JSON representation for `DoubleValue` is JSON number.
*
* @generated from protobuf message google.protobuf.DoubleValue
*/
export interface DoubleValue {
/**
* The double value.
*
* @generated from protobuf field: double value = 1;
*/
value: number;
}
/**
* Wrapper message for `float`.
*
* The JSON representation for `FloatValue` is JSON number.
*
* @generated from protobuf message google.protobuf.FloatValue
*/
export interface FloatValue {
/**
* The float value.
*
* @generated from protobuf field: float value = 1;
*/
value: number;
}
/**
* Wrapper message for `int64`.
*
* The JSON representation for `Int64Value` is JSON string.
*
* @generated from protobuf message google.protobuf.Int64Value
*/
export interface Int64Value {
/**
* The int64 value.
*
* @generated from protobuf field: int64 value = 1;
*/
value: string;
}
/**
* Wrapper message for `uint64`.
*
* The JSON representation for `UInt64Value` is JSON string.
*
* @generated from protobuf message google.protobuf.UInt64Value
*/
export interface UInt64Value {
/**
* The uint64 value.
*
* @generated from protobuf field: uint64 value = 1;
*/
value: string;
}
/**
* Wrapper message for `int32`.
*
* The JSON representation for `Int32Value` is JSON number.
*
* @generated from protobuf message google.protobuf.Int32Value
*/
export interface Int32Value {
/**
* The int32 value.
*
* @generated from protobuf field: int32 value = 1;
*/
value: number;
}
/**
* Wrapper message for `uint32`.
*
* The JSON representation for `UInt32Value` is JSON number.
*
* @generated from protobuf message google.protobuf.UInt32Value
*/
export interface UInt32Value {
/**
* The uint32 value.
*
* @generated from protobuf field: uint32 value = 1;
*/
value: number;
}
/**
* Wrapper message for `bool`.
*
* The JSON representation for `BoolValue` is JSON `true` and `false`.
*
* @generated from protobuf message google.protobuf.BoolValue
*/
export interface BoolValue {
/**
* The bool value.
*
* @generated from protobuf field: bool value = 1;
*/
value: boolean;
}
/**
* Wrapper message for `string`.
*
* The JSON representation for `StringValue` is JSON string.
*
* @generated from protobuf message google.protobuf.StringValue
*/
export interface StringValue {
/**
* The string value.
*
* @generated from protobuf field: string value = 1;
*/
value: string;
}
/**
* Wrapper message for `bytes`.
*
* The JSON representation for `BytesValue` is JSON string.
*
* @generated from protobuf message google.protobuf.BytesValue
*/
export interface BytesValue {
/**
* The bytes value.
*
* @generated from protobuf field: bytes value = 1;
*/
value: Uint8Array;
}
// @generated message type with reflection information, may provide speed optimized methods
class DoubleValue$Type extends MessageType<DoubleValue> {
constructor() {
super("google.protobuf.DoubleValue", [
{ no: 1, name: "value", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }
]);
}
/**
* Encode `DoubleValue` to JSON number.
*/
internalJsonWrite(message: DoubleValue, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(2, message.value, "value", false, true);
}
/**
* Decode `DoubleValue` from JSON number.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: DoubleValue): DoubleValue {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 1, undefined, "value") as number;
return target;
}
create(value?: PartialMessage<DoubleValue>): DoubleValue {
const message = { value: 0 };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<DoubleValue>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DoubleValue): DoubleValue {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* double value */ 1:
message.value = reader.double();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: DoubleValue, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* double value = 1; */
if (message.value !== 0)
writer.tag(1, WireType.Bit64).double(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.DoubleValue
*/
export const DoubleValue = new DoubleValue$Type();
// @generated message type with reflection information, may provide speed optimized methods
class FloatValue$Type extends MessageType<FloatValue> {
constructor() {
super("google.protobuf.FloatValue", [
{ no: 1, name: "value", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }
]);
}
/**
* Encode `FloatValue` to JSON number.
*/
internalJsonWrite(message: FloatValue, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(1, message.value, "value", false, true);
}
/**
* Decode `FloatValue` from JSON number.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: FloatValue): FloatValue {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 1, undefined, "value") as number;
return target;
}
create(value?: PartialMessage<FloatValue>): FloatValue {
const message = { value: 0 };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<FloatValue>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FloatValue): FloatValue {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* float value */ 1:
message.value = reader.float();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: FloatValue, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* float value = 1; */
if (message.value !== 0)
writer.tag(1, WireType.Bit32).float(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.FloatValue
*/
export const FloatValue = new FloatValue$Type();
// @generated message type with reflection information, may provide speed optimized methods
class Int64Value$Type extends MessageType<Int64Value> {
constructor() {
super("google.protobuf.Int64Value", [
{ no: 1, name: "value", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
]);
}
/**
* Encode `Int64Value` to JSON string.
*/
internalJsonWrite(message: Int64Value, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(ScalarType.INT64, message.value, "value", false, true);
}
/**
* Decode `Int64Value` from JSON string.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Int64Value): Int64Value {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, ScalarType.INT64, LongType.STRING, "value") as any;
return target;
}
create(value?: PartialMessage<Int64Value>): Int64Value {
const message = { value: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<Int64Value>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Int64Value): Int64Value {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* int64 value */ 1:
message.value = reader.int64().toString();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: Int64Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* int64 value = 1; */
if (message.value !== "0")
writer.tag(1, WireType.Varint).int64(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.Int64Value
*/
export const Int64Value = new Int64Value$Type();
// @generated message type with reflection information, may provide speed optimized methods
class UInt64Value$Type extends MessageType<UInt64Value> {
constructor() {
super("google.protobuf.UInt64Value", [
{ no: 1, name: "value", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }
]);
}
/**
* Encode `UInt64Value` to JSON string.
*/
internalJsonWrite(message: UInt64Value, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(ScalarType.UINT64, message.value, "value", false, true);
}
/**
* Decode `UInt64Value` from JSON string.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: UInt64Value): UInt64Value {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, ScalarType.UINT64, LongType.STRING, "value") as any;
return target;
}
create(value?: PartialMessage<UInt64Value>): UInt64Value {
const message = { value: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<UInt64Value>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UInt64Value): UInt64Value {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* uint64 value */ 1:
message.value = reader.uint64().toString();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: UInt64Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* uint64 value = 1; */
if (message.value !== "0")
writer.tag(1, WireType.Varint).uint64(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.UInt64Value
*/
export const UInt64Value = new UInt64Value$Type();
// @generated message type with reflection information, may provide speed optimized methods
class Int32Value$Type extends MessageType<Int32Value> {
constructor() {
super("google.protobuf.Int32Value", [
{ no: 1, name: "value", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
]);
}
/**
* Encode `Int32Value` to JSON string.
*/
internalJsonWrite(message: Int32Value, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(5, message.value, "value", false, true);
}
/**
* Decode `Int32Value` from JSON string.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Int32Value): Int32Value {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 5, undefined, "value") as number;
return target;
}
create(value?: PartialMessage<Int32Value>): Int32Value {
const message = { value: 0 };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<Int32Value>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Int32Value): Int32Value {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* int32 value */ 1:
message.value = reader.int32();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: Int32Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* int32 value = 1; */
if (message.value !== 0)
writer.tag(1, WireType.Varint).int32(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.Int32Value
*/
export const Int32Value = new Int32Value$Type();
// @generated message type with reflection information, may provide speed optimized methods
class UInt32Value$Type extends MessageType<UInt32Value> {
constructor() {
super("google.protobuf.UInt32Value", [
{ no: 1, name: "value", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }
]);
}
/**
* Encode `UInt32Value` to JSON string.
*/
internalJsonWrite(message: UInt32Value, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(13, message.value, "value", false, true);
}
/**
* Decode `UInt32Value` from JSON string.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: UInt32Value): UInt32Value {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 13, undefined, "value") as number;
return target;
}
create(value?: PartialMessage<UInt32Value>): UInt32Value {
const message = { value: 0 };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<UInt32Value>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UInt32Value): UInt32Value {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* uint32 value */ 1:
message.value = reader.uint32();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: UInt32Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* uint32 value = 1; */
if (message.value !== 0)
writer.tag(1, WireType.Varint).uint32(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.UInt32Value
*/
export const UInt32Value = new UInt32Value$Type();
// @generated message type with reflection information, may provide speed optimized methods
class BoolValue$Type extends MessageType<BoolValue> {
constructor() {
super("google.protobuf.BoolValue", [
{ no: 1, name: "value", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
]);
}
/**
* Encode `BoolValue` to JSON bool.
*/
internalJsonWrite(message: BoolValue, options: JsonWriteOptions): JsonValue {
return message.value;
}
/**
* Decode `BoolValue` from JSON bool.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: BoolValue): BoolValue {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 8, undefined, "value") as boolean;
return target;
}
create(value?: PartialMessage<BoolValue>): BoolValue {
const message = { value: false };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<BoolValue>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BoolValue): BoolValue {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* bool value */ 1:
message.value = reader.bool();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: BoolValue, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* bool value = 1; */
if (message.value !== false)
writer.tag(1, WireType.Varint).bool(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.BoolValue
*/
export const BoolValue = new BoolValue$Type();
// @generated message type with reflection information, may provide speed optimized methods
class StringValue$Type extends MessageType<StringValue> {
constructor() {
super("google.protobuf.StringValue", [
{ no: 1, name: "value", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
/**
* Encode `StringValue` to JSON string.
*/
internalJsonWrite(message: StringValue, options: JsonWriteOptions): JsonValue {
return message.value;
}
/**
* Decode `StringValue` from JSON string.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: StringValue): StringValue {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 9, undefined, "value") as string;
return target;
}
create(value?: PartialMessage<StringValue>): StringValue {
const message = { value: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<StringValue>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StringValue): StringValue {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string value */ 1:
message.value = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: StringValue, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string value = 1; */
if (message.value !== "")
writer.tag(1, WireType.LengthDelimited).string(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.StringValue
*/
export const StringValue = new StringValue$Type();
// @generated message type with reflection information, may provide speed optimized methods
class BytesValue$Type extends MessageType<BytesValue> {
constructor() {
super("google.protobuf.BytesValue", [
{ no: 1, name: "value", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
]);
}
/**
* Encode `BytesValue` to JSON string.
*/
internalJsonWrite(message: BytesValue, options: JsonWriteOptions): JsonValue {
return this.refJsonWriter.scalar(12, message.value, "value", false, true);
}
/**
* Decode `BytesValue` from JSON string.
*/
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: BytesValue): BytesValue {
if (!target)
target = this.create();
target.value = this.refJsonReader.scalar(json, 12, undefined, "value") as Uint8Array;
return target;
}
create(value?: PartialMessage<BytesValue>): BytesValue {
const message = { value: new Uint8Array(0) };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<BytesValue>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BytesValue): BytesValue {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* bytes value */ 1:
message.value = reader.bytes();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: BytesValue, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* bytes value = 1; */
if (message.value.length)
writer.tag(1, WireType.LengthDelimited).bytes(message.value);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message google.protobuf.BytesValue
*/
export const BytesValue = new BytesValue$Type();
+4
View File
@@ -0,0 +1,4 @@
export * from './google/protobuf/timestamp'
export * from './google/protobuf/wrappers'
export * from './results/api/v1/artifact'
export * from './results/api/v1/artifact.twirp'
@@ -0,0 +1,770 @@
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
// @generated from protobuf file "results/api/v1/artifact.proto" (package "github.actions.results.api.v1", syntax proto3)
// tslint:disable
import { ServiceType } from "@protobuf-ts/runtime-rpc";
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
import type { IBinaryWriter } from "@protobuf-ts/runtime";
import { WireType } from "@protobuf-ts/runtime";
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
import type { IBinaryReader } from "@protobuf-ts/runtime";
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
import type { PartialMessage } from "@protobuf-ts/runtime";
import { reflectionMergePartial } from "@protobuf-ts/runtime";
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
import { MessageType } from "@protobuf-ts/runtime";
import { Int64Value } from "../../../google/protobuf/wrappers";
import { StringValue } from "../../../google/protobuf/wrappers";
import { Timestamp } from "../../../google/protobuf/timestamp";
/**
* @generated from protobuf message github.actions.results.api.v1.CreateArtifactRequest
*/
export interface CreateArtifactRequest {
/**
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* @generated from protobuf field: string name = 3;
*/
name: string;
/**
* @generated from protobuf field: google.protobuf.Timestamp expires_at = 4;
*/
expiresAt?: Timestamp;
/**
* @generated from protobuf field: int32 version = 5;
*/
version: number;
}
/**
* @generated from protobuf message github.actions.results.api.v1.CreateArtifactResponse
*/
export interface CreateArtifactResponse {
/**
* @generated from protobuf field: bool ok = 1;
*/
ok: boolean;
/**
* @generated from protobuf field: string signed_upload_url = 2;
*/
signedUploadUrl: string;
}
/**
* @generated from protobuf message github.actions.results.api.v1.FinalizeArtifactRequest
*/
export interface FinalizeArtifactRequest {
/**
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* @generated from protobuf field: string name = 3;
*/
name: string;
/**
* @generated from protobuf field: int64 size = 4;
*/
size: string;
/**
* @generated from protobuf field: google.protobuf.StringValue hash = 5;
*/
hash?: StringValue; // optional
}
/**
* @generated from protobuf message github.actions.results.api.v1.FinalizeArtifactResponse
*/
export interface FinalizeArtifactResponse {
/**
* @generated from protobuf field: bool ok = 1;
*/
ok: boolean;
/**
* @generated from protobuf field: int64 artifact_id = 2;
*/
artifactId: string;
}
/**
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsRequest
*/
export interface ListArtifactsRequest {
/**
* The backend plan ID
*
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* The backend job ID
*
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* Name of the artifact to filter on
*
* @generated from protobuf field: google.protobuf.StringValue name_filter = 3;
*/
nameFilter?: StringValue; // optional
/**
* Monolith Database ID of the artifact to filter on
*
* @generated from protobuf field: google.protobuf.Int64Value id_filter = 4;
*/
idFilter?: Int64Value; // optional
}
/**
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsResponse
*/
export interface ListArtifactsResponse {
/**
* @generated from protobuf field: repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts = 1;
*/
artifacts: ListArtifactsResponse_MonolithArtifact[];
}
/**
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact
*/
export interface ListArtifactsResponse_MonolithArtifact {
/**
* The backend plan ID
*
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* The backend job ID
*
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* Monolith database ID of the artifact
*
* @generated from protobuf field: int64 database_id = 3;
*/
databaseId: string;
/**
* Name of the artifact
*
* @generated from protobuf field: string name = 4;
*/
name: string;
/**
* Size of the artifact in bytes
*
* @generated from protobuf field: int64 size = 5;
*/
size: string;
/**
* When the artifact was created in the monolith
*
* @generated from protobuf field: google.protobuf.Timestamp created_at = 6;
*/
createdAt?: Timestamp;
}
/**
* @generated from protobuf message github.actions.results.api.v1.GetSignedArtifactURLRequest
*/
export interface GetSignedArtifactURLRequest {
/**
* @generated from protobuf field: string workflow_run_backend_id = 1;
*/
workflowRunBackendId: string;
/**
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
*/
workflowJobRunBackendId: string;
/**
* @generated from protobuf field: string name = 3;
*/
name: string;
}
/**
* @generated from protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
*/
export interface GetSignedArtifactURLResponse {
/**
* @generated from protobuf field: string signed_url = 1;
*/
signedUrl: string;
}
// @generated message type with reflection information, may provide speed optimized methods
class CreateArtifactRequest$Type extends MessageType<CreateArtifactRequest> {
constructor() {
super("github.actions.results.api.v1.CreateArtifactRequest", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 4, name: "expires_at", kind: "message", T: () => Timestamp },
{ no: 5, name: "version", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
]);
}
create(value?: PartialMessage<CreateArtifactRequest>): CreateArtifactRequest {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "", version: 0 };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<CreateArtifactRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CreateArtifactRequest): CreateArtifactRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* string name */ 3:
message.name = reader.string();
break;
case /* google.protobuf.Timestamp expires_at */ 4:
message.expiresAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.expiresAt);
break;
case /* int32 version */ 5:
message.version = reader.int32();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: CreateArtifactRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* string name = 3; */
if (message.name !== "")
writer.tag(3, WireType.LengthDelimited).string(message.name);
/* google.protobuf.Timestamp expires_at = 4; */
if (message.expiresAt)
Timestamp.internalBinaryWrite(message.expiresAt, writer.tag(4, WireType.LengthDelimited).fork(), options).join();
/* int32 version = 5; */
if (message.version !== 0)
writer.tag(5, WireType.Varint).int32(message.version);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.CreateArtifactRequest
*/
export const CreateArtifactRequest = new CreateArtifactRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class CreateArtifactResponse$Type extends MessageType<CreateArtifactResponse> {
constructor() {
super("github.actions.results.api.v1.CreateArtifactResponse", [
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
{ no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<CreateArtifactResponse>): CreateArtifactResponse {
const message = { ok: false, signedUploadUrl: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<CreateArtifactResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CreateArtifactResponse): CreateArtifactResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* bool ok */ 1:
message.ok = reader.bool();
break;
case /* string signed_upload_url */ 2:
message.signedUploadUrl = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: CreateArtifactResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* bool ok = 1; */
if (message.ok !== false)
writer.tag(1, WireType.Varint).bool(message.ok);
/* string signed_upload_url = 2; */
if (message.signedUploadUrl !== "")
writer.tag(2, WireType.LengthDelimited).string(message.signedUploadUrl);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.CreateArtifactResponse
*/
export const CreateArtifactResponse = new CreateArtifactResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class FinalizeArtifactRequest$Type extends MessageType<FinalizeArtifactRequest> {
constructor() {
super("github.actions.results.api.v1.FinalizeArtifactRequest", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 4, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
{ no: 5, name: "hash", kind: "message", T: () => StringValue }
]);
}
create(value?: PartialMessage<FinalizeArtifactRequest>): FinalizeArtifactRequest {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "", size: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<FinalizeArtifactRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FinalizeArtifactRequest): FinalizeArtifactRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* string name */ 3:
message.name = reader.string();
break;
case /* int64 size */ 4:
message.size = reader.int64().toString();
break;
case /* google.protobuf.StringValue hash */ 5:
message.hash = StringValue.internalBinaryRead(reader, reader.uint32(), options, message.hash);
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: FinalizeArtifactRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* string name = 3; */
if (message.name !== "")
writer.tag(3, WireType.LengthDelimited).string(message.name);
/* int64 size = 4; */
if (message.size !== "0")
writer.tag(4, WireType.Varint).int64(message.size);
/* google.protobuf.StringValue hash = 5; */
if (message.hash)
StringValue.internalBinaryWrite(message.hash, writer.tag(5, WireType.LengthDelimited).fork(), options).join();
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeArtifactRequest
*/
export const FinalizeArtifactRequest = new FinalizeArtifactRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class FinalizeArtifactResponse$Type extends MessageType<FinalizeArtifactResponse> {
constructor() {
super("github.actions.results.api.v1.FinalizeArtifactResponse", [
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
{ no: 2, name: "artifact_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
]);
}
create(value?: PartialMessage<FinalizeArtifactResponse>): FinalizeArtifactResponse {
const message = { ok: false, artifactId: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<FinalizeArtifactResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FinalizeArtifactResponse): FinalizeArtifactResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* bool ok */ 1:
message.ok = reader.bool();
break;
case /* int64 artifact_id */ 2:
message.artifactId = reader.int64().toString();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: FinalizeArtifactResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* bool ok = 1; */
if (message.ok !== false)
writer.tag(1, WireType.Varint).bool(message.ok);
/* int64 artifact_id = 2; */
if (message.artifactId !== "0")
writer.tag(2, WireType.Varint).int64(message.artifactId);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeArtifactResponse
*/
export const FinalizeArtifactResponse = new FinalizeArtifactResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ListArtifactsRequest$Type extends MessageType<ListArtifactsRequest> {
constructor() {
super("github.actions.results.api.v1.ListArtifactsRequest", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "name_filter", kind: "message", T: () => StringValue },
{ no: 4, name: "id_filter", kind: "message", T: () => Int64Value }
]);
}
create(value?: PartialMessage<ListArtifactsRequest>): ListArtifactsRequest {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ListArtifactsRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsRequest): ListArtifactsRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* google.protobuf.StringValue name_filter */ 3:
message.nameFilter = StringValue.internalBinaryRead(reader, reader.uint32(), options, message.nameFilter);
break;
case /* google.protobuf.Int64Value id_filter */ 4:
message.idFilter = Int64Value.internalBinaryRead(reader, reader.uint32(), options, message.idFilter);
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ListArtifactsRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* google.protobuf.StringValue name_filter = 3; */
if (message.nameFilter)
StringValue.internalBinaryWrite(message.nameFilter, writer.tag(3, WireType.LengthDelimited).fork(), options).join();
/* google.protobuf.Int64Value id_filter = 4; */
if (message.idFilter)
Int64Value.internalBinaryWrite(message.idFilter, writer.tag(4, WireType.LengthDelimited).fork(), options).join();
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsRequest
*/
export const ListArtifactsRequest = new ListArtifactsRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ListArtifactsResponse$Type extends MessageType<ListArtifactsResponse> {
constructor() {
super("github.actions.results.api.v1.ListArtifactsResponse", [
{ no: 1, name: "artifacts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => ListArtifactsResponse_MonolithArtifact }
]);
}
create(value?: PartialMessage<ListArtifactsResponse>): ListArtifactsResponse {
const message = { artifacts: [] };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ListArtifactsResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsResponse): ListArtifactsResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts */ 1:
message.artifacts.push(ListArtifactsResponse_MonolithArtifact.internalBinaryRead(reader, reader.uint32(), options));
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ListArtifactsResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts = 1; */
for (let i = 0; i < message.artifacts.length; i++)
ListArtifactsResponse_MonolithArtifact.internalBinaryWrite(message.artifacts[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join();
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsResponse
*/
export const ListArtifactsResponse = new ListArtifactsResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ListArtifactsResponse_MonolithArtifact$Type extends MessageType<ListArtifactsResponse_MonolithArtifact> {
constructor() {
super("github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "database_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
{ no: 4, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 5, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
{ no: 6, name: "created_at", kind: "message", T: () => Timestamp }
]);
}
create(value?: PartialMessage<ListArtifactsResponse_MonolithArtifact>): ListArtifactsResponse_MonolithArtifact {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", databaseId: "0", name: "", size: "0" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<ListArtifactsResponse_MonolithArtifact>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsResponse_MonolithArtifact): ListArtifactsResponse_MonolithArtifact {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* int64 database_id */ 3:
message.databaseId = reader.int64().toString();
break;
case /* string name */ 4:
message.name = reader.string();
break;
case /* int64 size */ 5:
message.size = reader.int64().toString();
break;
case /* google.protobuf.Timestamp created_at */ 6:
message.createdAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.createdAt);
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ListArtifactsResponse_MonolithArtifact, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* int64 database_id = 3; */
if (message.databaseId !== "0")
writer.tag(3, WireType.Varint).int64(message.databaseId);
/* string name = 4; */
if (message.name !== "")
writer.tag(4, WireType.LengthDelimited).string(message.name);
/* int64 size = 5; */
if (message.size !== "0")
writer.tag(5, WireType.Varint).int64(message.size);
/* google.protobuf.Timestamp created_at = 6; */
if (message.createdAt)
Timestamp.internalBinaryWrite(message.createdAt, writer.tag(6, WireType.LengthDelimited).fork(), options).join();
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact
*/
export const ListArtifactsResponse_MonolithArtifact = new ListArtifactsResponse_MonolithArtifact$Type();
// @generated message type with reflection information, may provide speed optimized methods
class GetSignedArtifactURLRequest$Type extends MessageType<GetSignedArtifactURLRequest> {
constructor() {
super("github.actions.results.api.v1.GetSignedArtifactURLRequest", [
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<GetSignedArtifactURLRequest>): GetSignedArtifactURLRequest {
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<GetSignedArtifactURLRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetSignedArtifactURLRequest): GetSignedArtifactURLRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string workflow_run_backend_id */ 1:
message.workflowRunBackendId = reader.string();
break;
case /* string workflow_job_run_backend_id */ 2:
message.workflowJobRunBackendId = reader.string();
break;
case /* string name */ 3:
message.name = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: GetSignedArtifactURLRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string workflow_run_backend_id = 1; */
if (message.workflowRunBackendId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
/* string workflow_job_run_backend_id = 2; */
if (message.workflowJobRunBackendId !== "")
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
/* string name = 3; */
if (message.name !== "")
writer.tag(3, WireType.LengthDelimited).string(message.name);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLRequest
*/
export const GetSignedArtifactURLRequest = new GetSignedArtifactURLRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class GetSignedArtifactURLResponse$Type extends MessageType<GetSignedArtifactURLResponse> {
constructor() {
super("github.actions.results.api.v1.GetSignedArtifactURLResponse", [
{ no: 1, name: "signed_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<GetSignedArtifactURLResponse>): GetSignedArtifactURLResponse {
const message = { signedUrl: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<GetSignedArtifactURLResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetSignedArtifactURLResponse): GetSignedArtifactURLResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string signed_url */ 1:
message.signedUrl = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: GetSignedArtifactURLResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string signed_url = 1; */
if (message.signedUrl !== "")
writer.tag(1, WireType.LengthDelimited).string(message.signedUrl);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
*/
export const GetSignedArtifactURLResponse = new GetSignedArtifactURLResponse$Type();
/**
* @generated ServiceType for protobuf service github.actions.results.api.v1.ArtifactService
*/
export const ArtifactService = new ServiceType("github.actions.results.api.v1.ArtifactService", [
{ name: "CreateArtifact", options: {}, I: CreateArtifactRequest, O: CreateArtifactResponse },
{ name: "FinalizeArtifact", options: {}, I: FinalizeArtifactRequest, O: FinalizeArtifactResponse },
{ name: "ListArtifacts", options: {}, I: ListArtifactsRequest, O: ListArtifactsResponse },
{ name: "GetSignedArtifactURL", options: {}, I: GetSignedArtifactURLRequest, O: GetSignedArtifactURLResponse }
]);
@@ -0,0 +1,799 @@
import {
TwirpContext,
TwirpServer,
RouterEvents,
TwirpError,
TwirpErrorCode,
Interceptor,
TwirpContentType,
chainInterceptors,
} from "twirp-ts";
import {
CreateArtifactRequest,
CreateArtifactResponse,
FinalizeArtifactRequest,
FinalizeArtifactResponse,
ListArtifactsRequest,
ListArtifactsResponse,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse,
} from "./artifact";
//==================================//
// Client Code //
//==================================//
interface Rpc {
request(
service: string,
method: string,
contentType: "application/json" | "application/protobuf",
data: object | Uint8Array
): Promise<object | Uint8Array>;
}
export interface ArtifactServiceClient {
CreateArtifact(
request: CreateArtifactRequest
): Promise<CreateArtifactResponse>;
FinalizeArtifact(
request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse>;
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse>;
GetSignedArtifactURL(
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse>;
}
export class ArtifactServiceClientJSON implements ArtifactServiceClient {
private readonly rpc: Rpc;
constructor(rpc: Rpc) {
this.rpc = rpc;
this.CreateArtifact.bind(this);
this.FinalizeArtifact.bind(this);
this.ListArtifacts.bind(this);
this.GetSignedArtifactURL.bind(this);
}
CreateArtifact(
request: CreateArtifactRequest
): Promise<CreateArtifactResponse> {
const data = CreateArtifactRequest.toJson(request, {
useProtoFieldName: true,
emitDefaultValues: false,
});
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"CreateArtifact",
"application/json",
data as object
);
return promise.then((data) =>
CreateArtifactResponse.fromJson(data as any, {
ignoreUnknownFields: true,
})
);
}
FinalizeArtifact(
request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse> {
const data = FinalizeArtifactRequest.toJson(request, {
useProtoFieldName: true,
emitDefaultValues: false,
});
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"FinalizeArtifact",
"application/json",
data as object
);
return promise.then((data) =>
FinalizeArtifactResponse.fromJson(data as any, {
ignoreUnknownFields: true,
})
);
}
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse> {
const data = ListArtifactsRequest.toJson(request, {
useProtoFieldName: true,
emitDefaultValues: false,
});
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"ListArtifacts",
"application/json",
data as object
);
return promise.then((data) =>
ListArtifactsResponse.fromJson(data as any, { ignoreUnknownFields: true })
);
}
GetSignedArtifactURL(
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse> {
const data = GetSignedArtifactURLRequest.toJson(request, {
useProtoFieldName: true,
emitDefaultValues: false,
});
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"GetSignedArtifactURL",
"application/json",
data as object
);
return promise.then((data) =>
GetSignedArtifactURLResponse.fromJson(data as any, {
ignoreUnknownFields: true,
})
);
}
}
export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
private readonly rpc: Rpc;
constructor(rpc: Rpc) {
this.rpc = rpc;
this.CreateArtifact.bind(this);
this.FinalizeArtifact.bind(this);
this.ListArtifacts.bind(this);
this.GetSignedArtifactURL.bind(this);
}
CreateArtifact(
request: CreateArtifactRequest
): Promise<CreateArtifactResponse> {
const data = CreateArtifactRequest.toBinary(request);
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"CreateArtifact",
"application/protobuf",
data
);
return promise.then((data) =>
CreateArtifactResponse.fromBinary(data as Uint8Array)
);
}
FinalizeArtifact(
request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse> {
const data = FinalizeArtifactRequest.toBinary(request);
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"FinalizeArtifact",
"application/protobuf",
data
);
return promise.then((data) =>
FinalizeArtifactResponse.fromBinary(data as Uint8Array)
);
}
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse> {
const data = ListArtifactsRequest.toBinary(request);
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"ListArtifacts",
"application/protobuf",
data
);
return promise.then((data) =>
ListArtifactsResponse.fromBinary(data as Uint8Array)
);
}
GetSignedArtifactURL(
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse> {
const data = GetSignedArtifactURLRequest.toBinary(request);
const promise = this.rpc.request(
"github.actions.results.api.v1.ArtifactService",
"GetSignedArtifactURL",
"application/protobuf",
data
);
return promise.then((data) =>
GetSignedArtifactURLResponse.fromBinary(data as Uint8Array)
);
}
}
//==================================//
// Server Code //
//==================================//
export interface ArtifactServiceTwirp<T extends TwirpContext = TwirpContext> {
CreateArtifact(
ctx: T,
request: CreateArtifactRequest
): Promise<CreateArtifactResponse>;
FinalizeArtifact(
ctx: T,
request: FinalizeArtifactRequest
): Promise<FinalizeArtifactResponse>;
ListArtifacts(
ctx: T,
request: ListArtifactsRequest
): Promise<ListArtifactsResponse>;
GetSignedArtifactURL(
ctx: T,
request: GetSignedArtifactURLRequest
): Promise<GetSignedArtifactURLResponse>;
}
export enum ArtifactServiceMethod {
CreateArtifact = "CreateArtifact",
FinalizeArtifact = "FinalizeArtifact",
ListArtifacts = "ListArtifacts",
GetSignedArtifactURL = "GetSignedArtifactURL",
}
export const ArtifactServiceMethodList = [
ArtifactServiceMethod.CreateArtifact,
ArtifactServiceMethod.FinalizeArtifact,
ArtifactServiceMethod.ListArtifacts,
ArtifactServiceMethod.GetSignedArtifactURL,
];
export function createArtifactServiceServer<
T extends TwirpContext = TwirpContext
>(service: ArtifactServiceTwirp<T>) {
return new TwirpServer<ArtifactServiceTwirp, T>({
service,
packageName: "github.actions.results.api.v1",
serviceName: "ArtifactService",
methodList: ArtifactServiceMethodList,
matchRoute: matchArtifactServiceRoute,
});
}
function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
method: string,
events: RouterEvents<T>
) {
switch (method) {
case "CreateArtifact":
return async (
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
CreateArtifactRequest,
CreateArtifactResponse
>[]
) => {
ctx = { ...ctx, methodName: "CreateArtifact" };
await events.onMatch(ctx);
return handleArtifactServiceCreateArtifactRequest(
ctx,
service,
data,
interceptors
);
};
case "FinalizeArtifact":
return async (
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
FinalizeArtifactRequest,
FinalizeArtifactResponse
>[]
) => {
ctx = { ...ctx, methodName: "FinalizeArtifact" };
await events.onMatch(ctx);
return handleArtifactServiceFinalizeArtifactRequest(
ctx,
service,
data,
interceptors
);
};
case "ListArtifacts":
return async (
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
ListArtifactsRequest,
ListArtifactsResponse
>[]
) => {
ctx = { ...ctx, methodName: "ListArtifacts" };
await events.onMatch(ctx);
return handleArtifactServiceListArtifactsRequest(
ctx,
service,
data,
interceptors
);
};
case "GetSignedArtifactURL":
return async (
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
) => {
ctx = { ...ctx, methodName: "GetSignedArtifactURL" };
await events.onMatch(ctx);
return handleArtifactServiceGetSignedArtifactURLRequest(
ctx,
service,
data,
interceptors
);
};
default:
events.onNotFound();
const msg = `no handler found`;
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
function handleArtifactServiceCreateArtifactRequest<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
): Promise<string | Uint8Array> {
switch (ctx.contentType) {
case TwirpContentType.JSON:
return handleArtifactServiceCreateArtifactJSON<T>(
ctx,
service,
data,
interceptors
);
case TwirpContentType.Protobuf:
return handleArtifactServiceCreateArtifactProtobuf<T>(
ctx,
service,
data,
interceptors
);
default:
const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
function handleArtifactServiceFinalizeArtifactRequest<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
FinalizeArtifactRequest,
FinalizeArtifactResponse
>[]
): Promise<string | Uint8Array> {
switch (ctx.contentType) {
case TwirpContentType.JSON:
return handleArtifactServiceFinalizeArtifactJSON<T>(
ctx,
service,
data,
interceptors
);
case TwirpContentType.Protobuf:
return handleArtifactServiceFinalizeArtifactProtobuf<T>(
ctx,
service,
data,
interceptors
);
default:
const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
function handleArtifactServiceListArtifactsRequest<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
): Promise<string | Uint8Array> {
switch (ctx.contentType) {
case TwirpContentType.JSON:
return handleArtifactServiceListArtifactsJSON<T>(
ctx,
service,
data,
interceptors
);
case TwirpContentType.Protobuf:
return handleArtifactServiceListArtifactsProtobuf<T>(
ctx,
service,
data,
interceptors
);
default:
const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
function handleArtifactServiceGetSignedArtifactURLRequest<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
): Promise<string | Uint8Array> {
switch (ctx.contentType) {
case TwirpContentType.JSON:
return handleArtifactServiceGetSignedArtifactURLJSON<T>(
ctx,
service,
data,
interceptors
);
case TwirpContentType.Protobuf:
return handleArtifactServiceGetSignedArtifactURLProtobuf<T>(
ctx,
service,
data,
interceptors
);
default:
const msg = "unexpected Content-Type";
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
}
}
async function handleArtifactServiceCreateArtifactJSON<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
) {
let request: CreateArtifactRequest;
let response: CreateArtifactResponse;
try {
const body = JSON.parse(data.toString() || "{}");
request = CreateArtifactRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) {
if (e instanceof Error) {
const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
CreateArtifactRequest,
CreateArtifactResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.CreateArtifact(ctx, inputReq);
});
} else {
response = await service.CreateArtifact(ctx, request!);
}
return JSON.stringify(
CreateArtifactResponse.toJson(response, {
useProtoFieldName: true,
emitDefaultValues: false,
}) as string
);
}
async function handleArtifactServiceFinalizeArtifactJSON<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
FinalizeArtifactRequest,
FinalizeArtifactResponse
>[]
) {
let request: FinalizeArtifactRequest;
let response: FinalizeArtifactResponse;
try {
const body = JSON.parse(data.toString() || "{}");
request = FinalizeArtifactRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) {
if (e instanceof Error) {
const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
FinalizeArtifactRequest,
FinalizeArtifactResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.FinalizeArtifact(ctx, inputReq);
});
} else {
response = await service.FinalizeArtifact(ctx, request!);
}
return JSON.stringify(
FinalizeArtifactResponse.toJson(response, {
useProtoFieldName: true,
emitDefaultValues: false,
}) as string
);
}
async function handleArtifactServiceListArtifactsJSON<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
) {
let request: ListArtifactsRequest;
let response: ListArtifactsResponse;
try {
const body = JSON.parse(data.toString() || "{}");
request = ListArtifactsRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) {
if (e instanceof Error) {
const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
ListArtifactsRequest,
ListArtifactsResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.ListArtifacts(ctx, inputReq);
});
} else {
response = await service.ListArtifacts(ctx, request!);
}
return JSON.stringify(
ListArtifactsResponse.toJson(response, {
useProtoFieldName: true,
emitDefaultValues: false,
}) as string
);
}
async function handleArtifactServiceGetSignedArtifactURLJSON<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
) {
let request: GetSignedArtifactURLRequest;
let response: GetSignedArtifactURLResponse;
try {
const body = JSON.parse(data.toString() || "{}");
request = GetSignedArtifactURLRequest.fromJson(body, {
ignoreUnknownFields: true,
});
} catch (e) {
if (e instanceof Error) {
const msg = "the json request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.GetSignedArtifactURL(ctx, inputReq);
});
} else {
response = await service.GetSignedArtifactURL(ctx, request!);
}
return JSON.stringify(
GetSignedArtifactURLResponse.toJson(response, {
useProtoFieldName: true,
emitDefaultValues: false,
}) as string
);
}
async function handleArtifactServiceCreateArtifactProtobuf<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
) {
let request: CreateArtifactRequest;
let response: CreateArtifactResponse;
try {
request = CreateArtifactRequest.fromBinary(data);
} catch (e) {
if (e instanceof Error) {
const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
CreateArtifactRequest,
CreateArtifactResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.CreateArtifact(ctx, inputReq);
});
} else {
response = await service.CreateArtifact(ctx, request!);
}
return Buffer.from(CreateArtifactResponse.toBinary(response));
}
async function handleArtifactServiceFinalizeArtifactProtobuf<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
FinalizeArtifactRequest,
FinalizeArtifactResponse
>[]
) {
let request: FinalizeArtifactRequest;
let response: FinalizeArtifactResponse;
try {
request = FinalizeArtifactRequest.fromBinary(data);
} catch (e) {
if (e instanceof Error) {
const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
FinalizeArtifactRequest,
FinalizeArtifactResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.FinalizeArtifact(ctx, inputReq);
});
} else {
response = await service.FinalizeArtifact(ctx, request!);
}
return Buffer.from(FinalizeArtifactResponse.toBinary(response));
}
async function handleArtifactServiceListArtifactsProtobuf<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
) {
let request: ListArtifactsRequest;
let response: ListArtifactsResponse;
try {
request = ListArtifactsRequest.fromBinary(data);
} catch (e) {
if (e instanceof Error) {
const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
ListArtifactsRequest,
ListArtifactsResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.ListArtifacts(ctx, inputReq);
});
} else {
response = await service.ListArtifacts(ctx, request!);
}
return Buffer.from(ListArtifactsResponse.toBinary(response));
}
async function handleArtifactServiceGetSignedArtifactURLProtobuf<
T extends TwirpContext = TwirpContext
>(
ctx: T,
service: ArtifactServiceTwirp,
data: Buffer,
interceptors?: Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>[]
) {
let request: GetSignedArtifactURLRequest;
let response: GetSignedArtifactURLResponse;
try {
request = GetSignedArtifactURLRequest.fromBinary(data);
} catch (e) {
if (e instanceof Error) {
const msg = "the protobuf request could not be decoded";
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
}
}
if (interceptors && interceptors.length > 0) {
const interceptor = chainInterceptors(...interceptors) as Interceptor<
T,
GetSignedArtifactURLRequest,
GetSignedArtifactURLResponse
>;
response = await interceptor(ctx, request!, (ctx, inputReq) => {
return service.GetSignedArtifactURL(ctx, inputReq);
});
} else {
response = await service.GetSignedArtifactURL(ctx, request!);
}
return Buffer.from(GetSignedArtifactURLResponse.toBinary(response));
}
+228
View File
@@ -0,0 +1,228 @@
import {warning} from '@actions/core'
import {isGhes} from './shared/config'
import {
UploadArtifactOptions,
UploadArtifactResponse,
DownloadArtifactOptions,
GetArtifactResponse,
ListArtifactsOptions,
ListArtifactsResponse,
DownloadArtifactResponse,
FindOptions
} from './shared/interfaces'
import {uploadArtifact} from './upload/upload-artifact'
import {
downloadArtifactPublic,
downloadArtifactInternal
} from './download/download-artifact'
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact'
import {listArtifactsPublic, listArtifactsInternal} from './find/list-artifacts'
import {GHESNotSupportedError} from './shared/errors'
/**
* Generic interface for the artifact client.
*/
export interface ArtifactClient {
/**
* Uploads an artifact.
*
* @param name The name of the artifact, required
* @param files A list of absolute or relative paths that denote what files should be uploaded
* @param rootDirectory An absolute or relative file path that denotes the root parent directory of the files being uploaded
* @param options Extra options for customizing the upload behavior
* @returns single UploadArtifactResponse object
*/
uploadArtifact(
name: string,
files: string[],
rootDirectory: string,
options?: UploadArtifactOptions
): Promise<UploadArtifactResponse>
/**
* Lists all artifacts that are part of the current workflow run.
* This function will return at most 1000 artifacts per workflow run.
*
* If `options.findBy` is specified, this will call the public List-Artifacts API which can list from other runs.
* https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
*
* @param options Extra options that allow for the customization of the list behavior
* @returns ListArtifactResponse object
*/
listArtifacts(
options?: ListArtifactsOptions & FindOptions
): Promise<ListArtifactsResponse>
/**
* Finds an artifact by name.
* If there are multiple artifacts with the same name in the same workflow run, this will return the latest.
* If the artifact is not found, it will throw.
*
* If `options.findBy` is specified, this will use the public List Artifacts API with a name filter which can get artifacts from other runs.
* https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
* `@actions/artifact` v2+ does not allow for creating multiple artifacts with the same name in the same workflow run.
* It is possible to have multiple artifacts with the same name in the same workflow run by using old versions of upload-artifact (v1,v2 and v3), @actions/artifact < v2 or it is a rerun.
* If there are multiple artifacts with the same name in the same workflow run this function will return the first artifact that matches the name.
*
* @param artifactName The name of the artifact to find
* @param options Extra options that allow for the customization of the get behavior
*/
getArtifact(
artifactName: string,
options?: FindOptions
): Promise<GetArtifactResponse>
/**
* Downloads an artifact and unzips the content.
*
* If `options.findBy` is specified, this will use the public Download Artifact API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact
*
* @param artifactId The name of the artifact to download
* @param options Extra options that allow for the customization of the download behavior
* @returns single DownloadArtifactResponse object
*/
downloadArtifact(
artifactId: number,
options?: DownloadArtifactOptions & FindOptions
): Promise<DownloadArtifactResponse>
}
/**
* The default artifact client that is used by the artifact action(s).
*/
export class DefaultArtifactClient implements ArtifactClient {
async uploadArtifact(
name: string,
files: string[],
rootDirectory: string,
options?: UploadArtifactOptions
): Promise<UploadArtifactResponse> {
try {
if (isGhes()) {
throw new GHESNotSupportedError()
}
return uploadArtifact(name, files, rootDirectory, options)
} catch (error) {
warning(
`Artifact upload failed with error: ${error}.
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
If the error persists, please check whether Actions is operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
)
throw error
}
}
async downloadArtifact(
artifactId: number,
options?: DownloadArtifactOptions & FindOptions
): Promise<DownloadArtifactResponse> {
try {
if (isGhes()) {
throw new GHESNotSupportedError()
}
if (options?.findBy) {
const {
findBy: {repositoryOwner, repositoryName, token},
...downloadOptions
} = options
return downloadArtifactPublic(
artifactId,
repositoryOwner,
repositoryName,
token,
downloadOptions
)
}
return downloadArtifactInternal(artifactId, options)
} catch (error) {
warning(
`Download Artifact failed with error: ${error}.
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
)
throw error
}
}
async listArtifacts(
options?: ListArtifactsOptions & FindOptions
): Promise<ListArtifactsResponse> {
try {
if (isGhes()) {
throw new GHESNotSupportedError()
}
if (options?.findBy) {
const {
findBy: {workflowRunId, repositoryOwner, repositoryName, token}
} = options
return listArtifactsPublic(
workflowRunId,
repositoryOwner,
repositoryName,
token,
options?.latest
)
}
return listArtifactsInternal(options?.latest)
} catch (error: unknown) {
warning(
`Listing Artifacts failed with error: ${error}.
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
)
throw error
}
}
async getArtifact(
artifactName: string,
options?: FindOptions
): Promise<GetArtifactResponse> {
try {
if (isGhes()) {
throw new GHESNotSupportedError()
}
if (options?.findBy) {
const {
findBy: {workflowRunId, repositoryOwner, repositoryName, token}
} = options
return getArtifactPublic(
artifactName,
workflowRunId,
repositoryOwner,
repositoryName,
token
)
}
return getArtifactInternal(artifactName)
} catch (error: unknown) {
warning(
`Get Artifact failed with error: ${error}.
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
)
throw error
}
}
}
@@ -0,0 +1,172 @@
import fs from 'fs/promises'
import * as github from '@actions/github'
import * as core from '@actions/core'
import * as httpClient from '@actions/http-client'
import unzip from 'unzip-stream'
import {
DownloadArtifactOptions,
DownloadArtifactResponse
} from '../shared/interfaces'
import {getUserAgentString} from '../shared/user-agent'
import {getGitHubWorkspaceDir} from '../shared/config'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {
GetSignedArtifactURLRequest,
Int64Value,
ListArtifactsRequest
} from '../../generated'
import {getBackendIdsFromToken} from '../shared/util'
import {ArtifactNotFoundError} from '../shared/errors'
const scrubQueryParameters = (url: string): string => {
const parsed = new URL(url)
parsed.search = ''
return parsed.toString()
}
async function exists(path: string): Promise<boolean> {
try {
await fs.access(path)
return true
} catch (error) {
if (error.code === 'ENOENT') {
return false
} else {
throw error
}
}
}
async function streamExtract(url: string, directory: string): Promise<void> {
const client = new httpClient.HttpClient(getUserAgentString())
const response = await client.get(url)
if (response.message.statusCode !== 200) {
throw new Error(
`Unexpected HTTP response from blob storage: ${response.message.statusCode} ${response.message.statusMessage}`
)
}
return new Promise((resolve, reject) => {
response.message
.pipe(unzip.Extract({path: directory}))
.on('close', resolve)
.on('error', reject)
})
}
export async function downloadArtifactPublic(
artifactId: number,
repositoryOwner: string,
repositoryName: string,
token: string,
options?: DownloadArtifactOptions
): Promise<DownloadArtifactResponse> {
const downloadPath = await resolveOrCreateDirectory(options?.path)
const api = github.getOctokit(token)
core.info(
`Downloading artifact '${artifactId}' from '${repositoryOwner}/${repositoryName}'`
)
const {headers, status} = await api.rest.actions.downloadArtifact({
owner: repositoryOwner,
repo: repositoryName,
artifact_id: artifactId,
archive_format: 'zip',
request: {
redirect: 'manual'
}
})
if (status !== 302) {
throw new Error(`Unable to download artifact. Unexpected status: ${status}`)
}
const {location} = headers
if (!location) {
throw new Error(`Unable to redirect to artifact download url`)
}
core.info(
`Redirecting to blob download url: ${scrubQueryParameters(location)}`
)
try {
core.info(`Starting download of artifact to: ${downloadPath}`)
await streamExtract(location, downloadPath)
core.info(`Artifact download completed successfully.`)
} catch (error) {
throw new Error(`Unable to download and extract artifact: ${error.message}`)
}
return {downloadPath}
}
export async function downloadArtifactInternal(
artifactId: number,
options?: DownloadArtifactOptions
): Promise<DownloadArtifactResponse> {
const downloadPath = await resolveOrCreateDirectory(options?.path)
const artifactClient = internalArtifactTwirpClient()
const {workflowRunBackendId, workflowJobRunBackendId} =
getBackendIdsFromToken()
const listReq: ListArtifactsRequest = {
workflowRunBackendId,
workflowJobRunBackendId,
idFilter: Int64Value.create({value: artifactId.toString()})
}
const {artifacts} = await artifactClient.ListArtifacts(listReq)
if (artifacts.length === 0) {
throw new ArtifactNotFoundError(
`No artifacts found for ID: ${artifactId}\nAre you trying to download from a different run? Try specifying a github-token with \`actions:read\` scope.`
)
}
if (artifacts.length > 1) {
core.warning('Multiple artifacts found, defaulting to first.')
}
const signedReq: GetSignedArtifactURLRequest = {
workflowRunBackendId: artifacts[0].workflowRunBackendId,
workflowJobRunBackendId: artifacts[0].workflowJobRunBackendId,
name: artifacts[0].name
}
const {signedUrl} = await artifactClient.GetSignedArtifactURL(signedReq)
core.info(
`Redirecting to blob download url: ${scrubQueryParameters(signedUrl)}`
)
try {
core.info(`Starting download of artifact to: ${downloadPath}`)
await streamExtract(signedUrl, downloadPath)
core.info(`Artifact download completed successfully.`)
} catch (error) {
throw new Error(`Unable to download and extract artifact: ${error.message}`)
}
return {downloadPath}
}
async function resolveOrCreateDirectory(
downloadPath = getGitHubWorkspaceDir()
): Promise<string> {
if (!(await exists(downloadPath))) {
core.debug(
`Artifact destination folder does not exist, creating: ${downloadPath}`
)
await fs.mkdir(downloadPath, {recursive: true})
} else {
core.debug(`Artifact destination folder already exists: ${downloadPath}`)
}
return downloadPath
}
@@ -0,0 +1,117 @@
import {getOctokit} from '@actions/github'
import {retry} from '@octokit/plugin-retry'
import * as core from '@actions/core'
import {OctokitOptions} from '@octokit/core/dist-types/types'
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
import {getRetryOptions} from './retry-options'
import {requestLog} from '@octokit/plugin-request-log'
import {GetArtifactResponse} from '../shared/interfaces'
import {getBackendIdsFromToken} from '../shared/util'
import {getUserAgentString} from '../shared/user-agent'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {ListArtifactsRequest, StringValue, Timestamp} from '../../generated'
import {ArtifactNotFoundError, InvalidResponseError} from '../shared/errors'
export async function getArtifactPublic(
artifactName: string,
workflowRunId: number,
repositoryOwner: string,
repositoryName: string,
token: string
): Promise<GetArtifactResponse> {
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
const opts: OctokitOptions = {
log: undefined,
userAgent: getUserAgentString(),
previews: undefined,
retry: retryOpts,
request: requestOpts
}
const github = getOctokit(token, opts, retry, requestLog)
const getArtifactResp = await github.request(
'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts{?name}',
{
owner: repositoryOwner,
repo: repositoryName,
run_id: workflowRunId,
name: artifactName
}
)
if (getArtifactResp.status !== 200) {
throw new InvalidResponseError(
`Invalid response from GitHub API: ${getArtifactResp.status} (${getArtifactResp?.headers?.['x-github-request-id']})`
)
}
if (getArtifactResp.data.artifacts.length === 0) {
throw new ArtifactNotFoundError(
`Artifact not found for name: ${artifactName}`
)
}
let artifact = getArtifactResp.data.artifacts[0]
if (getArtifactResp.data.artifacts.length > 1) {
artifact = getArtifactResp.data.artifacts.sort((a, b) => b.id - a.id)[0]
core.debug(
`More than one artifact found for a single name, returning newest (id: ${artifact.id})`
)
}
return {
artifact: {
name: artifact.name,
id: artifact.id,
size: artifact.size_in_bytes,
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
}
}
}
export async function getArtifactInternal(
artifactName: string
): Promise<GetArtifactResponse> {
const artifactClient = internalArtifactTwirpClient()
const {workflowRunBackendId, workflowJobRunBackendId} =
getBackendIdsFromToken()
const req: ListArtifactsRequest = {
workflowRunBackendId,
workflowJobRunBackendId,
nameFilter: StringValue.create({value: artifactName})
}
const res = await artifactClient.ListArtifacts(req)
if (res.artifacts.length === 0) {
throw new ArtifactNotFoundError(
`Artifact not found for name: ${artifactName}`
)
}
let artifact = res.artifacts[0]
if (res.artifacts.length > 1) {
artifact = res.artifacts.sort(
(a, b) => Number(b.databaseId) - Number(a.databaseId)
)[0]
core.debug(
`More than one artifact found for a single name, returning newest (id: ${artifact.databaseId})`
)
}
return {
artifact: {
name: artifact.name,
id: Number(artifact.databaseId),
size: Number(artifact.size),
createdAt: artifact.createdAt
? Timestamp.toDate(artifact.createdAt)
: undefined
}
}
}
@@ -0,0 +1,165 @@
import {info, warning, debug} from '@actions/core'
import {getOctokit} from '@actions/github'
import {ListArtifactsResponse, Artifact} from '../shared/interfaces'
import {getUserAgentString} from '../shared/user-agent'
import {getRetryOptions} from './retry-options'
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
import {requestLog} from '@octokit/plugin-request-log'
import {retry} from '@octokit/plugin-retry'
import {OctokitOptions} from '@octokit/core/dist-types/types'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {getBackendIdsFromToken} from '../shared/util'
import {ListArtifactsRequest, Timestamp} from '../../generated'
// Limiting to 1000 for perf reasons
const maximumArtifactCount = 1000
const paginationCount = 100
const maxNumberOfPages = maximumArtifactCount / paginationCount
export async function listArtifactsPublic(
workflowRunId: number,
repositoryOwner: string,
repositoryName: string,
token: string,
latest = false
): Promise<ListArtifactsResponse> {
info(
`Fetching artifact list for workflow run ${workflowRunId} in repository ${repositoryOwner}/${repositoryName}`
)
let artifacts: Artifact[] = []
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
const opts: OctokitOptions = {
log: undefined,
userAgent: getUserAgentString(),
previews: undefined,
retry: retryOpts,
request: requestOpts
}
const github = getOctokit(token, opts, retry, requestLog)
let currentPageNumber = 1
const {data: listArtifactResponse} =
await github.rest.actions.listWorkflowRunArtifacts({
owner: repositoryOwner,
repo: repositoryName,
run_id: workflowRunId,
per_page: paginationCount,
page: currentPageNumber
})
let numberOfPages = Math.ceil(
listArtifactResponse.total_count / paginationCount
)
const totalArtifactCount = listArtifactResponse.total_count
if (totalArtifactCount > maximumArtifactCount) {
warning(
`Workflow run ${workflowRunId} has more than 1000 artifacts. Results will be incomplete as only the first ${maximumArtifactCount} artifacts will be returned`
)
numberOfPages = maxNumberOfPages
}
// Iterate over the first page
for (const artifact of listArtifactResponse.artifacts) {
artifacts.push({
name: artifact.name,
id: artifact.id,
size: artifact.size_in_bytes,
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
})
}
// Iterate over any remaining pages
for (
currentPageNumber;
currentPageNumber < numberOfPages;
currentPageNumber++
) {
currentPageNumber++
debug(`Fetching page ${currentPageNumber} of artifact list`)
const {data: listArtifactResponse} =
await github.rest.actions.listWorkflowRunArtifacts({
owner: repositoryOwner,
repo: repositoryName,
run_id: workflowRunId,
per_page: paginationCount,
page: currentPageNumber
})
for (const artifact of listArtifactResponse.artifacts) {
artifacts.push({
name: artifact.name,
id: artifact.id,
size: artifact.size_in_bytes,
createdAt: artifact.created_at
? new Date(artifact.created_at)
: undefined
})
}
}
if (latest) {
artifacts = filterLatest(artifacts)
}
info(`Found ${artifacts.length} artifact(s)`)
return {
artifacts
}
}
export async function listArtifactsInternal(
latest = false
): Promise<ListArtifactsResponse> {
const artifactClient = internalArtifactTwirpClient()
const {workflowRunBackendId, workflowJobRunBackendId} =
getBackendIdsFromToken()
const req: ListArtifactsRequest = {
workflowRunBackendId,
workflowJobRunBackendId
}
const res = await artifactClient.ListArtifacts(req)
let artifacts: Artifact[] = res.artifacts.map(artifact => ({
name: artifact.name,
id: Number(artifact.databaseId),
size: Number(artifact.size),
createdAt: artifact.createdAt
? Timestamp.toDate(artifact.createdAt)
: undefined
}))
if (latest) {
artifacts = filterLatest(artifacts)
}
info(`Found ${artifacts.length} artifact(s)`)
return {
artifacts
}
}
/**
* Filters a list of artifacts to only include the latest artifact for each name
* @param artifacts The artifacts to filter
* @returns The filtered list of artifacts
*/
function filterLatest(artifacts: Artifact[]): Artifact[] {
artifacts.sort((a, b) => b.id - a.id)
const latestArtifacts: Artifact[] = []
const seenArtifactNames = new Set<string>()
for (const artifact of artifacts) {
if (!seenArtifactNames.has(artifact.name)) {
latestArtifacts.push(artifact)
seenArtifactNames.add(artifact.name)
}
}
return latestArtifacts
}
@@ -0,0 +1,48 @@
import * as core from '@actions/core'
import {OctokitOptions} from '@octokit/core/dist-types/types'
import {RequestRequestOptions} from '@octokit/types'
export type RetryOptions = {
doNotRetry?: number[]
enabled?: boolean
}
// Defaults for fetching artifacts
const defaultMaxRetryNumber = 5
const defaultExemptStatusCodes = [400, 401, 403, 404, 422] // https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
export function getRetryOptions(
defaultOptions: OctokitOptions,
retries: number = defaultMaxRetryNumber,
exemptStatusCodes: number[] = defaultExemptStatusCodes
): [RetryOptions, RequestRequestOptions | undefined] {
if (retries <= 0) {
return [{enabled: false}, defaultOptions.request]
}
const retryOptions: RetryOptions = {
enabled: true
}
if (exemptStatusCodes.length > 0) {
retryOptions.doNotRetry = exemptStatusCodes
}
// The GitHub type has some defaults for `options.request`
// see: https://github.com/actions/toolkit/blob/4fbc5c941a57249b19562015edbd72add14be93d/packages/github/src/utils.ts#L15
// We pass these in here so they are not overridden.
const requestOptions: RequestRequestOptions = {
...defaultOptions.request,
retries
}
core.debug(
`GitHub client configured with: (retries: ${
requestOptions.retries
}, retry-exempt-status-code: ${
retryOptions.doNotRetry ?? 'octokit default: [400, 401, 403, 404, 422]'
})`
)
return [retryOptions, requestOptions]
}
@@ -0,0 +1,197 @@
import {HttpClient, HttpClientResponse, HttpCodes} from '@actions/http-client'
import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
import {info, debug} from '@actions/core'
import {ArtifactServiceClientJSON} from '../../generated'
import {getResultsServiceUrl, getRuntimeToken} from './config'
import {getUserAgentString} from './user-agent'
import {NetworkError, UsageError} from './errors'
// The twirp http client must implement this interface
interface Rpc {
request(
service: string,
method: string,
contentType: 'application/json' | 'application/protobuf',
data: object | Uint8Array
): Promise<object | Uint8Array>
}
class ArtifactHttpClient implements Rpc {
private httpClient: HttpClient
private baseUrl: string
private maxAttempts = 5
private baseRetryIntervalMilliseconds = 3000
private retryMultiplier = 1.5
constructor(
userAgent: string,
maxAttempts?: number,
baseRetryIntervalMilliseconds?: number,
retryMultiplier?: number
) {
const token = getRuntimeToken()
this.baseUrl = getResultsServiceUrl()
if (maxAttempts) {
this.maxAttempts = maxAttempts
}
if (baseRetryIntervalMilliseconds) {
this.baseRetryIntervalMilliseconds = baseRetryIntervalMilliseconds
}
if (retryMultiplier) {
this.retryMultiplier = retryMultiplier
}
this.httpClient = new HttpClient(userAgent, [
new BearerCredentialHandler(token)
])
}
// This function satisfies the Rpc interface. It is compatible with the JSON
// JSON generated client.
async request(
service: string,
method: string,
contentType: 'application/json' | 'application/protobuf',
data: object | Uint8Array
): Promise<object | Uint8Array> {
const url = new URL(`/twirp/${service}/${method}`, this.baseUrl).href
debug(`[Request] ${method} ${url}`)
const headers = {
'Content-Type': contentType
}
try {
const {body} = await this.retryableRequest(async () =>
this.httpClient.post(url, JSON.stringify(data), headers)
)
return body
} catch (error) {
throw new Error(`Failed to ${method}: ${error.message}`)
}
}
async retryableRequest(
operation: () => Promise<HttpClientResponse>
): Promise<{response: HttpClientResponse; body: object}> {
let attempt = 0
let errorMessage = ''
let rawBody = ''
while (attempt < this.maxAttempts) {
let isRetryable = false
try {
const response = await operation()
const statusCode = response.message.statusCode
rawBody = await response.readBody()
debug(`[Response] - ${response.message.statusCode}`)
debug(`Headers: ${JSON.stringify(response.message.headers, null, 2)}`)
const body = JSON.parse(rawBody)
debug(`Body: ${JSON.stringify(body, null, 2)}`)
if (this.isSuccessStatusCode(statusCode)) {
return {response, body}
}
isRetryable = this.isRetryableHttpStatusCode(statusCode)
errorMessage = `Failed request: (${statusCode}) ${response.message.statusMessage}`
if (body.msg) {
if (UsageError.isUsageErrorMessage(body.msg)) {
throw new UsageError()
}
errorMessage = `${errorMessage}: ${body.msg}`
}
} catch (error) {
if (error instanceof SyntaxError) {
debug(`Raw Body: ${rawBody}`)
throw error
}
if (error instanceof UsageError) {
throw error
}
if (NetworkError.isNetworkErrorCode(error?.code)) {
throw new NetworkError(error?.code)
}
isRetryable = true
errorMessage = error.message
}
if (!isRetryable) {
throw new Error(`Received non-retryable error: ${errorMessage}`)
}
if (attempt + 1 === this.maxAttempts) {
throw new Error(
`Failed to make request after ${this.maxAttempts} attempts: ${errorMessage}`
)
}
const retryTimeMilliseconds =
this.getExponentialRetryTimeMilliseconds(attempt)
info(
`Attempt ${attempt + 1} of ${
this.maxAttempts
} failed with error: ${errorMessage}. Retrying request in ${retryTimeMilliseconds} ms...`
)
await this.sleep(retryTimeMilliseconds)
attempt++
}
throw new Error(`Request failed`)
}
isSuccessStatusCode(statusCode?: number): boolean {
if (!statusCode) return false
return statusCode >= 200 && statusCode < 300
}
isRetryableHttpStatusCode(statusCode?: number): boolean {
if (!statusCode) return false
const retryableStatusCodes = [
HttpCodes.BadGateway,
HttpCodes.GatewayTimeout,
HttpCodes.InternalServerError,
HttpCodes.ServiceUnavailable,
HttpCodes.TooManyRequests
]
return retryableStatusCodes.includes(statusCode)
}
async sleep(milliseconds: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
getExponentialRetryTimeMilliseconds(attempt: number): number {
if (attempt < 0) {
throw new Error('attempt should be a positive integer')
}
if (attempt === 0) {
return this.baseRetryIntervalMilliseconds
}
const minTime =
this.baseRetryIntervalMilliseconds * this.retryMultiplier ** attempt
const maxTime = minTime * this.retryMultiplier
// returns a random number between minTime and maxTime (exclusive)
return Math.trunc(Math.random() * (maxTime - minTime) + minTime)
}
}
export function internalArtifactTwirpClient(options?: {
maxAttempts?: number
retryIntervalMs?: number
retryMultiplier?: number
}): ArtifactServiceClientJSON {
const client = new ArtifactHttpClient(
getUserAgentString(),
options?.maxAttempts,
options?.retryIntervalMs,
options?.retryMultiplier
)
return new ArtifactServiceClientJSON(client)
}
@@ -0,0 +1,53 @@
import os from 'os'
// Used for controlling the highWaterMark value of the zip that is being streamed
// The same value is used as the chunk size that is use during upload to blob storage
export function getUploadChunkSize(): number {
return 8 * 1024 * 1024 // 8 MB Chunks
}
export function getRuntimeToken(): string {
const token = process.env['ACTIONS_RUNTIME_TOKEN']
if (!token) {
throw new Error('Unable to get the ACTIONS_RUNTIME_TOKEN env variable')
}
return token
}
export function getResultsServiceUrl(): string {
const resultsUrl = process.env['ACTIONS_RESULTS_URL']
if (!resultsUrl) {
throw new Error('Unable to get the ACTIONS_RESULTS_URL env variable')
}
return new URL(resultsUrl).origin
}
export function isGhes(): boolean {
const ghUrl = new URL(
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
)
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
}
export function getGitHubWorkspaceDir(): string {
const ghWorkspaceDir = process.env['GITHUB_WORKSPACE']
if (!ghWorkspaceDir) {
throw new Error('Unable to get the GITHUB_WORKSPACE env variable')
}
return ghWorkspaceDir
}
// Mimics behavior of azcopy: https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize
// If your machine has fewer than 5 CPUs, then the value of this variable is set to 32.
// Otherwise, the default value is equal to 16 multiplied by the number of CPUs. The maximum value of this variable is 300.
export function getConcurrency(): number {
const numCPUs = os.cpus().length
if (numCPUs <= 4) {
return 32
}
const concurrency = 16 * numCPUs
return concurrency > 300 ? 300 : concurrency
}
@@ -0,0 +1,72 @@
export class FilesNotFoundError extends Error {
files: string[]
constructor(files: string[] = []) {
let message = 'No files were found to upload'
if (files.length > 0) {
message += `: ${files.join(', ')}`
}
super(message)
this.files = files
this.name = 'FilesNotFoundError'
}
}
export class InvalidResponseError extends Error {
constructor(message: string) {
super(message)
this.name = 'InvalidResponseError'
}
}
export class ArtifactNotFoundError extends Error {
constructor(message = 'Artifact not found') {
super(message)
this.name = 'ArtifactNotFoundError'
}
}
export class GHESNotSupportedError extends Error {
constructor(
message = '@actions/artifact v2.0.0+, upload-artifact@v4+ and download-artifact@v4+ are not currently supported on GHES.'
) {
super(message)
this.name = 'GHESNotSupportedError'
}
}
export class NetworkError extends Error {
code: string
constructor(code: string) {
const message = `Unable to make request: ${code}\nIf you are using self-hosted runners, please make sure your runner has access to all GitHub endpoints: https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#communication-between-self-hosted-runners-and-github`
super(message)
this.code = code
this.name = 'NetworkError'
}
static isNetworkErrorCode = (code?: string): boolean => {
if (!code) return false
return [
'ECONNRESET',
'ENOTFOUND',
'ETIMEDOUT',
'ECONNREFUSED',
'EHOSTUNREACH'
].includes(code)
}
}
export class UsageError extends Error {
constructor() {
const message = `Artifact storage quota has been hit. Unable to upload any new artifacts. Usage is recalculated every 6-12 hours.\nMore info on storage limits: https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#calculating-minute-and-storage-spending`
super(message)
this.name = 'UsageError'
}
static isUsageErrorMessage = (msg?: string): boolean => {
if (!msg) return false
return msg.includes('insufficient usage')
}
}
@@ -0,0 +1,149 @@
/**
* Response from the server when an artifact is uploaded
*/
export interface UploadArtifactResponse {
/**
* Total size of the artifact in bytes. Not provided if no artifact was uploaded
*/
size?: number
/**
* The id of the artifact that was created. Not provided if no artifact was uploaded
* This ID can be used as input to other APIs to download, delete or get more information about an artifact: https://docs.github.com/en/rest/actions/artifacts
*/
id?: number
}
/**
* Options for uploading an artifact
*/
export interface UploadArtifactOptions {
/**
* Duration after which artifact will expire in days.
*
* By default artifact expires after 90 days:
* https://docs.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts#downloading-and-deleting-artifacts-after-a-workflow-run-is-complete
*
* Use this option to override the default expiry.
*
* Min value: 1
* Max value: 90 unless changed by repository setting
*
* If this is set to a greater value than the retention settings allowed, the retention on artifacts
* will be reduced to match the max value allowed on server, and the upload process will continue. An
* input of 0 assumes default retention setting.
*/
retentionDays?: number
/**
* The level of compression for Zlib to be applied to the artifact archive.
* The value can range from 0 to 9:
* - 0: No compression
* - 1: Best speed
* - 6: Default compression (same as GNU Gzip)
* - 9: Best compression
* Higher levels will result in better compression, but will take longer to complete.
* For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
*/
compressionLevel?: number
}
/**
* Response from the server when getting an artifact
*/
export interface GetArtifactResponse {
/**
* Metadata about the artifact that was found
*/
artifact: Artifact
}
/**
* Options for listing artifacts
*/
export interface ListArtifactsOptions {
/**
* Filter the workflow run's artifacts to the latest by name
* In the case of reruns, this can be useful to avoid duplicates
*/
latest?: boolean
}
/**
* Response from the server when listing artifacts
*/
export interface ListArtifactsResponse {
/**
* A list of artifacts that were found
*/
artifacts: Artifact[]
}
/**
* Response from the server when downloading an artifact
*/
export interface DownloadArtifactResponse {
/**
* The path where the artifact was downloaded to
*/
downloadPath?: string
}
/**
* Options for downloading an artifact
*/
export interface DownloadArtifactOptions {
/**
* Denotes where the artifact will be downloaded to. If not specified then the artifact is download to GITHUB_WORKSPACE
*/
path?: string
}
/**
* An Actions Artifact
*/
export interface Artifact {
/**
* The name of the artifact
*/
name: string
/**
* The ID of the artifact
*/
id: number
/**
* The size of the artifact in bytes
*/
size: number
/**
* The time when the artifact was created
*/
createdAt?: Date
}
// FindOptions are for fetching Artifact(s) out of the scope of the current run.
export interface FindOptions {
/**
* The criteria for finding Artifact(s) out of the scope of the current run.
*/
findBy?: {
/**
* Token with actions:read permissions
*/
token: string
/**
* WorkflowRun of the artifact(s) to lookup
*/
workflowRunId: number
/**
* Repository owner (eg. 'actions')
*/
repositoryOwner: string
/**
* Repository owner (eg. 'toolkit')
*/
repositoryName: string
}
}
@@ -0,0 +1,9 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
const packageJson = require('../../../package.json')
/**
* Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package
*/
export function getUserAgentString(): string {
return `@actions/artifact-${packageJson.version}`
}
@@ -0,0 +1,71 @@
import * as core from '@actions/core'
import {getRuntimeToken} from './config'
import jwt_decode from 'jwt-decode'
export interface BackendIds {
workflowRunBackendId: string
workflowJobRunBackendId: string
}
interface ActionsToken {
scp: string
}
const InvalidJwtError = new Error(
'Failed to get backend IDs: The provided JWT token is invalid and/or missing claims'
)
// uses the JWT token claims to get the
// workflow run and workflow job run backend ids
export function getBackendIdsFromToken(): BackendIds {
const token = getRuntimeToken()
const decoded = jwt_decode<ActionsToken>(token)
if (!decoded.scp) {
throw InvalidJwtError
}
/*
* example decoded:
* {
* scp: "Actions.ExampleScope Actions.Results:ce7f54c7-61c7-4aae-887f-30da475f5f1a:ca395085-040a-526b-2ce8-bdc85f692774"
* }
*/
const scpParts = decoded.scp.split(' ')
if (scpParts.length === 0) {
throw InvalidJwtError
}
/*
* example scpParts:
* ["Actions.ExampleScope", "Actions.Results:ce7f54c7-61c7-4aae-887f-30da475f5f1a:ca395085-040a-526b-2ce8-bdc85f692774"]
*/
for (const scopes of scpParts) {
const scopeParts = scopes.split(':')
if (scopeParts?.[0] !== 'Actions.Results') {
// not the Actions.Results scope
continue
}
/*
* example scopeParts:
* ["Actions.Results", "ce7f54c7-61c7-4aae-887f-30da475f5f1a", "ca395085-040a-526b-2ce8-bdc85f692774"]
*/
if (scopeParts.length !== 3) {
// missing expected number of claims
throw InvalidJwtError
}
const ids = {
workflowRunBackendId: scopeParts[1],
workflowJobRunBackendId: scopeParts[2]
}
core.debug(`Workflow Run Backend ID: ${ids.workflowRunBackendId}`)
core.debug(`Workflow Job Run Backend ID: ${ids.workflowJobRunBackendId}`)
return ids
}
throw InvalidJwtError
}
@@ -0,0 +1,87 @@
import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob'
import {TransferProgressEvent} from '@azure/core-http'
import {ZipUploadStream} from './zip'
import {getUploadChunkSize, getConcurrency} from '../shared/config'
import * as core from '@actions/core'
import * as crypto from 'crypto'
import * as stream from 'stream'
import {NetworkError} from '../shared/errors'
export interface BlobUploadResponse {
/**
* The total reported upload size in bytes. Empty if the upload failed
*/
uploadSize?: number
/**
* The SHA256 hash of the uploaded file. Empty if the upload failed
*/
sha256Hash?: string
}
export async function uploadZipToBlobStorage(
authenticatedUploadURL: string,
zipUploadStream: ZipUploadStream
): Promise<BlobUploadResponse> {
let uploadByteCount = 0
const maxConcurrency = getConcurrency()
const bufferSize = getUploadChunkSize()
const blobClient = new BlobClient(authenticatedUploadURL)
const blockBlobClient = blobClient.getBlockBlobClient()
core.debug(
`Uploading artifact zip to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}`
)
const uploadCallback = (progress: TransferProgressEvent): void => {
core.info(`Uploaded bytes ${progress.loadedBytes}`)
uploadByteCount = progress.loadedBytes
}
const options: BlockBlobUploadStreamOptions = {
blobHTTPHeaders: {blobContentType: 'zip'},
onProgress: uploadCallback
}
let sha256Hash: string | undefined = undefined
const uploadStream = new stream.PassThrough()
const hashStream = crypto.createHash('sha256')
zipUploadStream.pipe(uploadStream) // This stream is used for the upload
zipUploadStream.pipe(hashStream).setEncoding('hex') // This stream is used to compute a hash of the zip content that gets used. Integrity check
core.info('Beginning upload of artifact content to blob storage')
try {
await blockBlobClient.uploadStream(
uploadStream,
bufferSize,
maxConcurrency,
options
)
} catch (error) {
if (NetworkError.isNetworkErrorCode(error?.code)) {
throw new NetworkError(error?.code)
}
throw error
}
core.info('Finished uploading artifact content to blob storage!')
hashStream.end()
sha256Hash = hashStream.read() as string
core.info(`SHA256 hash of uploaded artifact zip is ${sha256Hash}`)
if (uploadByteCount === 0) {
core.warning(
`No data was uploaded to blob storage. Reported upload byte count is 0.`
)
}
return {
uploadSize: uploadByteCount,
sha256Hash
}
}
@@ -0,0 +1,82 @@
import {info} from '@actions/core'
/**
* Invalid characters that cannot be in the artifact name or an uploaded file. Will be rejected
* from the server if attempted to be sent over. These characters are not allowed due to limitations with certain
* file systems such as NTFS. To maintain platform-agnostic behavior, all characters that are not supported by an
* individual filesystem/platform will not be supported on all fileSystems/platforms
*
* FilePaths can include characters such as \ and / which are not permitted in the artifact name alone
*/
const invalidArtifactFilePathCharacters = new Map<string, string>([
['"', ' Double quote "'],
[':', ' Colon :'],
['<', ' Less than <'],
['>', ' Greater than >'],
['|', ' Vertical bar |'],
['*', ' Asterisk *'],
['?', ' Question mark ?'],
['\r', ' Carriage return \\r'],
['\n', ' Line feed \\n']
])
const invalidArtifactNameCharacters = new Map<string, string>([
...invalidArtifactFilePathCharacters,
['\\', ' Backslash \\'],
['/', ' Forward slash /']
])
/**
* Validates the name of the artifact to check to make sure there are no illegal characters
*/
export function validateArtifactName(name: string): void {
if (!name) {
throw new Error(`Provided artifact name input during validation is empty`)
}
for (const [
invalidCharacterKey,
errorMessageForCharacter
] of invalidArtifactNameCharacters) {
if (name.includes(invalidCharacterKey)) {
throw new Error(
`The artifact name is not valid: ${name}. Contains the following character: ${errorMessageForCharacter}
Invalid characters include: ${Array.from(
invalidArtifactNameCharacters.values()
).toString()}
These characters are not allowed in the artifact name due to limitations with certain file systems such as NTFS. To maintain file system agnostic behavior, these characters are intentionally not allowed to prevent potential problems with downloads on different file systems.`
)
}
}
info(`Artifact name is valid!`)
}
/**
* Validates file paths to check for any illegal characters that can cause problems on different file systems
*/
export function validateFilePath(path: string): void {
if (!path) {
throw new Error(`Provided file path input during validation is empty`)
}
for (const [
invalidCharacterKey,
errorMessageForCharacter
] of invalidArtifactFilePathCharacters) {
if (path.includes(invalidCharacterKey)) {
throw new Error(
`The path for one of the files in artifact is not valid: ${path}. Contains the following character: ${errorMessageForCharacter}
Invalid characters include: ${Array.from(
invalidArtifactFilePathCharacters.values()
).toString()}
The following characters are not allowed in files that are uploaded due to limitations with certain file systems such as NTFS. To maintain file system agnostic behavior, these characters are intentionally not allowed to prevent potential problems with downloads on different file systems.
`
)
}
}
}
@@ -0,0 +1,34 @@
import {Timestamp} from '../../generated'
import * as core from '@actions/core'
export function getExpiration(retentionDays?: number): Timestamp | undefined {
if (!retentionDays) {
return undefined
}
const maxRetentionDays = getRetentionDays()
if (maxRetentionDays && maxRetentionDays < retentionDays) {
core.warning(
`Retention days cannot be greater than the maximum allowed retention set within the repository. Using ${maxRetentionDays} instead.`
)
retentionDays = maxRetentionDays
}
const expirationDate = new Date()
expirationDate.setDate(expirationDate.getDate() + retentionDays)
return Timestamp.fromDate(expirationDate)
}
function getRetentionDays(): number | undefined {
const retentionDays = process.env['GITHUB_RETENTION_DAYS']
if (!retentionDays) {
return undefined
}
const days = parseInt(retentionDays)
if (isNaN(days)) {
return undefined
}
return days
}
@@ -0,0 +1,115 @@
import * as core from '@actions/core'
import {
UploadArtifactOptions,
UploadArtifactResponse
} from '../shared/interfaces'
import {getExpiration} from './retention'
import {validateArtifactName} from './path-and-artifact-name-validation'
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
import {
UploadZipSpecification,
getUploadZipSpecification,
validateRootDirectory
} from './upload-zip-specification'
import {getBackendIdsFromToken} from '../shared/util'
import {uploadZipToBlobStorage} from './blob-upload'
import {createZipUploadStream} from './zip'
import {
CreateArtifactRequest,
FinalizeArtifactRequest,
StringValue
} from '../../generated'
import {FilesNotFoundError, InvalidResponseError} from '../shared/errors'
export async function uploadArtifact(
name: string,
files: string[],
rootDirectory: string,
options?: UploadArtifactOptions | undefined
): Promise<UploadArtifactResponse> {
validateArtifactName(name)
validateRootDirectory(rootDirectory)
const zipSpecification: UploadZipSpecification[] = getUploadZipSpecification(
files,
rootDirectory
)
if (zipSpecification.length === 0) {
throw new FilesNotFoundError(
zipSpecification.flatMap(s => (s.sourcePath ? [s.sourcePath] : []))
)
}
// get the IDs needed for the artifact creation
const backendIds = getBackendIdsFromToken()
// create the artifact client
const artifactClient = internalArtifactTwirpClient()
// create the artifact
const createArtifactReq: CreateArtifactRequest = {
workflowRunBackendId: backendIds.workflowRunBackendId,
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
name,
version: 4
}
// if there is a retention period, add it to the request
const expiresAt = getExpiration(options?.retentionDays)
if (expiresAt) {
createArtifactReq.expiresAt = expiresAt
}
const createArtifactResp =
await artifactClient.CreateArtifact(createArtifactReq)
if (!createArtifactResp.ok) {
throw new InvalidResponseError(
'CreateArtifact: response from backend was not ok'
)
}
const zipUploadStream = await createZipUploadStream(
zipSpecification,
options?.compressionLevel
)
// Upload zip to blob storage
const uploadResult = await uploadZipToBlobStorage(
createArtifactResp.signedUploadUrl,
zipUploadStream
)
// finalize the artifact
const finalizeArtifactReq: FinalizeArtifactRequest = {
workflowRunBackendId: backendIds.workflowRunBackendId,
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
name,
size: uploadResult.uploadSize ? uploadResult.uploadSize.toString() : '0'
}
if (uploadResult.sha256Hash) {
finalizeArtifactReq.hash = StringValue.create({
value: `sha256:${uploadResult.sha256Hash}`
})
}
core.info(`Finalizing artifact upload`)
const finalizeArtifactResp =
await artifactClient.FinalizeArtifact(finalizeArtifactReq)
if (!finalizeArtifactResp.ok) {
throw new InvalidResponseError(
'FinalizeArtifact: response from backend was not ok'
)
}
const artifactId = BigInt(finalizeArtifactResp.artifactId)
core.info(
`Artifact ${name}.zip successfully finalized. Artifact ID ${artifactId}`
)
return {
size: uploadResult.uploadSize,
id: Number(artifactId)
}
}
@@ -0,0 +1,111 @@
import * as fs from 'fs'
import {info} from '@actions/core'
import {normalize, resolve} from 'path'
import {validateFilePath} from './path-and-artifact-name-validation'
export interface UploadZipSpecification {
/**
* An absolute source path that points to a file that will be added to a zip. Null if creating a new directory
*/
sourcePath: string | null
/**
* The destination path in a zip for a file
*/
destinationPath: string
}
/**
* Checks if a root directory exists and is valid
* @param rootDirectory an absolute root directory path common to all input files that that will be trimmed from the final zip structure
*/
export function validateRootDirectory(rootDirectory: string): void {
if (!fs.existsSync(rootDirectory)) {
throw new Error(
`The provided rootDirectory ${rootDirectory} does not exist`
)
}
if (!fs.statSync(rootDirectory).isDirectory()) {
throw new Error(
`The provided rootDirectory ${rootDirectory} is not a valid directory`
)
}
info(`Root directory input is valid!`)
}
/**
* Creates a specification that describes how a zip file will be created for a set of input files
* @param filesToZip a list of file that should be included in the zip
* @param rootDirectory an absolute root directory path common to all input files that that will be trimmed from the final zip structure
*/
export function getUploadZipSpecification(
filesToZip: string[],
rootDirectory: string
): UploadZipSpecification[] {
const specification: UploadZipSpecification[] = []
// Normalize and resolve, this allows for either absolute or relative paths to be used
rootDirectory = normalize(rootDirectory)
rootDirectory = resolve(rootDirectory)
/*
Example
Input:
rootDirectory: '/home/user/files/plz-upload'
artifactFiles: [
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
]
Output:
specifications: [
['/home/user/files/plz-upload/file1.txt', '/file1.txt'],
['/home/user/files/plz-upload/file1.txt', '/file2.txt'],
['/home/user/files/plz-upload/file1.txt', '/dir/file3.txt']
]
The final zip that is later uploaded will look like this:
my-artifact.zip
- file.txt
- file2.txt
- dir/
- file3.txt
*/
for (let file of filesToZip) {
if (!fs.existsSync(file)) {
throw new Error(`File ${file} does not exist`)
}
if (!fs.statSync(file).isDirectory()) {
// Normalize and resolve, this allows for either absolute or relative paths to be used
file = normalize(file)
file = resolve(file)
if (!file.startsWith(rootDirectory)) {
throw new Error(
`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`
)
}
// Check for forbidden characters in file paths that may cause ambiguous behavior if downloaded on different file systems
const uploadPath = file.replace(rootDirectory, '')
validateFilePath(uploadPath)
specification.push({
sourcePath: file,
destinationPath: uploadPath
})
} else {
// Empty directory
const directoryPath = file.replace(rootDirectory, '')
validateFilePath(directoryPath)
specification.push({
sourcePath: null,
destinationPath: directoryPath
})
}
}
return specification
}
@@ -0,0 +1,101 @@
import * as stream from 'stream'
import * as archiver from 'archiver'
import * as core from '@actions/core'
import {createReadStream} from 'fs'
import {UploadZipSpecification} from './upload-zip-specification'
import {getUploadChunkSize} from '../shared/config'
export const DEFAULT_COMPRESSION_LEVEL = 6
// Custom stream transformer so we can set the highWaterMark property
// See https://github.com/nodejs/node/issues/8855
export class ZipUploadStream extends stream.Transform {
constructor(bufferSize: number) {
super({
highWaterMark: bufferSize
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_transform(chunk: any, enc: any, cb: any): void {
cb(null, chunk)
}
}
export async function createZipUploadStream(
uploadSpecification: UploadZipSpecification[],
compressionLevel: number = DEFAULT_COMPRESSION_LEVEL
): Promise<ZipUploadStream> {
core.debug(
`Creating Artifact archive with compressionLevel: ${compressionLevel}`
)
const zip = archiver.create('zip', {
highWaterMark: getUploadChunkSize(),
zlib: {level: compressionLevel}
})
// register callbacks for various events during the zip lifecycle
zip.on('error', zipErrorCallback)
zip.on('warning', zipWarningCallback)
zip.on('finish', zipFinishCallback)
zip.on('end', zipEndCallback)
for (const file of uploadSpecification) {
if (file.sourcePath !== null) {
// Add a normal file to the zip
zip.append(createReadStream(file.sourcePath), {
name: file.destinationPath
})
} else {
// Add a directory to the zip
zip.append('', {name: file.destinationPath})
}
}
const bufferSize = getUploadChunkSize()
const zipUploadStream = new ZipUploadStream(bufferSize)
core.debug(
`Zip write high watermark value ${zipUploadStream.writableHighWaterMark}`
)
core.debug(
`Zip read high watermark value ${zipUploadStream.readableHighWaterMark}`
)
zip.pipe(zipUploadStream)
zip.finalize()
return zipUploadStream
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const zipErrorCallback = (error: any): void => {
core.error('An error has occurred while creating the zip file for upload')
core.info(error)
throw new Error('An error has occurred during zip creation for the artifact')
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const zipWarningCallback = (error: any): void => {
if (error.code === 'ENOENT') {
core.warning(
'ENOENT warning during artifact zip creation. No such file or directory'
)
core.info(error)
} else {
core.warning(
`A non-blocking warning has occurred during artifact zip creation: ${error.code}`
)
core.info(error)
}
}
const zipFinishCallback = (): void => {
core.debug('Zip stream for upload has finished.')
}
const zipEndCallback = (): void => {
core.debug('Zip stream for upload has ended.')
}

Some files were not shown because too many files have changed in this diff Show More