Repository: ruby-syntax-tree/syntax_tree (Ruby)

Issue:
Bug with passing arguments for non-tty stdin.
In https://github.com/ruby-syntax-tree/syntax_tree/pull/152/files#diff-9c0147bbfba8210004d93e758fd167a09f12f0749003f15bd8ea5f41da995f9bR390, I believe the conditional changed from 

`$stdin.tty? || arguments.any?` to `$stdin.tty? && (arguments.any? || options.scripts.any?)`. This seems to alter the conditional to prevent non-tty stdin from using `FileItem` types. Instead you  get the following warning:

```
[warn] stdin
The listed files did not match the expected format.
```

This popped up for me when I tried to upgrade `syntax_tree` and it broke CI checks I had previously setup. 

If this was intentional, is there a better recommended way to run `stree:check` in CI?


Discussion:
Yeah this broke and then was fixed again. Are you running on the latest version?
I was updating to `3.6.0`
Oh, found the same bug in Discourse. Can't update to 3.6.0 because of this 

https://github.com/discourse/discourse-chat/pull/1256
In case it's useful for anyone else - we unblocked ourselves at Discourse by faking a TTY in GitHub actions:

```yaml
- name: Syntax Tree
  shell: script -qefc "/bin/bash {0}" /dev/null # fake tty to work around https://github.com/ruby-syntax-tree/syntax_tree/issues/159
  run: bundle exec stree check **/*.rb
```
Oh no! I'm so sorry to have broken your builds. I'm afraid I really don't understand exactly what TTY is and how it interacts with syntax tree if we're being totally honest. Would one of you be able potentially able to educate me? 
So I think TTY shells are shells that accept interaction via text input/output. Forking a process/running stuff on CI generally is not TTY, since there's no interaction.

In this case, I don't think there's an issue with `syntax_tree` itself, but rather the CLI tooling (and Rake tasks that depend on it). The change/code I linked seems to indicate that for the CLI to accept a list of files to check, it used to accept files as long as `$stdin` was either TTY *OR* `arguments` was provided. 

```ruby
if $stdin.tty? || arguments.any?
```

However, in the change for #152, it made it such that files could _only_ be passed in if a TTY `$stdin` was used *AND* either `arguments` are passed or `options.scripts` are passed 

```ruby
if $stdin.tty? && (arguments.any? || options.scripts.any?)
```

This means that non-TTY shells cannot pass filenames when running `stree:check` anymore (when they used to be able to). I _think_ (have not had to chance to verify) a repro of the issue would be to try and run something like

```ruby

SyntaxTree::Rake::CheckTask.new { |t| task.source_files = "foo.rb" }

stdout, stderr, status = Open3.capture3("./bin/rake stree:check") # this uses a non-TTY shell
puts stdout
puts stderr
```

I was not sure if it was intentional for the TTY shell restriction to be introduced.
Ahh thank you very much, that helps a lot.

Previously, I was checking if STDIN was a TTY to determine if there was content to be read. Instead now I'll just check the opposite (that inline scripts or filepaths were passed) and if nothing is present I'll try to read STDIN. The PR is up and I'll release it when it merges.
Thank you for your patience, v3.6.1 is out which fixes this. Let me know if you experience any more trouble.
3.6.1 works great - thanks @kddnewton
thanks for the turnaround @kddnewton . Am a fan of `syntax_tree` so far, keep up the great work!



Patch:
diff --git a/lib/syntax_tree/cli.rb b/lib/syntax_tree/cli.rb
index a364cd34..f3564e29 100644
--- a/lib/syntax_tree/cli.rb
+++ b/lib/syntax_tree/cli.rb
@@ -423,19 +423,12 @@ def run(argv)
             return 1
           end
 
-        # If we're not reading from stdin and the user didn't supply any
-        # filepaths to be read, then we exit with the usage message.
-        if $stdin.tty? && arguments.empty? && options.scripts.empty?
-          warn(HELP)
-          return 1
-        end
-
         # We're going to build up a queue of items to process.
         queue = Queue.new
 
-        # If we're reading from stdin, then we'll just add the stdin object to
-        # the queue. Otherwise, we'll add each of the filepaths to the queue.
-        if $stdin.tty? && (arguments.any? || options.scripts.any?)
+        # If there are any arguments or scripts, then we'll add those to the
+        # queue. Otherwise we'll read the content off STDIN.
+        if arguments.any? || options.scripts.any?
           arguments.each do |pattern|
             Dir
               .glob(pattern)


Test patch:
diff --git a/test/cli_test.rb b/test/cli_test.rb
index de09b093..3734e734 100644
--- a/test/cli_test.rb
+++ b/test/cli_test.rb
@@ -123,13 +123,6 @@ def test_help_default
     end
 
     def test_no_arguments
-      with_tty do
-        *, stderr = capture_io { SyntaxTree::CLI.run(["check"]) }
-        assert_includes(stderr, "stree help")
-      end
-    end
-
-    def test_no_arguments_no_tty
       stdin = $stdin
       $stdin = StringIO.new("1+1")
 
@@ -140,17 +133,13 @@ def test_no_arguments_no_tty
     end
 
     def test_inline_script
-      with_tty do
-        stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1]) }
-        assert_equal("1 + 1\n", stdio)
-      end
+      stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1]) }
+      assert_equal("1 + 1\n", stdio)
     end
 
     def test_multiple_inline_scripts
-      with_tty do
-        stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1 -e 2+2]) }
-        assert_equal("1 + 1\n2 + 2\n", stdio)
-      end
+      stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1 -e 2+2]) }
+      assert_equal("1 + 1\n2 + 2\n", stdio)
     end
 
     def test_generic_error
@@ -251,10 +240,8 @@ def run_cli(command, *args, contents: :default)
 
       status = nil
       stdio, stderr =
-        with_tty do
-          capture_io do
-            status = SyntaxTree::CLI.run([command, *args, tempfile.path])
-          end
+        capture_io do
+          status = SyntaxTree::CLI.run([command, *args, tempfile.path])
         end
 
       Result.new(status: status, stdio: stdio, stderr: stderr)
@@ -263,10 +250,6 @@ def run_cli(command, *args, contents: :default)
       tempfile.unlink
     end
 
-    def with_tty(&block)
-      $stdin.stub(:tty?, true, &block)
-    end
-
     def with_config_file(contents)
       filepath = File.join(Dir.pwd, SyntaxTree::CLI::ConfigFile::FILENAME)
       File.write(filepath, contents)