Add step to check for collisions to magic refs Importing a repository from github, containing refs starting with the magic ref prefix (refs/for or refs/meta) will lead to errors where any push to that repository would fail with: fatal: One or more refs/for/ names blocks change upload Prevent repositories containing refs starting with refs/for or refs/meta from being imported and provide a meaningful error message to the user so that they can fix the issue and try again. Bug: Issue 14059 Change-Id: I812e77624a6c7663d6efdec0694fef37b8b8ee4b
diff --git a/README.md b/README.md index 018f4d0..d01069d 100644 --- a/README.md +++ b/README.md
@@ -190,3 +190,22 @@ After the installation, Eclipse must be restarted and compilation errors should disappear. + +### Notes + +#### Magic refs + +Before importing a repository from github, this plugin checks that its git refs +do not clash with Gerrit magic refs, since importing those refs would prevent +users from creating change requests. + +Attempting to import repositories having refs starting with `refs/for/` or +`refs/meta` will fail with an error message. +For example: + +```text +Found 2 ref(s): Please remove or rename the following refs and try again: + refs/for/foo, refs/meta/bar +``` + +More information on Gerrit magic refs can be found [here](https://gerrit-review.googlesource.com/Documentation/intro-user.html#upload-change) \ No newline at end of file
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java index 4e6448b..f75030d 100644 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
@@ -24,6 +24,7 @@ import com.googlesource.gerrit.plugins.github.git.GitCloneStep; import com.googlesource.gerrit.plugins.github.git.GitHubRepository; import com.googlesource.gerrit.plugins.github.git.GitImporter; +import com.googlesource.gerrit.plugins.github.git.MagicRefCheckStep; import com.googlesource.gerrit.plugins.github.git.ProtectedBranchesCheckStep; import com.googlesource.gerrit.plugins.github.git.PullRequestImportJob; import com.googlesource.gerrit.plugins.github.git.ReplicateProjectStep; @@ -68,6 +69,10 @@ .build(ReplicateProjectStep.Factory.class)); install( new FactoryModuleBuilder() + .implement(MagicRefCheckStep.class, MagicRefCheckStep.class) + .build(MagicRefCheckStep.Factory.class)); + install( + new FactoryModuleBuilder() .implement(PullRequestImportJob.class, PullRequestImportJob.class) .build(PullRequestImportJob.Factory.class)); install(
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java index 66a7b5c..ff81411 100644 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitImporter.java
@@ -27,6 +27,7 @@ private static final Logger log = LoggerFactory.getLogger(GitImporter.class); private final ProtectedBranchesCheckStep.Factory protectedBranchesCheckFactory; + private final MagicRefCheckStep.Factory magicRefCheckFactory; private final GitCloneStep.Factory cloneFactory; private final CreateProjectStep.Factory projectFactory; private final ReplicateProjectStep.Factory replicateFactory; @@ -37,6 +38,7 @@ GitCloneStep.Factory cloneFactory, CreateProjectStep.Factory projectFactory, ReplicateProjectStep.Factory replicateFactory, + MagicRefCheckStep.Factory magicRefCheckFactory, JobExecutor executor, IdentifiedUser user) { super(executor, user); @@ -44,6 +46,7 @@ this.cloneFactory = cloneFactory; this.projectFactory = projectFactory; this.replicateFactory = replicateFactory; + this.magicRefCheckFactory = magicRefCheckFactory; } public void clone(int idx, String organisation, String repository, String description) { @@ -51,6 +54,7 @@ ProtectedBranchesCheckStep protectedBranchesCheckStep = protectedBranchesCheckFactory.create(organisation, repository); GitCloneStep cloneStep = cloneFactory.create(organisation, repository); + MagicRefCheckStep magicRefCheckStep = magicRefCheckFactory.create(organisation, repository); CreateProjectStep projectStep = projectFactory.create(organisation, repository, description, user.getUserName().get()); ReplicateProjectStep replicateStep = replicateFactory.create(organisation, repository); @@ -60,6 +64,7 @@ organisation, repository, protectedBranchesCheckStep, + magicRefCheckStep, cloneStep, projectStep, replicateStep);
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefCheckStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefCheckStep.java new file mode 100644 index 0000000..616a31c --- /dev/null +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefCheckStep.java
@@ -0,0 +1,72 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.github.git; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import com.google.gerrit.entities.RefNames; +import com.google.gerrit.server.util.MagicBranch; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.googlesource.gerrit.plugins.github.GitHubConfig; +import java.util.List; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.kohsuke.github.GHRef; + +public class MagicRefCheckStep extends ImportStep { + public interface Factory { + MagicRefCheckStep create( + @Assisted("organisation") String organisation, @Assisted("name") String repository); + } + + @Inject + public MagicRefCheckStep( + GitHubConfig config, + GitHubRepository.Factory gitHubRepoFactory, + @Assisted("organisation") String organisation, + @Assisted("name") String repository) { + super(config.gitHubUrl, organisation, repository, gitHubRepoFactory); + } + + @Override + public void doImport(ProgressMonitor progress) throws Exception { + try { + GHRef[] allRefs = getRepository().getRefs(); + progress.beginTask("Checking magic refs", allRefs.length); + + List<String> offendingRefs = Lists.newLinkedList(); + for (GHRef ref : allRefs) { + if (MagicBranch.isMagicBranch(ref.getRef()) + || ref.getRef().startsWith(RefNames.REFS_META)) { + offendingRefs.add(ref.getRef()); + } + progress.update(1); + } + + if (!offendingRefs.isEmpty()) { + throw new MagicRefFoundException( + String.format( + "Found %d ref(s): Please remove or rename the following ref(s) and try again: %s", + offendingRefs.size(), Joiner.on(", ").join(offendingRefs))); + } + } finally { + progress.endTask(); + } + } + + @Override + public boolean rollback() { + return true; + } +}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java new file mode 100644 index 0000000..263ee9d --- /dev/null +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java
@@ -0,0 +1,26 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.github.git; + +public class MagicRefFoundException extends GitException { + + public MagicRefFoundException(String message) { + super(message); + } + + @Override + public String getErrorDescription() { + return String.format("Clash with Gerrit magic refs. %s", getMessage()); + } +}