Skip to content
Permalink
Browse files

Merge pull request #36 from stephenc/jenkins-43507

[JENKINS-43507] Allow SCMSource and SCMNavigator subtypes to share common traits
  • Loading branch information...
stephenc committed Jun 14, 2017
2 parents 46581df + 0b6a184 commit cec562208e888c5447a18d2e848ddcdfd48cab8e
Showing with 6,447 additions and 316 deletions.
  1. +8 −7 pom.xml
  2. +46 −1 src/main/java/jenkins/scm/api/SCMHeadObserver.java
  3. +8 −3 src/main/java/jenkins/scm/api/SCMSourceObserver.java
  4. +4 −1 src/main/java/jenkins/scm/api/mixin/ChangeRequestSCMRevision.java
  5. +1 −1 src/main/java/jenkins/scm/api/mixin/SCMHeadMixin.java
  6. +191 −0 src/main/java/jenkins/scm/api/trait/SCMBuilder.java
  7. +212 −0 src/main/java/jenkins/scm/api/trait/SCMHeadAuthority.java
  8. +198 −0 src/main/java/jenkins/scm/api/trait/SCMHeadAuthorityDescriptor.java
  9. +54 −0 src/main/java/jenkins/scm/api/trait/SCMHeadFilter.java
  10. +52 −0 src/main/java/jenkins/scm/api/trait/SCMHeadPrefilter.java
  11. +267 −0 src/main/java/jenkins/scm/api/trait/SCMNavigatorContext.java
  12. +351 −0 src/main/java/jenkins/scm/api/trait/SCMNavigatorRequest.java
  13. +202 −0 src/main/java/jenkins/scm/api/trait/SCMNavigatorTrait.java
  14. +195 −0 src/main/java/jenkins/scm/api/trait/SCMNavigatorTraitDescriptor.java
  15. +204 −0 src/main/java/jenkins/scm/api/trait/SCMSourceBuilder.java
  16. +260 −0 src/main/java/jenkins/scm/api/trait/SCMSourceContext.java
  17. +127 −0 src/main/java/jenkins/scm/api/trait/SCMSourceDecorator.java
  18. +53 −0 src/main/java/jenkins/scm/api/trait/SCMSourceFilter.java
  19. +53 −0 src/main/java/jenkins/scm/api/trait/SCMSourcePrefilter.java
  20. +553 −0 src/main/java/jenkins/scm/api/trait/SCMSourceRequest.java
  21. +200 −0 src/main/java/jenkins/scm/api/trait/SCMSourceTrait.java
  22. +154 −0 src/main/java/jenkins/scm/api/trait/SCMSourceTraitDescriptor.java
  23. +57 −0 src/main/java/jenkins/scm/api/trait/SCMTrait.java
  24. +88 −0 src/main/java/jenkins/scm/api/trait/SCMTraitDescriptor.java
  25. +32 −0 src/main/java/jenkins/scm/api/trait/package-info.java
  26. +221 −0 src/main/java/jenkins/scm/impl/form/NamedArrayList.java
  27. +51 −0 src/main/java/jenkins/scm/impl/trait/Discovery.java
  28. +142 −0 src/main/java/jenkins/scm/impl/trait/RegexSCMHeadFilterTrait.java
  29. +141 −0 src/main/java/jenkins/scm/impl/trait/RegexSCMSourceFilterTrait.java
  30. +46 −0 src/main/java/jenkins/scm/impl/trait/Selection.java
  31. +144 −0 src/main/java/jenkins/scm/impl/trait/WildcardSCMHeadFilterTrait.java
  32. +142 −0 src/main/java/jenkins/scm/impl/trait/WildcardSCMSourceFilterTrait.java
  33. 0 src/main/resources/jenkins/scm/api/form/taglib
  34. +171 −0 src/main/resources/jenkins/scm/api/form/traits.jelly
  35. +43 −0 src/main/resources/jenkins/scm/api/form/traits/traits.css
  36. +50 −0 src/main/resources/jenkins/scm/api/form/traits/traits.js
  37. +27 −0 src/main/resources/jenkins/scm/impl/trait/Messages.properties
  38. +29 −0 src/main/resources/jenkins/scm/impl/trait/RegexSCMHeadFilterTrait/config.jelly
  39. +27 −0 src/main/resources/jenkins/scm/impl/trait/RegexSCMHeadFilterTrait/help-regex.html
  40. +29 −0 src/main/resources/jenkins/scm/impl/trait/RegexSCMSourceFilterTrait/config.jelly
  41. +27 −0 src/main/resources/jenkins/scm/impl/trait/RegexSCMSourceFilterTrait/help-regex.html
  42. +32 −0 src/main/resources/jenkins/scm/impl/trait/WildcardSCMHeadFilterTrait/config.jelly
  43. +27 −0 src/main/resources/jenkins/scm/impl/trait/WildcardSCMHeadFilterTrait/help-excludes.html
  44. +27 −0 src/main/resources/jenkins/scm/impl/trait/WildcardSCMHeadFilterTrait/help-includes.html
  45. +32 −0 src/main/resources/jenkins/scm/impl/trait/WildcardSCMSourceFilterTrait/config.jelly
  46. +27 −0 src/main/resources/jenkins/scm/impl/trait/WildcardSCMSourceFilterTrait/help-excludes.html
  47. +27 −0 src/main/resources/jenkins/scm/impl/trait/WildcardSCMSourceFilterTrait/help-includes.html
  48. +8 −7 src/test/java/jenkins/scm/api/SCMRevisionActionTest.java
  49. +0 −20 src/test/java/jenkins/scm/impl/NullSCMSourceTest.java
  50. +136 −69 src/test/java/jenkins/scm/impl/SingleSCMSourceTest.java
  51. +0 −1 src/test/java/jenkins/scm/impl/mock/MockChangeRequestFlags.java
  52. +1 −3 src/test/java/jenkins/scm/impl/mock/MockChangeRequestSCMHead.java
  53. +24 −3 src/test/java/jenkins/scm/impl/mock/MockChangeRequestSCMRevision.java
  54. +0 −2 src/test/java/jenkins/scm/impl/mock/MockRepositoryFlags.java
  55. +3 −1 src/test/java/jenkins/scm/impl/mock/MockSCM.java
  56. +53 −0 src/test/java/jenkins/scm/impl/mock/MockSCMBuilder.java
  57. +0 −1 src/test/java/jenkins/scm/impl/mock/MockSCMController.java
  58. +70 −0 src/test/java/jenkins/scm/impl/mock/MockSCMDiscoverBranches.java
  59. +112 −0 src/test/java/jenkins/scm/impl/mock/MockSCMDiscoverChangeRequests.java
  60. +71 −0 src/test/java/jenkins/scm/impl/mock/MockSCMDiscoverTags.java
  61. +59 −42 src/test/java/jenkins/scm/impl/mock/MockSCMNavigator.java
  62. +38 −0 src/test/java/jenkins/scm/impl/mock/MockSCMNavigatorContext.java
  63. +36 −0 src/test/java/jenkins/scm/impl/mock/MockSCMNavigatorRequest.java
  64. +142 −127 src/test/java/jenkins/scm/impl/mock/MockSCMSource.java
  65. +59 −0 src/test/java/jenkins/scm/impl/mock/MockSCMSourceBuilder.java
  66. +90 −0 src/test/java/jenkins/scm/impl/mock/MockSCMSourceContext.java
  67. +66 −0 src/test/java/jenkins/scm/impl/mock/MockSCMSourceRequest.java
  68. +65 −0 src/test/java/jenkins/scm/impl/trait/RegexSCMHeadFilterTraitTest.java
  69. +103 −0 src/test/java/jenkins/scm/impl/trait/RegexSCMSourceFilterTraitTest.java
  70. +103 −0 src/test/java/jenkins/scm/impl/trait/WildcardSCMHeadFilterTraitTest.java
  71. +135 −0 src/test/java/jenkins/scm/impl/trait/WildcardSCMSourceFilterTraitTest.java
  72. +31 −0 src/test/resources/jenkins/scm/impl/mock/MockSCMDiscoverChangeRequests/config.jelly
  73. +5 −12 src/test/resources/jenkins/scm/impl/mock/MockSCMNavigator/config.jelly
  74. +5 −15 src/test/resources/jenkins/scm/impl/mock/MockSCMSource/config-detail.jelly
15 pom.xml
@@ -29,7 +29,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.25</version>
<version>2.27</version>
<relativePath />
</parent>

@@ -102,19 +102,20 @@
<version>1.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
<version>2.5.3</version> <!-- 2.4.x does not work since it lacks https://github.com/jenkinsci/git-plugin/pull/402 -->
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-hpi-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate-taglib-interface</goal>
</goals>
</execution>
</executions>
<configuration>
<compatibleSinceVersion>2.0.0</compatibleSinceVersion>
</configuration>
@@ -1,7 +1,7 @@
/*
* The MIT License
*
* Copyright (c) 2011-2013, CloudBees, Inc., Stephen Connolly.
* Copyright (c) 2011-2017, CloudBees, Inc., Stephen Connolly.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package jenkins.scm.api;

import edu.umd.cs.findbugs.annotations.CheckForNull;
@@ -158,6 +159,17 @@ public static Any any() {
return new Any();
}

/**
* Creates an observer that selects the first revision it finds. Also useful for quick checks of non-empty.
*
* @return an observer that selects the first revision of a any head.
* @since 2.2.0
*/
@NonNull
public static None none() {
return None.INSTANCE;
}

/**
* An observer that wraps multiple observers and keeps observing as long as one of the wrapped observers wants to.
*/
@@ -545,6 +557,39 @@ public boolean isObserving() {

}

/**
* An observer that is already finished.
*
* @since 2.2.0
*/
public static final class None extends SCMHeadObserver {
/**
* Singleton.
*/
public static final None INSTANCE = new None();

/**
* Constructor.
*/
private None() {
}

/**
* {@inheritDoc}
*/
@Override
public void observe(@NonNull SCMHead head, @NonNull SCMRevision revision) {
}

/**
* {@inheritDoc}
*/
@Override
public boolean isObserving() {
return false;
}
}

/**
* Base class for an {@link SCMHeadObserver} that wraps another {@link SCMHeadObserver} while allowing access to the
* original observer via {@link #unwrap()}.
@@ -81,9 +81,12 @@
* {@link Item#getName}
* @return a secondary callback to customize the project, on which you must call {@link ProjectObserver#complete}
* @throws IllegalArgumentException if this {@code projectName} has already been encountered
* @throws IOException if observing this {@code projectName} could not be completed due to an {@link IOException}.
* @throws InterruptedException if observing this {@code projectName} was interrupted.
*/
@NonNull
public abstract ProjectObserver observe(@NonNull String projectName) throws IllegalArgumentException;
public abstract ProjectObserver observe(@NonNull String projectName) throws IllegalArgumentException, IOException,
InterruptedException;

/**
* Adds extra metadata about the overall organization.
@@ -212,7 +215,8 @@ public TaskListener getListener() {
*/
@Override
@NonNull
public ProjectObserver observe(@NonNull String projectName) throws IllegalArgumentException {
public ProjectObserver observe(@NonNull String projectName)
throws IllegalArgumentException, IOException, InterruptedException {
return delegate.observe(projectName);
}

@@ -280,7 +284,8 @@ public Filter(O delegate, String... projectNames) {
*/
@NonNull
@Override
public ProjectObserver observe(@NonNull String projectName) throws IllegalArgumentException {
public ProjectObserver observe(@NonNull String projectName)
throws IllegalArgumentException, IOException, InterruptedException {
if (remaining.remove(projectName)) {
return super.observe(projectName);
} else {
@@ -111,7 +111,10 @@ public final boolean equals(Object o) {
if (!equivalent(that)) {
return false;
}
return !isMerge() || target.equals(that.target);
if (isMerge() && that.isMerge()) {
return target.equals(that.target);
}
return isMerge() == that.isMerge();
}

/**
@@ -1,7 +1,7 @@
/*
* The MIT License
*
* Copyright (c) 2016 CloudBees, Inc.
* Copyright (c) 2016-2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,191 @@
/*
* The MIT License
*
* Copyright (c) 2017, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package jenkins.scm.api.trait;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.scm.SCM;
import java.util.Arrays;
import java.util.Collection;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;

/**
* Builder for a {@link SCM} instance. Typically instantiated in {@link SCMSource#build(SCMHead, SCMRevision)} or
* {@link SCMSource#build(SCMHead)} and then decorated by {@link SCMSourceTrait#applyToBuilder(SCMBuilder)} before
* calling {@link #build()} to generate the return value. Conventions:
* <ul>
* <li>The builder is not designed to be shared by multiple threads.</li>
* <li>All methods should be either {@code final} or {@code abstract} unless there is a documented reason for
* allowing overrides</li>
* <li>All "setter" methods will return {@link B} and be called "withXxx"</li>
* <li>All "getter" methods will be called "xxx()". Callers should not assume that the returned value is resistant
* from concurrent changes. Implementations should ensure that the returned value is immutable by the caller.
* In other words, it is intentional for implementations to reduce intermediate allocations by
* {@code return Collections.unmodifiableList(theList);} rather than the concurrency safe
* {@code return Collections.unmodifiableList(new ArrayList<>(theList));}
* </li>
* </ul>
*
* @param <B> the type of {@link SCMBuilder} so that subclasses can chain correctly in their {@link #withHead(SCMHead)}
* etc methods.
* @param <S> the type of {@link SCM} returned by {@link #build()}
*/
public abstract class SCMBuilder<B extends SCMBuilder<B,S>,S extends SCM> {

/**
* The base class of {@link SCM} that will be produced by the {@link SCMBuilder}.
*/
@NonNull
private final Class<S> clazz;
/**
* The {@link SCMHead} to produce the {@link SCM} for.
*/
@NonNull
private SCMHead head;
/**
* The {@link SCMRevision} to produce the {@link SCM} for or {@code null} to produce the {@link SCM} for the head
* revision.
*/
@CheckForNull
private SCMRevision revision;

/**
* Constructor.
*
* @param clazz The base class of {@link SCM} that will be produced by the {@link SCMBuilder}.
* @param head The {@link SCMHead} to produce the {@link SCM} for.
* @param revision The {@link SCMRevision} to produce the {@link SCM} for or {@code null} to produce the
* {@link SCM} for the head revision.
*/
public SCMBuilder(Class<S> clazz, @NonNull SCMHead head, @CheckForNull SCMRevision revision) {
this.clazz = clazz;
this.head = head;
this.revision = revision;
}

/**
* Returns the {@link SCMHead} to produce the {@link SCM} for.
*
* @return the {@link SCMHead} to produce the {@link SCM} for.
*/
@NonNull
public final SCMHead head() {
return head;
}

/**
* Returns the {@link SCMRevision} to produce the {@link SCM} for or {@code null} to produce the {@link SCM} for
* the head revision.
*
* @return the {@link SCMRevision} to produce the {@link SCM} for or {@code null} to produce the {@link SCM} for
* the head revision.
*/
@CheckForNull
public final SCMRevision revision() {
return revision;
}

/**
* Returns the base class of {@link SCM} that will be produced by the {@link SCMBuilder}.
*
* @return the base class of {@link SCM} that will be produced by the {@link SCMBuilder}.
*/
@NonNull
public final Class<S> scmClass() {
return clazz;
}

/**
* Replace the {@link #head()} with a new {@link SCMHead}.
*
* @param head the {@link SCMHead} to produce the {@link SCM} for.
* @return {@code this} for method chaining.
*/
@NonNull
public final B withHead(@NonNull SCMHead head) {
this.head = head;
return (B) this;
}

/**
* Replace the {@link #revision()} with a new {@link SCMRevision}
*
* @param revision the {@link SCMRevision} to produce the {@link SCM} for or {@code null} to produce the
* {@link SCM} for the head revision.
* @return {@code this} for method chaining.
*/
@NonNull
public final B withRevision(@CheckForNull SCMRevision revision) {
this.revision = revision;
return (B) this;
}

/**
* Apply the {@link SCMSourceTrait} to this {@link SCMBuilder}.
* @param trait the {@link SCMSourceTrait}.
* @return {@code this} for method chaining.
*/
@SuppressWarnings("unchecked")
@NonNull
public final B withTrait(@NonNull SCMSourceTrait trait) {
trait.applyToBuilder(this);
return (B) this;
}

/**
* Apply the {@link SCMSourceTrait} instances to this {@link SCMBuilder}.
*
* @param traits the {@link SCMSourceTrait} instances.
* @return {@code this} for method chaining.
*/
@NonNull
public final B withTraits(@NonNull SCMSourceTrait... traits) {
return withTraits(Arrays.asList(traits));
}

/**
* Apply the {@link SCMSourceTrait} instances to this {@link SCMBuilder}.
*
* @param traits the {@link SCMSourceTrait} instances.
* @return {@code this} for method chaining.
*/
@SuppressWarnings("unchecked")
@NonNull
public final B withTraits(@NonNull Collection<SCMSourceTrait> traits) {
for (SCMSourceTrait trait : traits) {
withTrait(trait);
}
return (B) this;
}

/**
* Instantiates the {@link SCM}.
* @return the {@link S} instance
*/
@NonNull
public abstract S build();
}

0 comments on commit cec5622

Please sign in to comment.
You can’t perform that action at this time.