Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@actions/artifact package #304

Merged
merged 48 commits into from
Feb 11, 2020
Merged

Conversation

konradpabjan
Copy link
Contributor

@konradpabjan konradpabjan commented Jan 13, 2020

Initial commit for the @actions/artifact package. So far only contains the code for uploading an artifact, download will come in a separate PR.

Adds support for uploading artifacts with new APIs that are independent of the runner (non-plugin). The original code for uploading artifacts can be found here (see https://github.com/actions/runner/tree/master/src/Runner.Plugins/Artifact). This PR largely ports over the C# code for uploading artifacts to node and switches over to some recently added APIs. This new package will be used for the v2 versions of actions/upload-artifact and actions/download-artifact.

Been using the structure of @actions/glob in this repo as an example. For this PR I deliberately did not do tsc and npm-install so there is no lib folder or node_modules folder. Trying to keep it clean and simple for this PR so that it is easy to review.

Been testing with the following two repos for upload artifact: https://github.com/bbq-beets/artifact-package and https://github.com/bbq-beets/upload-artifact-v2

Future work not part of this PR

  • Tests (all the code in search.ts and util.ts is a good candidate, will be added to a _TEST_ directory just like in all the other packages in this repo) (Tests have been added)
  • All the code related to downloadArtifact and downloadAllArtifacts (TODOs can be seen in src/internal-artifact.ts)
  • README with examples (will be added after download artifact is working and the package is almost ready to release)
  • lib and node_modules folder, (just like in `@actions/glob), will be added as we get close to release and everything is tested

Search uses our new glob package: @actions/glob (searching will be externally done)
Http calls are made using our new: @actions/http-client package in order to support proxies

Much of the work that was done in @actions/cache was used as a reference in terms of how concurrent chunked uploads are done, see: actions/cache#128

Formatting was done by doing prettier --write packages src/*.ts so the style should be consistent with the other code in this repo.

packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/package.json Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/utils.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/artifact.ts Outdated Show resolved Hide resolved
packages/artifact/src/search.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-artifact-http-client.ts Outdated Show resolved Hide resolved
@yacaovsnc
Copy link
Contributor

Working on some major changes (almost ready but not quite), don't review yet

Errr, didn't see this....

@konradpabjan konradpabjan changed the title @actions/artifact package @actions/artifact package - Almost ready for review Jan 31, 2020
@konradpabjan konradpabjan changed the title @actions/artifact package - Almost ready for review @actions/artifact package Feb 3, 2020
@konradpabjan
Copy link
Contributor Author

Working on some major changes (almost ready but not quite), don't review yet

Errr, didn't see this....

Still a lot of great feedback! I should have changed the PR title so it's more obvious that it's not ready for review, I'll do that moving forward. Thanks for taking a look! 😀

packages/artifact/package.json Outdated Show resolved Hide resolved
packages/artifact/src/config-variables.ts Outdated Show resolved Hide resolved

const parameters: UploadFileParameters[] = []
let continueOnError = true
if (options) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not future proof - if we add another option in the future, this check will fail. Would
const continueOnError = !!(options && options.continueOnError)
work?

Copy link
Contributor Author

@konradpabjan konradpabjan Feb 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In upload-options.ts, continueOnError is a required property though, so as long as there are some uploadOptions provided this should work even if some extra properties are added to uploadOptions

If there ever are more options added to upload-options.ts, they should be required (there would be a lot of unnecessary checks if there were optional parameters in an already optional object). The general flow will be something like this?

// define default options
if (options){
// update default options to whatever is specified in options
}

Copy link
Contributor

@yacaovsnc yacaovsnc Feb 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, individual options in the options object should not be required. Imagine if there are many options available, user should only need to set the ones they care about.

Copy link
Contributor Author

@konradpabjan konradpabjan Feb 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed continueOnError so it is optional in upload-options.ts

Changed the rest to this:

  // by default, file uploads will continue if there is an error unless specified differently in the options
  let continueOnError = true
  if (options) {
    if (options.continueOnError === false) {
      continueOnError = false
    }
  }

The double bang operators didn't seem very readable so I tried to avoid it. We do also need to support a default value if no continueOnError option is specified. Doing all that in a single line is possible but it gets pretty ugly so I think what I have is easy to follow

Also added two extra tests so now we have the following cases:

  • no uploadOptions
  • uploadOptions with continueOnError set to undefined
  • uploadOptions with continueOnError set to false
  • uploadOptions with continueOnError set to true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be more readable as Yang suggested:

const continueOnError = !!(options && options.continueOnError)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that one liner would be fine if we didn't care about the default true behavior if no options are provided. So it just won't work

Changing to just that one line changes the expected behavior if no options are provided (2 tests start to fail).

packages/artifact/src/upload-http-client.ts Outdated Show resolved Hide resolved
packages/artifact/src/upload-specification.ts Outdated Show resolved Hide resolved
@konradpabjan
Copy link
Contributor Author

@ericsciple could you also take a 👀 at this PR. Getting ready to merge this in. A new package to the toolkit is quite a hefty addition and you're probably the best person to look at this. I have another PR pretty much ready to go after this with documentation and all the extra code related to downloading an artifact.

Copy link
Member

@joshmgross joshmgross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

path.join(artifactName, 'folder-f', 'bad-item3.txt')
)
} else {
throw new Error('this should never be reached')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to fail the test by throwing an error, we should be more explicit about what went wrong.

In this specific case, it might be better to simplify this into an array contains

expect(badUploadFilePaths).toContain(specification.uploadFilePath)

https://jestjs.io/docs/en/expect#tocontainitem

Copy link
Contributor Author

@konradpabjan konradpabjan Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toContain is fairly similar to what I have with includes, I can swap that out in a few places that I use it because it seems nicer

I use an array to check for the absolutePaths however using just another array for uploadFilePath does not 100% check for what we need. It is possible that all the correct strings exist for uploadFilePath in an array, however the right combination must match with the absolutePath which is what I'm doing with the if else-if statements

}

if (uploadSpecification.length === 0) {
core.warning(`No files found that can be uploaded`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a warning? It seems like an error case if there are no files to upload.

Copy link
Contributor Author

@konradpabjan konradpabjan Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current behavior is that and empty upload will throw a warning but not fail.

It is possible that someone includes only empty directories in the files that they want uploaded. If that is the case, the uploadspecification will be empty and this will be hit because directories get ignored by the FCS during upload.


const parameters: UploadFileParameters[] = []
let continueOnError = true
if (options) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be more readable as Yang suggested:

const continueOnError = !!(options && options.continueOnError)

)

// eslint-disable-next-line no-console
console.log(`Total size of all the files uploaded is ${fileSizes} bytes`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: you can use core.info here and elsewhere if you want to console.log. It's easier to mock core than console and you don't need the eslint disables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like core.info isn't documented anywhere, even though it exists 🤔 https://github.com/actions/toolkit/tree/master/packages/core

I can use it a few places, though console.log is better because it isn't limited to just strings so certain things like formatted http responses look better

if (isSuccessStatusCode(retryResponse.message.statusCode)) {
return true
} else {
// eslint-disable-next-line no-console
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think stdout is preferred so unit tests can be less noisy

e.g. here is a snippet from somewhere else in toolkit

        process.stdout.write(`GITHUB_EVENT_PATH ${path} does not exist${EOL}`)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure, the linter may have another reason for avoiding console.log

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could disable console.log in the jest configuration? https://stackoverflow.com/questions/44467657/jest-better-way-to-disable-console-inside-unit-tests

Some of the response logging that I have is really noisy, for the tests I'll just mock console.log so that there is no annoying output

This comment was marked as off-topic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up doing the following for each of the tests

   jest.spyOn(console, 'log').mockImplementation(() => {})
   jest.spyOn(core, 'debug').mockImplementation(() => {})
   jest.spyOn(core, 'info').mockImplementation(() => {})
   jest.spyOn(core, 'warning').mockImplementation(() => {})

Shouldn't be any noise in the tests now

@konradpabjan konradpabjan merged commit 6cbb8e9 into master Feb 11, 2020
@konradpabjan konradpabjan deleted the konradpabjan/actions/artifact branch February 11, 2020 14:50
at-wat pushed a commit to at-wat/actions-toolkit that referenced this pull request Aug 31, 2023
* Initial commit for @actions/artifact package
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants