Skip to content

Commit b75823d

Browse files
bazel-ioPagten
andauthored
[9.0.0] Support checking out the repo's default branch in git_repository/new_git_repository rule (#27701)
The `git_repository` and `new_git_repository` rules currently require not only the remote repository URI to be specified but also either the branch, tag or revision (commit) to check out. This PR removes the latter requirement. If no branch, tag or revision are specified, the repo's default branch will be checked out. The main reason for introducing this proposed change, is because I noticed certain Bazel rules already generate `git_repository` targets from git URIs or other git repo specs that might not have a branch, tag or revision specified. These rules then typically default to a branch name of `master`, which is not correct in general. This change will allow those rules to simply omit the branch, tag and revision from the generated `git_repository` targets, to check out the repo's default branch. An alternative, more explicit, interface for specifying that the default branch is to be checked out, would have been to add an optional boolean `default_branch` attribute to the `git_repository` and `new_git_repository` rules. The presence of that attribute would be mutually exclusive with the presence of `branch`, `tag` and `commit`. Let me know if that interface is preferable. Addresses issue #27610. Closes #27611. PiperOrigin-RevId: 833710273 Change-Id: I7bc18efcbcfcaba61bf27052fecceb50336d2eb3 Commit ee3af97 Co-authored-by: Pieter Agten <pieter.agten@gmail.com>
1 parent 6909a69 commit b75823d

File tree

4 files changed

+66
-43
lines changed

4 files changed

+66
-43
lines changed

src/test/java/com/google/devtools/build/lib/blackbox/tests/workspace/GitRepositoryBlackBoxTest.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@
3838
* classes.
3939
*
4040
* <p>1. We are creating some git repository with the preset contents, which will be used for
41-
* fetching contents for the test. We plan to fetch contents specifying either commit hash, tag, or
42-
* branch. For all test variants, we are creating the same repository, as the same HEAD commit is
43-
* marked with a tag, and can be addressed with commit hash, main branch, and tag name.
41+
* fetching contents for the test. We plan to fetch contents specifying either commit hash, tag,
42+
* specific branch or default branch. For all test variants, we are creating the same repository, as
43+
* the same HEAD commit is marked with a tag, and can be addressed with commit hash, main branch,
44+
* and tag name.
4445
*
4546
* <p>2. The contents of the git repository working tree is generated by {@link
4647
* RepoWithRuleWritingTextGenerator}. We pass some certain text to that generator; that exact text
@@ -152,6 +153,38 @@ public void testCloneAtMain() throws Exception {
152153
WorkspaceTestUtils.assertLinesExactly(outPath, HELLO_FROM_EXTERNAL_REPOSITORY);
153154
}
154155

156+
/**
157+
* Tests usage of new_git_repository workspace rule without a "tag", "commit" or "branch"
158+
* attribute, which means the repository's default branch is to be checked out. Please see the
159+
* general approach description in the class javadoc comment.
160+
*/
161+
@Test
162+
public void testCloneAtDefaultBranch() throws Exception {
163+
Path repo = context().getTmpDir().resolve("ext_repo");
164+
setupGitRepository(context(), repo);
165+
166+
String buildFileContent =
167+
String.format(
168+
"%s\n%s",
169+
loadRule(""), callRule("call_write_text", "out.txt", HELLO_FROM_EXTERNAL_REPOSITORY));
170+
context()
171+
.write(
172+
"MODULE.bazel",
173+
"new_git_repository = use_repo_rule(\"@bazel_tools//tools/build_defs/repo:git.bzl\","
174+
+ " \"new_git_repository\")",
175+
"new_git_repository(",
176+
" name='ext',",
177+
String.format(" remote='%s',", PathUtils.pathToFileURI(repo.resolve(".git"))),
178+
String.format(" build_file_content=\"\"\"%s\"\"\",", buildFileContent),
179+
")");
180+
181+
// This creates Bazel without MSYS, see implementation for details.
182+
BuilderRunner bazel = WorkspaceTestUtils.bazel(context());
183+
bazel.build("@ext//:call_write_text");
184+
Path outPath = context().resolveBinPath(bazel, "external/+new_git_repository+ext/out.txt");
185+
WorkspaceTestUtils.assertLinesExactly(outPath, HELLO_FROM_EXTERNAL_REPOSITORY);
186+
}
187+
155188
/**
156189
* Tests usage of git_repository workspace rule in the particular use case, when only the commit
157190
* hash is specified, and the commit is not in the HEAD-reachable subtree, on a separate branch.

src/test/shell/bazel/starlark_git_repository_test.sh

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ function test_new_git_repository_with_build_file_strip_prefix() {
181181
do_new_git_repository_test "3-subdir-bare" "build_file" "pluto"
182182
}
183183

184+
function test_new_git_repository_with_build_file_strip_prefix_default_branch() {
185+
do_new_git_repository_test "" "build_file" "pluto"
186+
}
187+
184188
function test_new_git_repository_with_build_file_content() {
185189
do_new_git_repository_test "0-initial" "build_file_content"
186190
}
@@ -189,6 +193,10 @@ function test_new_git_repository_with_build_file_content_strip_prefix() {
189193
do_new_git_repository_test "3-subdir-bare" "build_file_content" "pluto"
190194
}
191195

196+
function test_new_git_repository_with_build_file_content_strip_prefix_default_branch() {
197+
do_new_git_repository_test "" "build_file_content" "pluto"
198+
}
199+
192200
# Test cloning a Git repository using the new_git_repository rule.
193201
#
194202
# This test uses the pluto Git repository at tag 0-initial, which contains the
@@ -203,6 +211,9 @@ function test_new_git_repository_with_build_file_content_strip_prefix() {
203211
# pluto/
204212
# info
205213
#
214+
# Finally, it uses the pluto Git repository at the default branch, which is the
215+
# master branch, which is at the same revision as the 3-subdir-bare tag.
216+
#
206217
# Set up workspace with the following files:
207218
#
208219
# $WORKSPACE_DIR/
@@ -217,17 +228,19 @@ function test_new_git_repository_with_build_file_content_strip_prefix() {
217228
function do_new_git_repository_test() {
218229
local pluto_repo_dir=$(get_pluto_repo)
219230
local strip_prefix=""
231+
local tag=""
220232
[ $# -eq 3 ] && strip_prefix="strip_prefix=\"$3\","
233+
[ "$1" != "" ] && tag="tag = \"$1\","
221234

222235
# Create a workspace that clones the repository at the first commit.
223236

224-
if [ "$2" == "build_file" ] ; then
237+
if [ "$2" == "build_file" ]; then
225238
cat >> MODULE.bazel <<EOF
226239
new_git_repository = use_repo_rule('@bazel_tools//tools/build_defs/repo:git.bzl', 'new_git_repository')
227240
new_git_repository(
228241
name = "pluto",
229242
remote = "$pluto_repo_dir",
230-
tag = "$1",
243+
$tag
231244
build_file = "//:pluto.BUILD",
232245
$strip_prefix
233246
)
@@ -249,7 +262,7 @@ new_git_repository = use_repo_rule('@bazel_tools//tools/build_defs/repo:git.bzl'
249262
new_git_repository(
250263
name = "pluto",
251264
remote = "$pluto_repo_dir",
252-
tag = "$1",
265+
$tag
253266
$strip_prefix
254267
build_file_content = """
255268
filegroup(
@@ -626,33 +639,7 @@ EOF
626639

627640
bazel fetch //planets:planet-info >& $TEST_log \
628641
|| echo "Expect run to fail."
629-
expect_log "Exactly one of commit"
630-
}
631-
632-
# Verifies that rule fails if neither tag or commit are set.
633-
#
634-
# This test uses the pluto Git repository at tag 1-build, which contains the
635-
# following files:
636-
#
637-
# pluto/
638-
# MODULE.bazel
639-
# BUILD
640-
# info
641-
function test_git_repository_no_commit_tag_error() {
642-
setup_error_test
643-
local pluto_repo_dir=$(get_pluto_repo)
644-
645-
cat >> MODULE.bazel <<EOF
646-
git_repository = use_repo_rule('@bazel_tools//tools/build_defs/repo:git.bzl', 'git_repository')
647-
git_repository(
648-
name = "pluto",
649-
remote = "$pluto_repo_dir",
650-
)
651-
EOF
652-
653-
bazel fetch //planets:planet-info >& $TEST_log \
654-
|| echo "Expect run to fail."
655-
expect_log "Exactly one of commit"
642+
expect_log "At most one of commit"
656643
}
657644

658645
# Verifies that if a non-existent subdirectory is supplied, then strip_prefix

tools/build_defs/repo/git.bzl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ load(
3030
)
3131

3232
def _clone_or_update_repo(ctx):
33-
if ((not ctx.attr.tag and not ctx.attr.commit and not ctx.attr.branch) or
34-
(ctx.attr.tag and ctx.attr.commit) or
33+
if ((ctx.attr.tag and ctx.attr.commit) or
3534
(ctx.attr.tag and ctx.attr.branch) or
3635
(ctx.attr.commit and ctx.attr.branch)):
37-
fail("Exactly one of commit, tag, or branch must be provided")
36+
fail("At most one of commit, tag, or branch may be provided")
3837

3938
root = ctx.path(".")
4039
directory = str(root)
@@ -225,11 +224,12 @@ git_repository = repository_rule(
225224
attrs = _common_attrs,
226225
doc = """Clone an external git repository.
227226
228-
Clones a Git repository, checks out the specified tag, or commit, and
229-
makes its targets available for binding. Also determine the id of the
230-
commit actually checked out and its date, and return a dict with parameters
231-
that provide a reproducible version of this rule (which a tag not necessarily
232-
is).
227+
Clones a Git repository, checks out the specified branch, tag, or commit, and
228+
makes its targets available for binding. If no branch, tag or commit is
229+
specified, check out the repository's default branch. Also determine the id
230+
and date of the commit that was checked out, and return a dict with
231+
parameters that provide a reproducible version of this rule (which a tag or
232+
branch not necessarily is).
233233
234234
Bazel will first try to perform a shallow fetch of only the specified commit.
235235
If that fails (usually due to missing server support), it will fall back to a

tools/build_defs/repo/git_worker.bzl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ _GitRepoInfo = provider(
2727
"directory": "Working directory path",
2828
"shallow": "Defines the depth of a fetch. Either empty, --depth=1, or --shallow-since=<>",
2929
"reset_ref": """Reference to use for resetting the git repository.
30-
Either commit hash, tag or branch.""",
30+
Either commit hash, tag, branch name, or default branch.""",
3131
"fetch_ref": """Reference for fetching.
32-
Either commit hash, tag or branch.""",
32+
Either commit hash, tag, branch name, or default branch.""",
3333
"remote": "URL of the git repository to fetch from.",
3434
"init_submodules": """If True, submodules update command will be called after fetching
3535
and resetting to the specified reference.""",
@@ -75,6 +75,9 @@ def git_repo(ctx, directory):
7575
elif ctx.attr.branch:
7676
reset_ref = "origin/" + ctx.attr.branch
7777
fetch_ref = ctx.attr.branch + ":origin/" + ctx.attr.branch
78+
else:
79+
reset_ref = "origin/HEAD"
80+
fetch_ref = "HEAD:refs/remotes/origin/HEAD"
7881

7982
git_repo = _GitRepoInfo(
8083
directory = ctx.path(directory),

0 commit comments

Comments
 (0)