Repository: pantsbuild/pants

Issue:
discrepancy between ./pants changed and ./pants --changed-parent=head list
clean repo:
```
$ ./pants changed --parent=head
WARN] /Users/yic/workspace/pants/src/python/pants/task/console_task.py:57: DeprecationWarning: DEPRECATED: `./pants changed` will be removed in version 1.5.0dev0.
  Use e.g. `./pants --changed-parent=HEAD list` instead.
  for value in self.console_output(targets):
```
(result is empty, which is correct)

```
$ ./pants --changed-parent=head list | wc -l
    1462
```




Discussion:
I don't seem to repro this:

```
[omerta pants (master)]$ ./pants changed --parent=head
WARN] /Users/kwilson/dev/pants/src/python/pants/task/console_task.py:57: DeprecationWarning: DEPRECATED: `./pants changed` will be removed in version 1.5.0dev0.
  Use e.g. `./pants --changed-parent=HEAD list` instead.
  for value in self.console_output(targets):


[omerta pants (master)]$ ./pants --changed-parent=head list

[omerta pants (master)]$ git rev-parse HEAD
5a90c00e842bf3439199b7ef68f9186de661b236
```
assuming you can still repro, could you paste the full debug output of `./pants -ldebug --changed-parent=HEAD list`
My guess is that this is related to a diff that matches "the empty set", which for `list` still triggers "the whole repo".
I cannot repro this now...will reopen if stumping on this again.
Ok now it is a different issue:

```
[tw-mbp-yic pants (master)]$ git st
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   contrib/go/examples/src/go/server/main.go

no changes added to commit (use "git add" and/or "git commit -a")
[tw-mbp-yic pants (master)]$  ./pants --changed-parent=head list

[tw-mbp-yic pants (master)]$ ./pants changed 
WARN] /Users/yic/workspace/pants/src/python/pants/task/console_task.py:57: DeprecationWarning: DEPRECATED: `./pants changed` will be removed in version 1.5.0dev0.
  Use e.g. `./pants --changed-parent=HEAD list` instead.
  for value in self.console_output(targets):

contrib/go/examples/src/go/server:server
```
looks like a default sources thing with `go` targets:

```
$ cat contrib/go/examples/src/go/server/BUILD 
# Auto-generated by pants!
# To re-generate run: `pants buildgen.go --materialize --remote`

go_binary(
  dependencies=[
    'contrib/go/examples/3rdparty/go/github.com/gorilla/mux',
    'contrib/go/examples/3rdparty/go/golang.org/x/net:http2',
    'contrib/go/examples/3rdparty/go/google.golang.org/grpc',
    'contrib/go/examples/3rdparty/go/gopkg.in/yaml.v2',
  ]
)
```

```
(Pdb) hydrated_target.adaptor
TargetAdaptor(address=contrib/go/examples/src/go/server)
(Pdb) hydrated_target.adaptor.kwargs()
{u'type_alias': u'go_binary', 'dependencies': [contrib/go/examples/3rdparty/go/github.com/gorilla/mux:mux, contrib/go/examples/3rdparty/go/golang.org/x/net:http2, contrib/go/examples/3rdparty/go/google.golang.org/grpc:grpc, contrib/go/examples/3rdparty/go/gopkg.in/yaml.v2:yaml.v2], u'name': u'server', u'address': BuildFileAddress(contrib/go/examples/src/go/server/BUILD, server)}
```

Resolving patch:
diff --git a/contrib/go/src/python/pants/contrib/go/targets/go_local_source.py b/contrib/go/src/python/pants/contrib/go/targets/go_local_source.py
--- a/contrib/go/src/python/pants/contrib/go/targets/go_local_source.py
+++ b/contrib/go/src/python/pants/contrib/go/targets/go_local_source.py
@@ -58,17 +58,18 @@ def alias(cls):
     """
     raise NotImplementedError()
 
-  def __init__(self, address=None, payload=None, **kwargs):
-    # We grab all files in the current directory except BUILD files for 2 reasons:
-    # 1. cgo: If a file imports "C" then it may rely on sibling .c, .cc, etc files that `go build`
-    #    will compile.
-    # 2. resources: Even though go does not support them; ie by providing a protocol to embed them
-    #    in binaries, it does allow them to be placed in a directory where a test might use them
-    #    for example via plain old filesystem access.
-    globs = Globs(ParseContext(rel_path=address.spec_path, type_aliases={}))
-    sources = globs('*', exclude=[globs('BUILD*'),
-                                  # This skips subdir content.
-                                  globs('*/**')])
+  def __init__(self, address=None, payload=None, sources=None, **kwargs):
+    if not sources:
+      # We grab all files in the current directory except BUILD files for 2 reasons:
+      # 1. cgo: If a file imports "C" then it may rely on sibling .c, .cc, etc files that `go build`
+      #    will compile.
+      # 2. resources: Even though go does not support them; ie by providing a protocol to embed them
+      #    in binaries, it does allow them to be placed in a directory where a test might use them
+      #    for example via plain old filesystem access.
+      globs = Globs(ParseContext(rel_path=address.spec_path, type_aliases={}))
+      sources = globs('*', exclude=[globs('BUILD*'),
+                                    # This skips subdir content.
+                                    globs('*/**')])
 
     payload = payload or Payload()
     payload.add_fields({
diff --git a/src/python/pants/bin/engine_initializer.py b/src/python/pants/bin/engine_initializer.py
--- a/src/python/pants/bin/engine_initializer.py
+++ b/src/python/pants/bin/engine_initializer.py
@@ -17,10 +17,10 @@
 from pants.engine.legacy.change_calculator import EngineChangeCalculator
 from pants.engine.legacy.graph import HydratedTargets, LegacyBuildGraph, create_legacy_graph_tasks
 from pants.engine.legacy.parser import LegacyPythonCallbacksParser
-from pants.engine.legacy.structs import (JavaLibraryAdaptor, JunitTestsAdaptor, JvmAppAdaptor,
-                                         PythonLibraryAdaptor, PythonTargetAdaptor,
-                                         PythonTestsAdaptor, RemoteSourcesAdaptor,
-                                         ScalaLibraryAdaptor, TargetAdaptor)
+from pants.engine.legacy.structs import (GoTargetAdaptor, JavaLibraryAdaptor, JunitTestsAdaptor,
+                                         JvmAppAdaptor, PythonLibraryAdaptor, PythonTargetAdaptor,
+                                         PythonTestsAdaptor, RemoteSourcesAdaptor, ScalaLibraryAdaptor,
+                                         TargetAdaptor)
 from pants.engine.mapper import AddressMapper
 from pants.engine.parser import SymbolTable
 from pants.engine.scheduler import LocalScheduler
@@ -58,6 +58,8 @@ def table(cls):
       aliases[alias] = ScalaLibraryAdaptor
     for alias in ['python_library', 'pants_plugin']:
       aliases[alias] = PythonLibraryAdaptor
+    for alias in ['go_library', 'go_binary']:
+      aliases[alias] = GoTargetAdaptor
 
     aliases['junit_tests'] = JunitTestsAdaptor
     aliases['jvm_app'] = JvmAppAdaptor
diff --git a/src/python/pants/engine/legacy/structs.py b/src/python/pants/engine/legacy/structs.py
--- a/src/python/pants/engine/legacy/structs.py
+++ b/src/python/pants/engine/legacy/structs.py
@@ -104,7 +104,6 @@ def __str__(self):
 
 
 class JavaLibraryAdaptor(TargetAdaptor):
-
   @property
   def default_sources_globs(self):
     return ('*.java',)
@@ -115,7 +114,6 @@ def default_sources_exclude_globs(self):
 
 
 class ScalaLibraryAdaptor(TargetAdaptor):
-
   @property
   def default_sources_globs(self):
     return ('*.scala',)
@@ -126,7 +124,6 @@ def default_sources_exclude_globs(self):
 
 
 class JunitTestsAdaptor(TargetAdaptor):
-
   java_test_globs = ('*Test.java',)
   scala_test_globs = ('*Test.scala', '*Spec.scala')
 
@@ -227,7 +224,6 @@ def field_adaptors(self):
 
 
 class PythonLibraryAdaptor(PythonTargetAdaptor):
-
   @property
   def default_sources_globs(self):
     return ('*.py',)
@@ -238,7 +234,6 @@ def default_sources_exclude_globs(self):
 
 
 class PythonTestsAdaptor(PythonTargetAdaptor):
-
   python_test_globs = ('test_*.py', '*_test.py')
 
   @property
@@ -246,6 +241,13 @@ def default_sources_globs(self):
     return self.python_test_globs
 
 
+class GoTargetAdaptor(TargetAdaptor):
+  @property
+  def default_sources_globs(self):
+    # N.B. Go targets glob on `*` due to the way resources and .c companion files are handled.
+    return ('*',)
+
+
 class BaseGlobs(Locatable, AbstractClass):
   """An adaptor class to allow BUILD file parsing from ContextAwareObjectFactories."""
 


Test patch:
diff --git a/tests/python/pants_test/engine/legacy/test_changed_integration.py b/tests/python/pants_test/engine/legacy/test_changed_integration.py
--- a/tests/python/pants_test/engine/legacy/test_changed_integration.py
+++ b/tests/python/pants_test/engine/legacy/test_changed_integration.py
@@ -78,88 +78,110 @@ def create_isolated_git_repo():
   #          |--BUILD
   #          |--ClasspathDirectoriesSpec.scala
   with temporary_dir(root_dir=get_buildroot()) as worktree:
-    with safe_open(os.path.join(worktree, 'README'), 'w') as fp:
-      fp.write('Just a test tree.')
-
-    # Create an empty pants config file.
-    touch(os.path.join(worktree, 'pants.ini'))
-
-    # Copy .gitignore to new repo.
-    shutil.copyfile('.gitignore', os.path.join(worktree, '.gitignore'))
+    def create_file(path, content):
+      """Creates a file in the isolated git repo."""
+      write_path = os.path.join(worktree, path)
+      with safe_open(write_path, 'w') as f:
+        f.write(dedent(content))
+      return write_path
+
+    def copy_into(path, to_path=None):
+      """Copies a file from the real git repo into the isolated git repo."""
+      write_path = os.path.join(worktree, to_path or path)
+      if os.path.isfile(path):
+        safe_mkdir(os.path.dirname(write_path))
+        shutil.copyfile(path, write_path)
+      else:
+        shutil.copytree(path, write_path)
+      return write_path
+
+    create_file('README', 'N.B. This is just a test tree.')
+    create_file('pants.ini',
+      """
+      [GLOBAL]
+      pythonpath: [
+          "{0}/contrib/go/src/python",
+          "{0}/pants-plugins/src/python"
+        ]
+      backend_packages: +[
+          "internal_backend.utilities",
+          "pants.contrib.go"
+        ]
+      """.format(get_buildroot())
+    )
+    copy_into('.gitignore')
 
     with initialize_repo(worktree=worktree, gitdir=os.path.join(worktree, '.git')) as git:
-      # Resource File
-      resource_file = os.path.join(worktree, 'src/resources/org/pantsbuild/resourceonly/README.md')
-      with safe_open(resource_file, 'w') as fp:
-        fp.write('Just resource.')
-
-      resource_build_file = os.path.join(worktree, 'src/resources/org/pantsbuild/resourceonly/BUILD')
-      with safe_open(resource_build_file, 'w') as fp:
-        fp.write(dedent("""
-        resources(
-          name='resource',
-          sources=['README.md'],
+      def add_to_git(commit_msg, *files):
+        git.add(*files)
+        git.commit(commit_msg)
+
+      add_to_git('a go target with default sources',
+        create_file('src/go/tester/BUILD', 'go_binary()'),
+        create_file('src/go/tester/main.go',
+          """
+          package main
+          import "fmt"
+          func main() {
+            fmt.Println("hello, world")
+          }
+          """
         )
-        """))
-
-      git.add(resource_file, resource_build_file)
-      git.commit('Check in a resource target.')
+      )
 
-      # Java Program
-      src_file = os.path.join(worktree, 'src/java/org/pantsbuild/helloworld/helloworld.java')
-      with safe_open(src_file, 'w') as fp:
-        fp.write(dedent("""
-        package org.pantsbuild.helloworld;
+      add_to_git('resource file',
+        create_file('src/resources/org/pantsbuild/resourceonly/BUILD',
+          """
+          resources(
+            name='resource',
+            sources=['README.md']
+          )
+          """
+        ),
+        create_file('src/resources/org/pantsbuild/resourceonly/README.md', 'Just a resource.')
+      )
 
-        class HelloWorld {
-          public static void main(String[] args) {
-            System.out.println("Hello, World!\n");
+      add_to_git('hello world java program with a dependency on a resource file',
+        create_file('src/java/org/pantsbuild/helloworld/BUILD',
+          """
+          jvm_binary(
+            dependencies=[
+              'src/resources/org/pantsbuild/resourceonly:resource',
+            ],
+            source='helloworld.java',
+            main='org.pantsbuild.helloworld.HelloWorld',
+          )
+          """
+        ),
+        create_file('src/java/org/pantsbuild/helloworld/helloworld.java',
+          """
+          package org.pantsbuild.helloworld;
+
+          class HelloWorld {
+            public static void main(String[] args) {
+              System.out.println("Hello, World!\n");
+            }
           }
-        }
-        """))
-
-      src_build_file = os.path.join(worktree, 'src/java/org/pantsbuild/helloworld/BUILD')
-      with safe_open(src_build_file, 'w') as fp:
-        fp.write(dedent("""
-        jvm_binary(
-          dependencies=[
-            '{}',
-          ],
-          source='helloworld.java',
-          main='org.pantsbuild.helloworld.HelloWorld',
+          """
         )
-        """.format('src/resources/org/pantsbuild/resourceonly:resource')))
-
-      git.add(src_file, src_build_file)
-      git.commit('hello world java program with a dependency on a resource file.')
-
-      # Scala Program
-      scala_src_dir = os.path.join(worktree, 'tests/scala/org/pantsbuild/cp-directories')
-      safe_mkdir(os.path.dirname(scala_src_dir))
-      shutil.copytree('testprojects/tests/scala/org/pantsbuild/testproject/cp-directories', scala_src_dir)
-      git.add(scala_src_dir)
-      git.commit('Check in a scala test target.')
-
-      # Python library and binary
-      python_src_dir = os.path.join(worktree, 'src/python/python_targets')
-      safe_mkdir(os.path.dirname(python_src_dir))
-      shutil.copytree('testprojects/src/python/python_targets', python_src_dir)
-      git.add(python_src_dir)
-      git.commit('Check in python targets.')
-
-      # A `python_library` with `resources=['file.name']`.
-      python_src_dir = os.path.join(worktree, 'src/python/sources')
-      safe_mkdir(os.path.dirname(python_src_dir))
-      shutil.copytree('testprojects/src/python/sources', python_src_dir)
-      git.add(python_src_dir)
-      git.commit('Check in a python library with resource dependency.')
-
-      # Copy 3rdparty/BUILD.
-      _3rdparty_build = os.path.join(worktree, '3rdparty/BUILD')
-      safe_mkdir(os.path.dirname(_3rdparty_build))
-      shutil.copyfile('3rdparty/BUILD', _3rdparty_build)
-      git.add(_3rdparty_build)
-      git.commit('Check in 3rdparty/BUILD.')
+      )
+
+      add_to_git('scala test target',
+        copy_into(
+          'testprojects/tests/scala/org/pantsbuild/testproject/cp-directories',
+          'tests/scala/org/pantsbuild/cp-directories'
+        )
+      )
+
+      add_to_git('python targets',
+        copy_into('testprojects/src/python/python_targets', 'src/python/python_targets')
+      )
+
+      add_to_git('a python_library with resources=["filename"]',
+        copy_into('testprojects/src/python/sources', 'src/python/sources')
+      )
+
+      add_to_git('3rdparty/BUILD', copy_into('3rdparty/BUILD'))
 
       with environment_as(PANTS_BUILDROOT_OVERRIDE=worktree):
         yield worktree
@@ -214,6 +236,12 @@ class ChangedIntegrationTest(PantsRunIntegrationTest, TestGenerator):
       direct=['tests/scala/org/pantsbuild/cp-directories:cp-directories'],
       transitive=['tests/scala/org/pantsbuild/cp-directories:cp-directories']
     ),
+    # A `go_binary` with default sources.
+    'src/go/tester/main.go': dict(
+      none=['src/go/tester:tester'],
+      direct=['src/go/tester:tester'],
+      transitive=['src/go/tester:tester']
+    ),
     # An unclaimed source file.
     'src/python/python_targets/test_unclaimed_src.py': dict(
       none=[],