Merge branch 'stable-3.4' * stable-3.4: Add step to check for collisions to magic refs Set version to 3.4.0-rc0 Add branch protection check during the project import Set version to 3.3.0 Change-Id: Ia2998edd81b342f6252e2457b9656dcfb6615b0e
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 12acdb2..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,8 @@ 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; import com.googlesource.gerrit.plugins.github.notification.WebhookServlet; @@ -51,6 +53,10 @@ install( new FactoryModuleBuilder() + .implement(ProtectedBranchesCheckStep.class, ProtectedBranchesCheckStep.class) + .build(ProtectedBranchesCheckStep.Factory.class)); + install( + new FactoryModuleBuilder() .implement(GitCloneStep.class, GitCloneStep.class) .build(GitCloneStep.Factory.class)); install( @@ -63,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/AbstractCloneJob.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java index 4421841..753575f 100644 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/AbstractCloneJob.java
@@ -26,6 +26,9 @@ protected String getErrorDescription(Throwable exception) { LOG.error("Job " + this + " FAILED", exception); + if (exception instanceof ProtectedBranchFoundException) { + return exception.getMessage(); + } if (GitException.class.isAssignableFrom(exception.getClass())) { return ((GitException) exception).getErrorDescription(); } else if (ProvisionException.class.isAssignableFrom(exception.getClass())) {
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 0176091..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
@@ -26,31 +26,48 @@ public static class Provider extends HttpSessionProvider<GitImporter> {} 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; @Inject public GitImporter( + ProtectedBranchesCheckStep.Factory protectedBranchesCheckFactory, GitCloneStep.Factory cloneFactory, CreateProjectStep.Factory projectFactory, ReplicateProjectStep.Factory replicateFactory, + MagicRefCheckStep.Factory magicRefCheckFactory, JobExecutor executor, IdentifiedUser user) { super(executor, user); + this.protectedBranchesCheckFactory = protectedBranchesCheckFactory; this.cloneFactory = cloneFactory; this.projectFactory = projectFactory; this.replicateFactory = replicateFactory; + this.magicRefCheckFactory = magicRefCheckFactory; } public void clone(int idx, String organisation, String repository, String description) { try { + 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); GitImportJob gitCloneJob = - new GitImportJob(idx, organisation, repository, cloneStep, projectStep, replicateStep); + new GitImportJob( + idx, + organisation, + repository, + protectedBranchesCheckStep, + magicRefCheckStep, + cloneStep, + projectStep, + replicateStep); log.debug("New Git clone job created: " + gitCloneJob); schedule(idx, gitCloneJob); } catch (Throwable e) {
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()); + } +}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java new file mode 100644 index 0000000..221152f --- /dev/null +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java
@@ -0,0 +1,22 @@ +// 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 ProtectedBranchFoundException extends Exception { + + public ProtectedBranchFoundException(String msg) { + super(msg); + } +}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchesCheckStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchesCheckStep.java new file mode 100644 index 0000000..5b2f763 --- /dev/null +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchesCheckStep.java
@@ -0,0 +1,67 @@ +// 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.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.googlesource.gerrit.plugins.github.GitHubConfig; +import java.util.Collection; +import java.util.List; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.kohsuke.github.GHBranch; + +public class ProtectedBranchesCheckStep extends ImportStep { + + public interface Factory { + ProtectedBranchesCheckStep create( + @Assisted("organisation") String organisation, @Assisted("name") String repository); + } + + @Inject + public ProtectedBranchesCheckStep( + 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 { + Collection<GHBranch> branches = getRepository().getBranches().values(); + progress.beginTask("Checking branch protection", branches.size()); + List<String> protectedBranchNames = Lists.newLinkedList(); + for (GHBranch branch : branches) { + if (branch.isProtected()) { + protectedBranchNames.add(branch.getName()); + } + progress.update(1); + } + progress.endTask(); + if (!protectedBranchNames.isEmpty()) { + throw new ProtectedBranchFoundException( + String.format( + "Cannot import project with protected branches, you should remove protection from:%s", + Joiner.on(",").join(protectedBranchNames))); + } + } + + @Override + public boolean rollback() { + return true; + } +}