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

Allow specifying stdin #360

Merged
merged 9 commits into from
Apr 13, 2020
Merged

Allow specifying stdin #360

merged 9 commits into from
Apr 13, 2020

Conversation

sethvargo
Copy link
Contributor

Fixes GH-164

@@ -30,6 +30,9 @@ export interface ExecOptions {
/** optional. How long in ms to wait for STDIO streams to close after the exit event of the process before terminating. defaults to 10000 */
delay?: number

/** optional. input to write to the process on STDIN. */
stdin?: Buffer
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 kept going back-and-forth about whether to accept a Buffer or Stream here. I think Buffer is a better API for most users, but it's not quite as flexible as giving users the ability to specify a stream.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree that buffer is the better api for most users. Its simple and should work for most use cases here. If we end up implementing more complicated scenarios with streams in the future, we can always support passing in a stream or a buffer mutually exclusive. We some use cases for that scenario

@bryanmacfarlane , FYI.

Copy link
Member

Choose a reason for hiding this comment

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

Are we sure this is a buffer? subprocess.stdin advertises it as a writable stream. Another reason I wanted to see a pure js test instead of the script. https://nodejs.org/api/child_process.html#child_process_subprocess_stdin

Copy link
Collaborator

Choose a reason for hiding this comment

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

The input we are allowing a user to pass in here is a buffer.

We write the contents of that buffer to the process's StdIn Stream.

Very similar to how node does this with the input option you outlined below, which also takes a string and various other inputs.
https://nodejs.org/api/child_process.html#child_process_child_process_execfilesync_file_args_options

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry I just realized node also has input option. Should we just pass the value through and let node handle writing to the stream?

Copy link
Contributor

Choose a reason for hiding this comment

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

...that said, seems like would be an implementation detail and wouldn't change behavior exposed by this PR. So i think this PR is OK the way it is (incremental)

Copy link
Collaborator

Choose a reason for hiding this comment

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

input doesn't appear to be available for any of the async process creation function. In particular we use spawn. https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

Copy link
Contributor

Choose a reason for hiding this comment

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

oh weird, didnt realize it was only on the sync functions. makes sense now why we dont pass thru :)

@sethvargo
Copy link
Contributor Author

Test failure seems unrelated?

@joshmgross
Copy link
Member

👋 Thanks for this! I've added @bryanmacfarlane and @ericsciple to help review this change.

@sittie82

This comment has been minimized.

@sittie82

This comment has been minimized.

@ericsciple ericsciple requested a review from thboop February 28, 2020 18:33
@ericsciple
Copy link
Contributor

adding to @thboop's radar

@ericsciple
Copy link
Contributor

Would be great to solve in a way that enables #346 (chain output of one tool runner to input of second)

Might be good to start with generic bare minimum to enable the scenario, before adding specific helpers like "execWithPiping".

Workaround today, piping can be achieved today by running command line, but then lose arg escaping goodness built into tool runner.

Extremely leary of adding piping into toolrunner. Was in a lib before and weird race never solved. I think the second process shouldnt be started until output is actually ready from the first process? Worried about adding solution into toolrunner but not finishing.

@sethvargo
Copy link
Contributor Author

Hey @ericsciple thanks for the feedback. I think this does solve it in a way that supports #346. This is a lower-level API that enables Action authors to accept an input stream in their action. The framework itself could be extended to leverage this API to chain action output, but I don't think that belongs in this PR.

The proposed solution in #346 wouldn't solve the use case this PR is solving. I have actions that invoke a command. The command accepts either a filepath on disk or input on stdin. The current action performs additional work to write the contents to disk before executing the command, but the extra steps could be removed if the toolrunner accepted a stream instead.

  • It's not feasible to change the command's behavior
  • Accepting stdin on a pipe is quite common among many commands
  • Altering the command to run echo 'thing' | command isn't cross-platform compatible and relies on shell-specifics (like pipes), in addition to your mention of arg escaping; spawning that additional subcommand is an unnecessary fork if the process just accepts stdin
  • Writing files to disk is sometimes seen as a security hole, and the Actions framework makes it trivally easy to create a world-readable file

@ericsciple
Copy link
Contributor

@sethvargo sorry i intended much of the feedback for @thboop to consider when reviewing.

@thboop two scenarios i think we should cover: stdin, and piping.

@thboop thboop self-assigned this Mar 2, 2020
@craigdbarber
Copy link

@imjohnbo could you PTAL.

Copy link
Collaborator

@thboop thboop left a comment

Choose a reason for hiding this comment

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

Handles stdin is failing on windows. Do you have some time to fix that? If not, I can take over the PR to get this merged in.

Thanks for the contribution!

@@ -30,6 +30,9 @@ export interface ExecOptions {
/** optional. How long in ms to wait for STDIO streams to close after the exit event of the process before terminating. defaults to 10000 */
delay?: number

/** optional. input to write to the process on STDIN. */
stdin?: Buffer
Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree that buffer is the better api for most users. Its simple and should work for most use cases here. If we end up implementing more complicated scenarios with streams in the future, we can always support passing in a stream or a buffer mutually exclusive. We some use cases for that scenario

@bryanmacfarlane , FYI.

@sethvargo sethvargo requested a review from thboop April 8, 2020 23:16
@sethvargo
Copy link
Contributor Author

@thboop updated. seems happy now.

@sethvargo sethvargo requested a review from ericsciple April 9, 2020 13:22
if (IS_WINDOWS) {
command = 'wait-for-input.cmd'
} else {
command = 'wait-for-input.sh'
Copy link
Member

Choose a reason for hiding this comment

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

I would like to see a test that shows what an action author would do. e.g. all js instead of the sh and cmd scripts.

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 added a js-specific test, although I admit I'm not sure exactly what you're asking. All of these tests spawn a childprocess using exec - there's no "all js". The test spawns a node subprocess with a node file that prints what it gets on stdin.

@@ -524,6 +524,14 @@ export class ToolRunner extends events.EventEmitter {
resolve(exitCode)
}
})

if (this.options.stdin) {
if (!cp.stdin) {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Responded to this above: #360 (comment)

Copy link
Collaborator

@thboop thboop left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@ericsciple ericsciple left a comment

Choose a reason for hiding this comment

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

I think this change is good.

It seems like future goal is likely to align more with node's options. That is, allow more types for input (whatever types node allows) and passthru to node.

As long as we're convinced this PR doesn't prevent ^, then i think this incremental change sounds fine.

@bryanmacfarlane
Copy link
Member

added to todo list for one last look

@joshmgross joshmgross removed their request for review April 10, 2020 19:04
@sethvargo
Copy link
Contributor Author

Yay! Looks like we're all green 🟢

@thboop thboop merged commit c4b6011 into actions:master Apr 13, 2020
@sethvargo sethvargo deleted the sethvargo/stdin branch April 13, 2020 18:31
akiojin added a commit to akiojin/store-git-credential-github-action that referenced this pull request Feb 21, 2022
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.

Add stdin support to exec
7 participants