Merge branch 'stable-3.1'

* stable-3.1:
  Replace documentation of gerrit.ui with gerrit.enableGwtUi
  Use the environment variables provided by the GerritCodeReview-plugin
  DeleteZombieCommentsRefsTest: Open RevWalk in try-with-resource
  Documentation: Mention unused_deps with buildifier
  Bazel: Remove bazel version check
  Documentation: Recommend Bazelisk to launch bazel
  Add a pgm to delete dead draft comments refs

Change-Id: I78758c7168b7374b491413dcc7f130df3d9dfd58
This commit is contained in:
David Pursehouse 2020-01-29 18:02:53 +09:00
commit bfe2d146e1
9 changed files with 479 additions and 74 deletions

View File

@ -22,12 +22,22 @@ To build Gerrit from source, you need:
* Python 2 or 3
* link:https://github.com/nodesource/distributions/blob/master/README.md[Node.js (including npm),role=external,window=_blank]
* Bower (`sudo npm install -g bower`)
* link:https://docs.bazel.build/versions/master/install.html[Bazel,role=external,window=_blank] directly
or through link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank]
* link:https://docs.bazel.build/versions/master/install.html[Bazel,role=external,window=_blank] -launched with
link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank]
* Maven
* zip, unzip
* gcc
[[bazel]]
=== Bazel
link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank] includes a
link:https://bazel.build/[Bazel,role=external,window=_blank] version check and downloads the correct
`bazel` version for the git project/repository. Bazelisk is the recommended
`bazel` launcher for Gerrit. Once Bazelisk is installed locally, a `bazel`
symlink can be created towards it. This is so that every `bazel` command
seamlessly uses Bazelisk, which then runs the proper `bazel` binary version.
[[java]]
=== Java

View File

@ -116,7 +116,10 @@ To format Java source code, Gerrit uses the
link:https://github.com/google/google-java-format[`google-java-format`,role=external,window=_blank]
tool (version 1.7), and to format Bazel BUILD, WORKSPACE and .bzl files the
link:https://github.com/bazelbuild/buildtools/tree/master/buildifier[`buildifier`,role=external,window=_blank]
tool (version 0.29.0).
tool (version 0.29.0). Unused dependencies are found and removed using the
link:https://github.com/bazelbuild/buildtools/tree/master/unused_deps[`unused_deps`,role=external,window=_blank]
build tool, a sibling of `buildifier`.
These tools automatically apply format according to the style guides; this
streamlines code review by reducing the need for time-consuming, tedious,
and contentious discussions about trivial issues like whitespace.

View File

@ -2,7 +2,7 @@
= Gerrit Code Review: Developer Setup
To build a developer instance, you'll need link:https://bazel.build/[Bazel,role=external,window=_blank] to
compile the code.
compile the code, preferably launched with link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank].
== Git Setup

44
Jenkinsfile vendored
View File

@ -25,15 +25,6 @@ class Globals {
static final String gerritRepositoryNameSha1Suffix = "-a6a0e4682515f3521897c5f950d1394f4619d928"
}
class Change {
static String sha1 = ""
static String number = ""
static String branch = ""
static String ref = ""
static String patchNum = ""
static String url = ""
}
class Build {
String url
String result
@ -83,36 +74,17 @@ def postCheck(check) {
gerritCheck(checks: [ "${check.uuid}" : "${check.getCheckResultFromBuild()}" ], url: "${check.consoleUrl}")
}
def queryChangedFiles(url, changeNum, sha1) {
def queryUrl = "${url}changes/${Change.number}/revisions/${Change.sha1}/files/"
def queryChangedFiles(url) {
def queryUrl = "${url}changes/${env.GERRIT_CHANGE_NUMBER}/revisions/${env.GERRIT_PATCHSET_REVISION}/files/"
def response = httpRequest queryUrl
def files = response.getContent().substring(5)
def filesJson = new JsonSlurper().parseText(files)
return filesJson.keySet().findAll { it != "/COMMIT_MSG" }
}
def queryChange(){
def requestedChangeId = env.BRANCH_NAME.split('/')[1]
def queryUrl = "${Globals.gerritUrl}changes/${requestedChangeId}/?pp=0&O=3"
def response = httpRequest queryUrl
def jsonSlurper = new JsonSlurper()
return jsonSlurper.parseText(response.getContent().substring(5))
}
def getChangeMetaData(){
def changeJson = queryChange()
Change.sha1 = changeJson.current_revision
Change.number = changeJson._number
Change.branch = changeJson.branch
def revision = changeJson.revisions.get(Change.sha1)
Change.ref = revision.ref
Change.patchNum = revision._number
Change.url = Globals.gerritUrl + "#/c/" + Change.number + "/" + Change.patchNum
}
def collectBuildModes() {
Builds.modes = ["notedb"]
def changedFiles = queryChangedFiles(Globals.gerritUrl, Change.number, Change.sha1)
def changedFiles = queryChangedFiles(Globals.gerritUrl)
def polygerritFiles = changedFiles.findAll { it.startsWith("polygerrit-ui") ||
it.startsWith("lib/js") }
@ -137,11 +109,11 @@ def prepareBuildsForMode(buildName, mode="notedb", retryTimes = 1) {
for (int i = 1; i <= retryTimes; i++) {
try {
slaveBuild = build job: "${buildName}", parameters: [
string(name: 'REFSPEC', value: Change.ref),
string(name: 'BRANCH', value: Change.sha1),
string(name: 'CHANGE_URL', value: Change.url),
string(name: 'REFSPEC', value: "refs/changes/${env.BRANCH_NAME}"),
string(name: 'BRANCH', value: env.GERRIT_PATCHSET_REVISION),
string(name: 'CHANGE_URL', value: "${Globals.gerritUrl}c/${env.GERRIT_PROJECT}/+/${env.GERRIT_CHANGE_NUMBER}"),
string(name: 'MODE', value: mode),
string(name: 'TARGET_BRANCH', value: Change.branch)
string(name: 'TARGET_BRANCH', value: env.GERRIT_BRANCH)
], propagate: false
} finally {
if (buildName == "Gerrit-codestyle"){
@ -243,8 +215,6 @@ node ('master') {
if (hasChangeNumber()) {
stage('Preparing'){
gerritReview labels: ['Verified': 0, 'Code-Style': 0]
getChangeMetaData()
collectBuildModes()
}
}

View File

@ -23,13 +23,6 @@ load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig")
# otherwise refer to RBE docs.
rbe_autoconfig(name = "rbe_default")
http_archive(
name = "bazel_skylib",
sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a",
strip_prefix = "bazel-skylib-0.8.0",
urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz"],
)
http_archive(
name = "io_bazel_rules_closure",
sha256 = "03c3b16f205085817fd89cfdcb2220a0138647ee7992be9cef291b069dd90301",
@ -47,15 +40,6 @@ http_file(
urls = ["https://raw.githubusercontent.com/google/closure-compiler/35d2b3340ff23a69441f10fa3bc820691c2942f2/contrib/externs/polymer-1.0.js"],
)
# Check Bazel version when invoked by Bazel directly
load("//tools/bzl:bazelisk_version.bzl", "bazelisk_version")
bazelisk_version(name = "bazelisk_version")
load("@bazelisk_version//:check.bzl", "check_bazel_version")
check_bazel_version()
load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies", "rules_closure_toolchains")
# Prevent redundant loading of dependencies.
@ -64,7 +48,6 @@ load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_depende
# https://github.com/google/closure-templates/pull/155
rules_closure_dependencies(
omit_aopalliance = True,
omit_bazel_skylib = True,
omit_javax_inject = True,
omit_rules_cc = True,
)

View File

@ -0,0 +1,78 @@
// Copyright (C) 2020 The Android Open Source Project
//
// 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.
package com.google.gerrit.pgm;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.notedb.DeleteZombieCommentsRefs;
import com.google.gerrit.server.notedb.DeleteZombieCommentsRefs.Factory;
import com.google.gerrit.server.schema.SchemaModule;
import com.google.gerrit.server.securestore.SecureStoreClassName;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.util.Providers;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.kohsuke.args4j.Option;
/**
* A pgm which can be used to clean zombie draft comments refs More context in
* https://gerrit-review.googlesource.com/c/gerrit/+/246233
*
* <p>The implementation is in {@link DeleteZombieCommentsRefs}
*/
public class DeleteZombieDrafts extends SiteProgram {
@Option(
name = "--cleanup-percentage",
aliases = {"-c"},
usage = "Clean a % of zombie drafts (default is 100%)")
private Integer cleanupPercentage = 100;
@Override
public int run() throws IOException {
mustHaveValidSite();
Injector sysInjector = getSysInjector();
DeleteZombieCommentsRefs cleanup =
sysInjector.getInstance(Factory.class).create(cleanupPercentage);
cleanup.execute();
return 0;
}
private Injector getSysInjector() {
List<Module> modules = new ArrayList<>();
modules.add(
new AbstractModule() {
@Override
protected void configure() {
bind(Path.class).annotatedWith(SitePath.class).toInstance(getSitePath());
bind(ConsoleUI.class).toInstance(ConsoleUI.getInstance(false));
bind(String.class)
.annotatedWith(SecureStoreClassName.class)
.toProvider(Providers.of(getConfiguredSecureStoreClass()));
install(new FactoryModuleBuilder().build(DeleteZombieCommentsRefs.Factory.class));
}
});
modules.add(new GerritServerConfigModule());
modules.add(new SchemaModule());
return Guice.createInjector(modules);
}
}

View File

@ -0,0 +1,130 @@
// Copyright (C) 2020 The Android Open Source Project
//
// 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.
package com.google.gerrit.server.notedb;
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.Iterables;
import com.google.gerrit.entities.Change;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceiveCommand;
/**
* This class can be used to clean zombie draft comments refs. More context in <a
* href="https://gerrit-review.googlesource.com/c/gerrit/+/246233">
* https://gerrit-review.googlesource.com/c/gerrit/+/246233 </a>
*
* <p>An earlier bug in the deletion of draft comments {@code
* refs/draft-comments/$change_id_short/$change_id/$user_id} caused some draft refs to remain in Git
* and not get deleted. These refs point to an empty tree.
*/
public class DeleteZombieCommentsRefs {
private final String EMPTY_TREE_ID = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
private final String DRAFT_REFS_PREFIX = "refs/draft-comments";
private final int CHUNK_SIZE = 100; // log progress after deleting every CHUNK_SIZE refs
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
private final int cleanupPercentage;
private Repository allUsersRepo;
public interface Factory {
DeleteZombieCommentsRefs create(int cleanupPercentage);
}
@Inject
public DeleteZombieCommentsRefs(
AllUsersName allUsers,
GitRepositoryManager repoManager,
@Assisted Integer cleanupPercentage) {
this.allUsers = allUsers;
this.repoManager = repoManager;
this.cleanupPercentage = (cleanupPercentage == null) ? 100 : cleanupPercentage;
}
public void execute() throws IOException {
allUsersRepo = repoManager.openRepository(allUsers);
List<Ref> draftRefs = allUsersRepo.getRefDatabase().getRefsByPrefix(DRAFT_REFS_PREFIX);
List<Ref> zombieRefs = filterZombieRefs(draftRefs);
System.out.println(
String.format(
"Found a total of %d zombie draft refs in %s repo.",
zombieRefs.size(), allUsers.get()));
System.out.println(String.format("Cleanup percentage = %d", cleanupPercentage));
zombieRefs =
zombieRefs.stream()
.filter(ref -> Change.Id.fromAllUsersRef(ref.getName()).get() % 100 < cleanupPercentage)
.collect(toImmutableList());
System.out.println(
String.format("Number of zombie refs to be cleaned = %d", zombieRefs.size()));
long zombieRefsCnt = zombieRefs.size();
long deletedRefsCnt = 0;
long startTime = System.currentTimeMillis();
for (List<Ref> refsBatch : Iterables.partition(zombieRefs, CHUNK_SIZE)) {
deleteBatchZombieRefs(refsBatch);
long elapsed = (System.currentTimeMillis() - startTime) / 1000;
deletedRefsCnt += refsBatch.size();
logProgress(deletedRefsCnt, zombieRefsCnt, elapsed);
}
}
private void deleteBatchZombieRefs(List<Ref> refsBatch) throws IOException {
List<ReceiveCommand> deleteCommands =
refsBatch.stream()
.map(
zombieRef ->
new ReceiveCommand(
zombieRef.getObjectId(), ObjectId.zeroId(), zombieRef.getName()))
.collect(toImmutableList());
BatchRefUpdate bru = allUsersRepo.getRefDatabase().newBatchUpdate();
bru.setAtomic(true);
bru.addCommand(deleteCommands);
RefUpdateUtil.executeChecked(bru, allUsersRepo);
}
private List<Ref> filterZombieRefs(List<Ref> allDraftRefs) throws IOException {
List<Ref> zombieRefs = new ArrayList<>((int) (allDraftRefs.size() * 0.5));
for (Ref ref : allDraftRefs) {
if (isZombieRef(ref)) {
zombieRefs.add(ref);
}
}
return zombieRefs;
}
private boolean isZombieRef(Ref ref) throws IOException {
return allUsersRepo.parseCommit(ref.getObjectId()).getTree().getName().equals(EMPTY_TREE_ID);
}
private void logProgress(long deletedRefsCount, long allRefsCount, long elapsed) {
System.out.format(
"Deleted %d/%d zombie draft refs (%d seconds)\n", deletedRefsCount, allRefsCount, elapsed);
}
}

View File

@ -0,0 +1,247 @@
// Copyright (C) 2020 The Android Open Source Project
//
// 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.
package com.google.gerrit.server.git;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.notedb.DeleteZombieCommentsRefs;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class DeleteZombieCommentsRefsTest {
private InMemoryRepositoryManager repoManager = new InMemoryRepositoryManager();
private Project.NameKey allUsersProject = Project.nameKey("All-Users");
@Test
public void cleanZombieDraftsSmall() throws Exception {
try (Repository usersRepo = repoManager.createRepository(allUsersProject)) {
Ref ref1 = createRefWithNonEmptyTreeCommit(usersRepo, 1, 1000001);
Ref ref2 = createRefWithEmptyTreeCommit(usersRepo, 1, 1000002);
DeleteZombieCommentsRefs clean =
new DeleteZombieCommentsRefs(new AllUsersName("All-Users"), repoManager, null);
clean.execute();
/* Check that ref1 still exists, and ref2 is deleted */
assertThat(usersRepo.exactRef(ref1.getName())).isNotNull();
assertThat(usersRepo.exactRef(ref2.getName())).isNull();
}
}
@Test
public void cleanZombieDraftsWithPercentage() throws Exception {
try (Repository usersRepo = repoManager.createRepository(allUsersProject)) {
Ref ref1 = createRefWithNonEmptyTreeCommit(usersRepo, 1005, 1000001);
Ref ref2 = createRefWithEmptyTreeCommit(usersRepo, 1006, 1000002);
Ref ref3 = createRefWithEmptyTreeCommit(usersRepo, 1060, 1000002);
assertThat(usersRepo.getRefDatabase().getRefs()).hasSize(3);
int cleanupPercentage = 50;
DeleteZombieCommentsRefs clean =
new DeleteZombieCommentsRefs(
new AllUsersName("All-Users"), repoManager, cleanupPercentage);
clean.execute();
/* ref1 not deleted, ref2 deleted, ref3 not deleted because of the clean percentage */
assertThat(usersRepo.getRefDatabase().getRefs()).hasSize(2);
assertThat(usersRepo.exactRef(ref1.getName())).isNotNull();
assertThat(usersRepo.exactRef(ref2.getName())).isNull();
assertThat(usersRepo.exactRef(ref3.getName())).isNotNull();
/* Re-execute the cleanup and make sure nothing's changed */
clean.execute();
assertThat(usersRepo.getRefDatabase().getRefs()).hasSize(2);
assertThat(usersRepo.exactRef(ref1.getName())).isNotNull();
assertThat(usersRepo.exactRef(ref2.getName())).isNull();
assertThat(usersRepo.exactRef(ref3.getName())).isNotNull();
/* Increase the cleanup percentage */
cleanupPercentage = 70;
clean =
new DeleteZombieCommentsRefs(
new AllUsersName("All-Users"), repoManager, cleanupPercentage);
clean.execute();
/* Now ref3 is deleted */
assertThat(usersRepo.getRefDatabase().getRefs()).hasSize(1);
assertThat(usersRepo.exactRef(ref1.getName())).isNotNull();
assertThat(usersRepo.exactRef(ref2.getName())).isNull();
assertThat(usersRepo.exactRef(ref3.getName())).isNull();
}
}
@Test
public void cleanZombieDraftsLarge() throws Exception {
try (Repository usersRepo = repoManager.createRepository(allUsersProject)) {
int goodRefsCnt = 5000;
int zombieRefsCnt = 5000;
int userIdGoodRefs = 1000001;
int userIdBadRefs = 1000002;
Ref nonEmptyBaseRef = createRefWithNonEmptyTreeCommit(usersRepo, 1, userIdGoodRefs);
Ref emptyBaseRef = createRefWithEmptyTreeCommit(usersRepo, 1, userIdBadRefs);
List<String> goodRefs =
createNRefsOnCommit(
usersRepo, nonEmptyBaseRef.getObjectId(), goodRefsCnt, userIdGoodRefs);
List<String> badRefs =
createNRefsOnCommit(usersRepo, emptyBaseRef.getObjectId(), zombieRefsCnt, userIdBadRefs);
goodRefs.add(0, nonEmptyBaseRef.getName());
badRefs.add(0, emptyBaseRef.getName());
assertThat(usersRepo.getRefDatabase().getRefs().size())
.isEqualTo(goodRefs.size() + badRefs.size());
DeleteZombieCommentsRefs clean =
new DeleteZombieCommentsRefs(new AllUsersName("All-Users"), repoManager, null);
clean.execute();
assertThat(
usersRepo.getRefDatabase().getRefs().stream()
.map(Ref::getName)
.collect(toImmutableList()))
.containsExactlyElementsIn(goodRefs);
assertThat(
usersRepo.getRefDatabase().getRefs().stream()
.map(Ref::getName)
.collect(toImmutableList()))
.containsNoneIn(badRefs);
}
}
private static List<String> createNRefsOnCommit(
Repository usersRepo, ObjectId commitId, int n, int uuid) throws IOException {
List<String> refNames = new ArrayList<>();
BatchRefUpdate bru = usersRepo.getRefDatabase().newBatchUpdate();
bru.setAtomic(true);
for (int i = 2; i <= n + 1; i++) {
String refName = getRefName(i, uuid);
bru.addCommand(
new ReceiveCommand(ObjectId.zeroId(), commitId, refName, ReceiveCommand.Type.CREATE));
refNames.add(refName);
}
RefUpdateUtil.executeChecked(bru, usersRepo);
return refNames;
}
private static String getRefName(int changeId, int userId) {
Change.Id cId = Change.id(changeId);
Account.Id aId = Account.id(userId);
return RefNames.refsDraftComments(cId, aId);
}
private static Ref createRefWithNonEmptyTreeCommit(Repository usersRepo, int changeId, int userId)
throws IOException {
RevWalk rw = new RevWalk(usersRepo);
ObjectId fileObj = createBlob(usersRepo, String.format("file %d content", changeId));
ObjectId treeObj =
createTree(usersRepo, rw.lookupBlob(fileObj), String.format("file%d.txt", changeId));
ObjectId commitObj = createCommit(usersRepo, treeObj, null);
Ref refObj = createRef(usersRepo, commitObj, getRefName(changeId, userId));
return refObj;
}
private static Ref createRefWithEmptyTreeCommit(Repository usersRepo, int changeId, int userId)
throws IOException {
ObjectId treeEmpty = createTree(usersRepo, null, "");
ObjectId commitObj = createCommit(usersRepo, treeEmpty, null);
Ref refObj = createRef(usersRepo, commitObj, getRefName(changeId, userId));
return refObj;
}
private static Ref createRef(Repository repo, ObjectId commitId, String refName)
throws IOException {
RefUpdate update = repo.updateRef(refName);
update.setNewObjectId(commitId);
update.setForceUpdate(true);
update.update();
return repo.exactRef(refName);
}
private static ObjectId createCommit(Repository repo, ObjectId treeId, ObjectId parentCommit)
throws IOException {
try (ObjectInserter oi = repo.newObjectInserter()) {
PersonIdent committer =
new PersonIdent(new PersonIdent("Foo Bar", "foo.bar@baz.com"), TimeUtil.nowTs());
CommitBuilder cb = new CommitBuilder();
cb.setTreeId(treeId);
cb.setCommitter(committer);
cb.setAuthor(committer);
cb.setMessage("Test commit");
if (parentCommit != null) {
cb.setParentIds(parentCommit);
}
ObjectId commitId = oi.insert(cb);
oi.flush();
oi.close();
return commitId;
}
}
private static ObjectId createTree(Repository repo, RevBlob blob, String blobName)
throws IOException {
try (ObjectInserter oi = repo.newObjectInserter()) {
TreeFormatter formatter = new TreeFormatter();
if (blob != null) {
formatter.append(blobName, blob);
}
ObjectId treeId = oi.insert(formatter);
oi.flush();
oi.close();
return treeId;
}
}
private static ObjectId createBlob(Repository repo, String content) throws IOException {
try (ObjectInserter oi = repo.newObjectInserter()) {
ObjectId blobId = oi.insert(Constants.OBJ_BLOB, content.getBytes(UTF_8));
oi.flush();
oi.close();
return blobId;
}
}
}

View File

@ -1,16 +0,0 @@
_template = """
load("@bazel_skylib//lib:versions.bzl", "versions")
def check_bazel_version():
versions.check(minimum_bazel_version = "{version}")
""".strip()
def _impl(repository_ctx):
repository_ctx.symlink(Label("@//:.bazelversion"), ".bazelversion")
bazelversion = repository_ctx.read(".bazelversion").strip()
repository_ctx.file("BUILD", executable = False)
repository_ctx.file("check.bzl", executable = False, content = _template.format(version = bazelversion))
bazelisk_version = repository_rule(implementation = _impl)