Add the gazelle plugin to the distribution (#400)

* Add the gazelle plugin to the distribution

To avoid everyone needing to take a dep on `rules_go`, we
do the following:

1. Regular Bazel users need to load `bazel_skylib_gazelle_plugin_workspace`
   and call that, and then `bazel_skylib_gazelle_plugin_setup`

2. `bzlmod` users need do nothing, but we now include the
   `rules_go` dep in the `MODULE.bazel` shipped in the release.
    This is fine, because `bzlmod` will lazily load
    dependencies.

* Run buildifier

* Add docstring to `gazelle_setup.bzl`

* Move "internal only" marker

* Make @com_github_bazelbuild_buildtools visible in the deployed module

* Respond to review comments

* Move plugin to a nested workspace

* Run buildifier

* Restore the module declaration from `main`

* Bump versions of rules_go and gazelle used in the top-level module to match the ones in gazelle

* Respond to review comments and add gazelle to ignored directories so //... works as expected

* Add missing descriptor for stardoc

* Move gazelle hints into workspace files
diff --git a/.bazelignore b/.bazelignore
new file mode 100644
index 0000000..dbff643
--- /dev/null
+++ b/.bazelignore
@@ -0,0 +1 @@
+gazelle/
diff --git a/MODULE.bazel b/MODULE.bazel
index 64ce586..81b8b5c 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -1,6 +1,7 @@
 module(
     name = "bazel_skylib",
     compatibility_level = 1,
+    # If you change this, please also update @bazel_skylib_gazelle_plugin//:MODULE.bazel
     version = "1.3.0",
 )
 
@@ -13,21 +14,7 @@
 
 ### INTERNAL ONLY - lines after this are not included in the release packaging.
 
-# Gazelle extension is experimental
-bazel_dep(name = "rules_go", repo_name = "io_bazel_rules_go", version = "0.33.0")
-bazel_dep(name = "gazelle", repo_name = "bazel_gazelle", version = "0.26.0")
-
-go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
-
-go_deps.module(
-    path = "github.com/bazelbuild/buildtools",
-    sum = "h1:fmdo+fvvWlhldUcqkhAMpKndSxMN3vH5l7yow5cEaiQ=",
-    version = "v0.0.0-20220531122519-a43aed7014c8",
-)
-
-use_repo(go_deps, "com_github_bazelbuild_buildtools")
-
 # Build-only / test-only dependencies
 bazel_dep(name = "stardoc", dev_dependency = True, repo_name = "io_bazel_stardoc", version = "0.5.3")
 bazel_dep(name = "rules_pkg", dev_dependency = True, version = "0.5.1")
-bazel_dep(name = "rules_cc", dev_dependency = True, version = "0.0.1")
+bazel_dep(name = "rules_cc", dev_dependency = True, version = "0.0.2")
diff --git a/README.md b/README.md
index ce70bab..1954aa3 100644
--- a/README.md
+++ b/README.md
@@ -132,3 +132,38 @@
 
 See the [maintaner's guide](docs/maintainers_guide.md) for instructions for
 cutting a new release.
+
+## Gazelle Plugin
+
+`bazel_skylib` ships with a [gazelle](https://github.com/bazelbuild/bazel-gazelle)
+plugin to generate `bzl_library` entries in build files. To use this, in your
+`WORKSPACE`:
+
+```starlark
+load("@bazel_skylib_gazelle_plugin//:workspace.bzl", "bazel_skylib_gazelle_plugin_workspace")
+
+bazel_skylib_gazelle_plugin_workspace()
+
+load("@bazel_skylib_gazelle_plugin//:setup.bzl", "bazel_skylib_gazelle_plugin_setup"
+
+bazel_skylib_gazelle_plugin_setup()
+```
+
+You may then include the plugin using code similar to this in your `BUILD.bazel`
+file:
+
+```starlark
+load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle", "gazelle_binary")
+
+gazelle(
+    name = "gazelle",
+    gazelle = ":gazelle_bin",
+)
+
+gazelle_binary(
+    name = "gazelle_bin",
+    languages = DEFAULT_LANGUAGES + [
+        "@bazel_skylib_gazelle_plugin//gazelle/bzl",
+    ],
+)
+```
diff --git a/WORKSPACE b/WORKSPACE
index 3876987..a9c182a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -2,22 +2,22 @@
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+load(":workspace.bzl", "bazel_skylib_workspace")
 
-maybe(
-    name = "io_bazel_rules_go",
-    repo_rule = http_archive,
-    sha256 = "685052b498b6ddfe562ca7a97736741d87916fe536623afb7da2824c0211c369",
-    urls = [
-        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip",
-        "https://github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip",
-    ],
+bazel_skylib_workspace()
+
+local_repository(
+    name = "bazel_skylib_gazelle_plugin",
+    path = "gazelle",
 )
 
-load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
+load("@bazel_skylib_gazelle_plugin//:workspace.bzl", "bazel_skylib_gazelle_plugin_workspace")
 
-go_rules_dependencies()
+bazel_skylib_gazelle_plugin_workspace()
 
-go_register_toolchains(version = "1.17.1")
+load("@bazel_skylib_gazelle_plugin//:setup.bzl", "bazel_skylib_gazelle_plugin_setup")
+
+bazel_skylib_gazelle_plugin_setup()
 
 # Below this line is for documentation generation only,
 # and should thus not be included by dependencies on
@@ -64,22 +64,3 @@
 load("//lib:unittest.bzl", "register_unittest_toolchains")
 
 register_unittest_toolchains()
-
-# Provide a repository hint for Gazelle to inform it that the go package
-# github.com/bazelbuild/rules_go is available from io_bazel_rules_go and it
-# doesn't need to duplicatively fetch it.
-# gazelle:repository go_repository name=io_bazel_rules_go importpath=github.com/bazelbuild/rules_go
-http_archive(
-    name = "bazel_gazelle",
-    sha256 = "de69a09dc70417580aabf20a28619bb3ef60d038470c7cf8442fafcf627c21cb",
-    urls = [
-        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz",
-        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz",
-    ],
-)
-# Another Gazelle repository hint.
-# gazelle:repository go_repository name=bazel_gazelle importpath=github.com/bazelbuild/bazel-gazelle/testtools
-
-load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
-
-gazelle_dependencies()
diff --git a/gazelle/BUILD b/gazelle/BUILD
new file mode 100644
index 0000000..2259933
--- /dev/null
+++ b/gazelle/BUILD
@@ -0,0 +1,34 @@
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+# The files needed for distribution
+filegroup(
+    name = "distribution",
+    srcs = glob(
+        ["*"],
+        allow_empty = True,
+    ),
+    visibility = [
+        "//:__pkg__",
+    ],
+)
+
+bzl_library(
+    name = "setup",
+    srcs = ["setup.bzl"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@bazel_gazelle//:deps",
+        "@io_bazel_rules_go//go:deps",
+    ],
+)
+
+bzl_library(
+    name = "workspace",
+    srcs = ["workspace.bzl"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@bazel_skylib//:workspace",
+        "@bazel_tools//tools/build_defs/repo:http.bzl",
+        "@bazel_tools//tools/build_defs/repo:utils.bzl",
+    ],
+)
diff --git a/gazelle/MODULE.bazel b/gazelle/MODULE.bazel
new file mode 100644
index 0000000..d997651
--- /dev/null
+++ b/gazelle/MODULE.bazel
@@ -0,0 +1,31 @@
+module(
+    name = "bazel_skylib_gazelle_plugin",
+    compatibility_level = 1,
+    # If you change this, please also update @bazel_gazelle//:MODULE.bazel
+    version = "1.3.0",
+)
+
+bazel_dep(name = "bazel_skylib", version = "1.3.0")
+bazel_dep(name = "gazelle", repo_name = "bazel_gazelle", version = "0.28.0")
+bazel_dep(name = "rules_go", repo_name = "io_bazel_rules_go", version = "0.35.0")
+
+go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")
+
+go_sdk.download(
+    name = "go_sdk",
+    version = "1.18",
+)
+
+use_repo(go_sdk, "go_sdk")
+
+register_toolchains("@go_sdk//:all")
+
+go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
+
+go_deps.module(
+    path = "github.com/bazelbuild/buildtools",
+    sum = "h1:fmdo+fvvWlhldUcqkhAMpKndSxMN3vH5l7yow5cEaiQ=",
+    version = "v0.0.0-20220531122519-a43aed7014c8",
+)
+
+use_repo(go_deps, "com_github_bazelbuild_buildtools")
diff --git a/gazelle/WORKSPACE b/gazelle/WORKSPACE
new file mode 100644
index 0000000..cc0217d
--- /dev/null
+++ b/gazelle/WORKSPACE
@@ -0,0 +1,25 @@
+workspace(name = "bazel_skylib_gazelle_plugin")
+
+local_repository(
+    name = "bazel_skylib",
+    path = "..",
+)
+
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+
+bazel_skylib_workspace()
+
+load(":workspace.bzl", "bazel_skylib_gazelle_plugin_workspace")
+
+bazel_skylib_gazelle_plugin_workspace()
+
+load(":setup.bzl", "bazel_skylib_gazelle_plugin_setup")
+
+bazel_skylib_gazelle_plugin_setup()
+
+# Provide a repository hint for Gazelle to inform it that the go package
+# github.com/bazelbuild/rules_go is available from io_bazel_rules_go and it
+# doesn't need to duplicatively fetch it.
+# gazelle:repository go_repository name=io_bazel_rules_go importpath=github.com/bazelbuild/rules_go
+# Another Gazelle repository hint.
+# gazelle:repository go_repository name=bazel_gazelle importpath=github.com/bazelbuild/bazel-gazelle/testtools
diff --git a/gazelle/WORKSPACE.bzlmod b/gazelle/WORKSPACE.bzlmod
new file mode 100644
index 0000000..621db93
--- /dev/null
+++ b/gazelle/WORKSPACE.bzlmod
@@ -0,0 +1,8 @@
+workspace(name = "bazel_skylib_gazelle_plugin")
+
+# Provide a repository hint for Gazelle to inform it that the go package
+# github.com/bazelbuild/rules_go is available from io_bazel_rules_go and it
+# doesn't need to duplicatively fetch it.
+# gazelle:repository go_repository name=io_bazel_rules_go importpath=github.com/bazelbuild/rules_go
+# Another Gazelle repository hint.
+# gazelle:repository go_repository name=bazel_gazelle importpath=github.com/bazelbuild/bazel-gazelle/testtools
diff --git a/gazelle/bzl/BUILD b/gazelle/bzl/BUILD
index 29caeb0..dca6b61 100644
--- a/gazelle/bzl/BUILD
+++ b/gazelle/bzl/BUILD
@@ -51,3 +51,25 @@
     name = "gazelle",
     gazelle = ":gazelle-skylib",
 )
+
+# The files needed for distribution
+# A fake testdata directory is created so that
+# the build file has nothing missing, but we
+# do not bloat the distribution tarball
+filegroup(
+    name = "distribution",
+    srcs = glob(["*.go"]) + [
+        "BUILD",
+        ":fake-testdata",
+    ],
+    visibility = [
+        "//:__pkg__",
+        "//distribution:__pkg__",
+    ],
+)
+
+genrule(
+    name = "fake-testdata",
+    outs = ["testdata"],
+    cmd = "touch $@",
+)
diff --git a/gazelle/bzl/gazelle_test.go b/gazelle/bzl/gazelle_test.go
index e4f59e8..1554337 100644
--- a/gazelle/bzl/gazelle_test.go
+++ b/gazelle/bzl/gazelle_test.go
@@ -29,7 +29,7 @@
 
 var gazellePath = findGazelle()
 
-const testDataPath = "gazelle/bzl/testdata/"
+const testDataPath = "bzl/testdata/"
 
 // TestGazelleBinary runs a gazelle binary with starlib installed on each
 // directory in `testdata/*`. Please see `testdata/README.md` for more
@@ -135,7 +135,7 @@
 }
 
 func findGazelle() string {
-	gazellePath, ok := bazel.FindBinary("gazelle/bzl", "gazelle-skylib")
+	gazellePath, ok := bazel.FindBinary("bzl", "gazelle-skylib")
 	if !ok {
 		panic("could not find gazelle binary")
 	}
diff --git a/gazelle/setup.bzl b/gazelle/setup.bzl
new file mode 100644
index 0000000..b70c64c
--- /dev/null
+++ b/gazelle/setup.bzl
@@ -0,0 +1,32 @@
+# Copyright 2019 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Dependency registration helpers for the gazelle plugin."""
+
+load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
+load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
+
+def bazel_skylib_gazelle_plugin_setup(go_version = "1.18.7", register_go_toolchains = True):
+    """Set up the dependencies needed by the Gazelle plugin.
+
+    Args:
+      go_version: The version of Go registered as part of the build as a string
+      register_go_toolchains: A boolean indicating whether or not to register the Go toolchains. Defaults to `True`
+    """
+    go_rules_dependencies()
+
+    if register_go_toolchains:
+        go_register_toolchains(version = go_version)
+
+    gazelle_dependencies()
diff --git a/gazelle/workspace.bzl b/gazelle/workspace.bzl
new file mode 100644
index 0000000..91400b3
--- /dev/null
+++ b/gazelle/workspace.bzl
@@ -0,0 +1,43 @@
+# Copyright 2019 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Dependency registration helpers for repositories which need to load bazel-skylib's gazelle plugin."""
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+
+def bazel_skylib_gazelle_plugin_workspace():
+    """Loads dependencies required to use skylib's gazelle plugin"""
+    bazel_skylib_workspace()
+
+    maybe(
+        http_archive,
+        name = "io_bazel_rules_go",
+        sha256 = "099a9fb96a376ccbbb7d291ed4ecbdfd42f6bc822ab77ae6f1b5cb9e914e94fa",
+        urls = [
+            "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
+            "https://github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
+        ],
+    )
+
+    maybe(
+        http_archive,
+        name = "bazel_gazelle",
+        sha256 = "448e37e0dbf61d6fa8f00aaa12d191745e14f07c31cabfa731f0c8e8a4f41b97",
+        urls = [
+            "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.28.0/bazel-gazelle-v0.28.0.tar.gz",
+            "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.28.0/bazel-gazelle-v0.28.0.tar.gz",
+        ],
+    )