diff --git a/src/main/java/com/cloudbees/plugins/credentials/Credentials.java b/src/main/java/com/cloudbees/plugins/credentials/Credentials.java index f1c5107bd..e556bd035 100644 --- a/src/main/java/com/cloudbees/plugins/credentials/Credentials.java +++ b/src/main/java/com/cloudbees/plugins/credentials/Credentials.java @@ -27,6 +27,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.ExtensionPoint; import hudson.model.Describable; +import hudson.model.Run; import java.io.Serializable; /** @@ -54,4 +55,16 @@ public interface Credentials extends Describable, Serializable, Ext @NonNull @SuppressWarnings("unchecked") CredentialsDescriptor getDescriptor(); + + /** + * Optionally produce a special value when used in the context of a particular build. + * @param context a build wishing to consume these credentials + * @return contextualized credentials, preferably implementing the same interfaces (if not of the same concrete type); by default, {@code this} + * @see CredentialsProvider#findCredentialById(java.lang.String, java.lang.Class, hudson.model.Run, com.cloudbees.plugins.credentials.domains.DomainRequirement...) + */ + @NonNull + default Credentials forRun(@NonNull Run context) { + return this; + } + } diff --git a/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java b/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java index 3db354249..84c5f08a6 100644 --- a/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java +++ b/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java @@ -916,7 +916,8 @@ public static C findCredentialById(@NonNull String id, CredentialsProvider.lookupCredentials(type, run.getParent(), ACL.SYSTEM, domainRequirements) ); } - return CredentialsMatchers.firstOrNull(candidates, CredentialsMatchers.withId(id)); + // TODO should this be calling track? + return contextualize(type, CredentialsMatchers.firstOrNull(candidates, CredentialsMatchers.withId(id)), run); } // this is a parameter and not the default value, we need to determine who triggered the build final Map.Entry> triggeredBy = triggeredBy(run); @@ -957,7 +958,23 @@ public static C findCredentialById(@NonNull String id, C result = CredentialsMatchers.firstOrNull(candidates, CredentialsMatchers.withId(id)); // if the run has not completed yet then we can safely assume that the credential is being used for this run // so we will track it's usage. We use isLogUpdated() as it could be used during post production - return run.isLogUpdated() ? track(run, result) : result; + if (run.isLogUpdated()) { + track(run, result); + } + return contextualize(type, result, run); + } + + @CheckForNull + private static C contextualize(@NonNull Class type, @CheckForNull C credentials, @NonNull Run run) { + if (credentials != null) { + Credentials contextualized = credentials.forRun(run); + if (type.isInstance(contextualized)) { + return type.cast(contextualized); + } else { + LOGGER.warning(() -> "Ignoring " + contextualized.getClass().getName() + " return value of " + credentials.getClass().getName() + ".forRun since it is not assignable to " + type.getName()); + } + } + return credentials; } /**