diff --git a/src/main/java/jenkins/scm/api/SCMFileSystem.java b/src/main/java/jenkins/scm/api/SCMFileSystem.java index 286c7bb4..69378cea 100644 --- a/src/main/java/jenkins/scm/api/SCMFileSystem.java +++ b/src/main/java/jenkins/scm/api/SCMFileSystem.java @@ -187,7 +187,28 @@ public static SCMFileSystem of(@NonNull Item owner, @NonNull SCM scm) throws IOE * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted. */ @CheckForNull - public static SCMFileSystem of(@NonNull Item owner, @NonNull SCM scm, @CheckForNull SCMRevision rev) + public static SCMFileSystem of(@NonNull Item owner, @NonNull SCM scm, @CheckForNull SCMRevision rev) throws IOException, InterruptedException { + return of(owner, scm, rev, null); + } + + + /** + * Given a {@link SCM} this method will try to retrieve a corresponding {@link SCMFileSystem} instance that + * reflects the content at the specified {@link SCMRevision}. + * + * @param owner the owner of the {@link SCM} + * @param scm the {@link SCM}. + * @param rev the specified {@link SCMRevision}. + * @param build an associated build context, if any, that could be used for example to look up parameters + * @return the corresponding {@link SCMFileSystem} or {@code null} if there is none. + * @throws IOException if the attempt to create a {@link SCMFileSystem} failed due to an IO error + * (such as the remote system being unavailable) + * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted. + */ + @CheckForNull + public static SCMFileSystem of(@NonNull Item owner, @NonNull SCM scm, + @CheckForNull SCMRevision rev, + @CheckForNull Run build) throws IOException, InterruptedException { Objects.requireNonNull(scm); SCMFileSystem fallBack = null; @@ -195,7 +216,8 @@ public static SCMFileSystem of(@NonNull Item owner, @NonNull SCM scm, @CheckForN for (Builder b : ExtensionList.lookup(Builder.class)) { if (b.supports(scm)) { try { - SCMFileSystem inspector = b.build(owner, scm, rev); + SCMFileSystem inspector = b.build(owner, scm, rev, build); + if (inspector != null) { if (inspector.isFixedRevision()) { return inspector; @@ -231,15 +253,15 @@ public static SCMFileSystem of(@NonNull Item owner, @NonNull SCM scm, @CheckForN /** * Given a {@link SCM} this method will check if there is at least one {@link SCMFileSystem} provider capable - * of being instantiated. Returning {@code true} does not mean that {@link #of(Item, SCM, SCMRevision)} + * of being instantiated. Returning {@code true} does not mean that {@link #of(Item, SCM, SCMRevision, Run)} * will be able to instantiate a {@link SCMFileSystem} for any specific {@link SCMRevision}, * rather returning {@code false} indicates that there is absolutely no point in calling - * {@link #of(Item, SCM, SCMRevision)} as it will always return {@code null}. + * {@link #of(Item, SCM, SCMRevision, Run)} as it will always return {@code null}. * * @param scm the {@link SCMSource}. - * @return {@code true} if {@link SCMFileSystem#of(Item, SCM)} / {@link #of(Item, SCM, SCMRevision)} could return a + * @return {@code true} if {@link SCMFileSystem#of(Item, SCM)} / {@link #of(Item, SCM, SCMRevision, Run)} could return a * {@link SCMFileSystem} implementation, {@code false} if {@link SCMFileSystem#of(Item, SCM)} / - * {@link #of(Item, SCM, SCMRevision)} will always return {@code null} for the supplied {@link SCM}. + * {@link #of(Item, SCM, SCMRevision, Run)} will always return {@code null} for the supplied {@link SCM}. * @since 2.0 */ public static boolean supports(@NonNull SCM scm) { @@ -350,13 +372,13 @@ public static boolean supports(@NonNull SCMSource source) { /** * Given a {@link SCMDescriptor} this method will check if there is at least one {@link SCMFileSystem} provider * capable of being instantiated from the descriptor's {@link SCMSource}. Returning {@code true} does not mean that - * {@link #of(Item, SCM, SCMRevision)} will be able to instantiate a {@link SCMFileSystem} for any specific + * {@link #of(Item, SCM, SCMRevision, Run)} will be able to instantiate a {@link SCMFileSystem} for any specific * {@link Item} or {@link SCMRevision}, rather returning {@code false} indicates that there is absolutely no point - * in calling {@link #of(Item, SCM, SCMRevision)} as it will always return {@code null}. + * in calling {@link #of(Item, SCM, SCMRevision, Run)} as it will always return {@code null}. * * @param descriptor the {@link SCMDescriptor}. - * @return {@code true} if {@link #of(Item, SCM, SCMRevision)} could return a {@link SCMFileSystem} implementation, - * {@code false} if {@link #of(Item, SCM, SCMRevision)} will always return {@code null} for the supplied {@link SCM}. + * @return {@code true} if {@link #of(Item, SCM, SCMRevision, Run)} could return a {@link SCMFileSystem} implementation, + * {@code false} if {@link #of(Item, SCM, SCMRevision, Run)} will always return {@code null} for the supplied {@link SCM}. * @since 2.3.0 */ public static boolean supports(@NonNull SCMDescriptor descriptor) { @@ -500,8 +522,11 @@ public final boolean supports(SCMSourceDescriptor descriptor) { * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted. */ @CheckForNull - public abstract SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull SCMRevision rev) - throws IOException, InterruptedException; + public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull SCMRevision rev) + throws IOException, InterruptedException + { + throw new AbstractMethodError("Implement build(Item, SCM, SCMRevision, Run) and override this method to delegate to it"); + } /** * Given a {@link SCMSource}, a {@link SCMHead} and a {@link SCMRevision} this method should try to build a @@ -525,12 +550,38 @@ public SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead head, if (owner == null) { throw new IOException("Cannot instantiate a SCMFileSystem from an SCM without an owner"); } - return build(owner, source.build(head, rev), rev); + return build(owner, source.build(head, rev), rev, null); } private boolean isEnclosedByDescribable(Descriptor descriptor) { Class enclosingClass = getClass().getEnclosingClass(); return enclosingClass != null && descriptor.clazz.isAssignableFrom(enclosingClass); } + + /** + * Given a {@link SCM} this should try to build a corresponding {@link SCMFileSystem} instance that + * reflects the content at the specified {@link SCMRevision}. If the {@link SCM} is supported but not + * for a fixed revision, best effort is acceptable as the most capable {@link SCMFileSystem} will be returned + * to the caller. If the {@link Run} is provided, it can be used to alter the behavior. + * For example, variables in the branch name can be expanded based on current build properties, etc. + * + * @param owner the owner of the {@link SCM} + * @param scm the {@link SCM}. + * @param rev the specified {@link SCMRevision}. + * @param _build the specified {@link Run}. + * @return the corresponding {@link SCMFileSystem} or {@code null} if this builder cannot create a {@link + * SCMFileSystem} for the specified {@link SCM}. + * @throws IOException if the attempt to create a {@link SCMFileSystem} failed due to an IO error + * (such as the remote system being unavailable) + * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted. + */ + @CheckForNull + public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull SCMRevision rev, + @CheckForNull Run _build) + throws IOException, InterruptedException + { + // if this is not overridden, fall back to the previous implementation + return build(owner, scm, rev); + } } }