-
-
Notifications
You must be signed in to change notification settings - Fork 273
[JENKINS-35227] added support for AdditionalCredentials to SubversionSCMSource #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
3685c38
11db817
fa29350
3540bb6
4a9730b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -297,7 +297,7 @@ public SubversionSCM(List<ModuleLocation> locations, | |
| */ | ||
| public SubversionSCM(List<ModuleLocation> locations, | ||
| boolean useUpdate, SubversionRepositoryBrowser browser, String excludedRegions, String excludedUsers, String excludedRevprop, String excludedCommitMessages) { | ||
| this(locations, useUpdate, false, browser, excludedRegions, excludedUsers, excludedRevprop, excludedCommitMessages); | ||
| this(locations, useUpdate, false, browser, excludedRegions, excludedUsers, excludedRevprop, excludedCommitMessages); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -372,28 +372,35 @@ public SubversionSCM(List<ModuleLocation> locations, WorkspaceUpdater workspaceU | |
| * Convenience constructor, especially during testing. | ||
| */ | ||
| public SubversionSCM(String svnUrl) { | ||
| this(svnUrl, null, "."); | ||
| this(svnUrl, null, ".", new ArrayList<AdditionalCredentials>()); | ||
| } | ||
|
|
||
| /** | ||
| * Convenience constructor, especially during testing. | ||
| */ | ||
| public SubversionSCM(String svnUrl, String local) { | ||
| this(svnUrl, null, local); | ||
| this(svnUrl, null, local, new ArrayList<AdditionalCredentials>()); | ||
| } | ||
|
|
||
| /** | ||
| * Convenience constructor, especially during testing. | ||
| */ | ||
| public SubversionSCM(String svnUrl, String credentialId, String local) { | ||
| this(new String[]{svnUrl}, new String[]{credentialId}, new String[]{local}); | ||
| this(new String[]{svnUrl}, new String[]{credentialId}, new String[]{local}, new ArrayList<AdditionalCredentials>()); | ||
| } | ||
|
|
||
| /** | ||
| * Convenience constructor, especially during testing. | ||
| */ | ||
| public SubversionSCM(String svnUrl, String credentialId, String local, List<AdditionalCredentials> additionalCredentials) { | ||
| this(new String[]{svnUrl}, new String[]{credentialId}, new String[]{local}, additionalCredentials); | ||
| } | ||
|
|
||
| /** | ||
| * Convenience constructor, especially during testing. | ||
| */ | ||
| public SubversionSCM(String[] svnUrls, String[] locals) { | ||
| this(svnUrls, null, locals); | ||
| this(svnUrls, null, locals, new ArrayList<AdditionalCredentials>()); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -403,6 +410,14 @@ public SubversionSCM(String[] svnUrls, String[] credentialIds, String[] locals) | |
| this(ModuleLocation.parse(svnUrls, credentialIds, locals, null,null), true, false, null, null, null, null, null); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Convenience constructor, especially during testing. | ||
| */ | ||
| public SubversionSCM(String[] svnUrls, String[] credentialIds, String[] locals, List<AdditionalCredentials> additionalCredentials) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not believe new methods are really required if you implement proper null handling in the original constructors. You say these methods are useful for testing, but there is no autotests |
||
| this(ModuleLocation.parse(svnUrls, credentialIds, locals, null,null), new UpdateUpdater(), null, null, null, null, null, null, false, false, additionalCredentials); | ||
| } | ||
|
|
||
| /** | ||
| * @deprecated | ||
| * as of 1.91. Use {@link #getLocations()} instead. | ||
|
|
@@ -418,7 +433,7 @@ public String getModules() { | |
| */ | ||
| @Exported | ||
| public ModuleLocation[] getLocations() { | ||
| return getLocations(null, null); | ||
| return getLocations(null, null); | ||
| } | ||
|
|
||
| @Override public String getKey() { | ||
|
|
@@ -777,36 +792,36 @@ private void calcChangeLog(Run<?,?> build, FilePath workspace, File changelogFil | |
| try { | ||
| String line; | ||
| while((line=br.readLine())!=null) { | ||
| boolean isPinned = false; | ||
| int indexLast = line.length(); | ||
| if (line.lastIndexOf("::p") == indexLast-3) { | ||
| isPinned = true; | ||
| indexLast -= 3; | ||
| } | ||
| int index = line.lastIndexOf('/'); | ||
| boolean isPinned = false; | ||
| int indexLast = line.length(); | ||
| if (line.lastIndexOf("::p") == indexLast-3) { | ||
| isPinned = true; | ||
| indexLast -= 3; | ||
| } | ||
| int index = line.lastIndexOf('/'); | ||
| if(index<0) { | ||
| continue; // invalid line? | ||
| } | ||
| try { | ||
| String url = line.substring(0, index); | ||
| long revision = Long.parseLong(line.substring(index+1,indexLast)); | ||
| Long oldRevision = revisions.get(url); | ||
| if (isPinned) { | ||
| if (!prunePinnedExternals) { | ||
| if (oldRevision == null) | ||
| // If we're writing pinned, only write if there are no unpinned | ||
| revisions.put(url, revision); | ||
| } | ||
| } else { | ||
| // unpinned | ||
| if (oldRevision == null || oldRevision > revision) | ||
| // For unpinned, take minimum | ||
| revisions.put(url, revision); | ||
| } | ||
| } catch (NumberFormatException e) { | ||
| // perhaps a corrupted line. | ||
| LOGGER.log(WARNING, "Error parsing line " + line, e); | ||
| } | ||
| String url = line.substring(0, index); | ||
| long revision = Long.parseLong(line.substring(index+1,indexLast)); | ||
| Long oldRevision = revisions.get(url); | ||
| if (isPinned) { | ||
| if (!prunePinnedExternals) { | ||
| if (oldRevision == null) | ||
| // If we're writing pinned, only write if there are no unpinned | ||
| revisions.put(url, revision); | ||
| } | ||
| } else { | ||
| // unpinned | ||
| if (oldRevision == null || oldRevision > revision) | ||
| // For unpinned, take minimum | ||
| revisions.put(url, revision); | ||
| } | ||
| } catch (NumberFormatException e) { | ||
| // perhaps a corrupted line. | ||
| LOGGER.log(WARNING, "Error parsing line " + line, e); | ||
| } | ||
| } | ||
| } finally { | ||
| br.close(); | ||
|
|
@@ -2759,7 +2774,7 @@ public String getLocalDir() { | |
| * possible "@NNN" suffix. | ||
| */ | ||
| public String getURL() { | ||
| return SvnHelper.getUrlWithoutRevision(remote); | ||
| return SvnHelper.getUrlWithoutRevision(remote); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -3237,7 +3252,7 @@ private static StandardCredentials lookupCredentials(Item context, String creden | |
| URIRequirementBuilder.fromUri(repoURL.toString()).build()), | ||
| CredentialsMatchers.withId(credentialsId)); | ||
| } | ||
|
|
||
| public static class AdditionalCredentials extends AbstractDescribableImpl<AdditionalCredentials> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, you must leave this class where it was for reasons of settings compatibility. Nothing is stopping |
||
| @NonNull | ||
| private final String realm; | ||
|
|
@@ -3331,5 +3346,5 @@ public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context, | |
| } | ||
|
|
||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,7 @@ | |
| import hudson.scm.FilterSVNAuthenticationManager; | ||
| import hudson.scm.SubversionRepositoryStatus; | ||
| import hudson.scm.SubversionSCM; | ||
| import hudson.scm.SubversionSCM.AdditionalCredentials; | ||
| import hudson.scm.subversion.SvnHelper; | ||
| import hudson.security.ACL; | ||
| import hudson.util.EditDistance; | ||
|
|
@@ -121,6 +122,8 @@ public class SubversionSCMSource extends SCMSource { | |
| private final String remoteBase; | ||
|
|
||
| private String credentialsId = ""; // TODO null would be a better default, but need to check null safety on usages | ||
|
|
||
| private List<AdditionalCredentials> additionalCredentials; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from what I see it still may be null when you read data from the disk |
||
|
|
||
| private String includes = DescriptorImpl.DEFAULT_INCLUDES; | ||
|
|
||
|
|
@@ -136,15 +139,18 @@ public SubversionSCMSource(String id, String remoteBase, String credentialsId, S | |
| setCredentialsId(credentialsId); | ||
| setIncludes(StringUtils.defaultIfEmpty(includes, DescriptorImpl.DEFAULT_INCLUDES)); | ||
| setExcludes(StringUtils.defaultIfEmpty(excludes, DescriptorImpl.DEFAULT_EXCLUDES)); | ||
| this.additionalCredentials = new ArrayList<AdditionalCredentials>(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usage of this collection is ineffective if you do not plan to modify it on the flight. Use |
||
| } | ||
|
|
||
| @DataBoundConstructor | ||
| @SuppressWarnings("unused") // by stapler | ||
| public SubversionSCMSource(String id, String remoteBase) { | ||
| super(id); | ||
| this.remoteBase = StringUtils.removeEnd(remoteBase, "/") + "/"; | ||
| this.additionalCredentials = new ArrayList<AdditionalCredentials>(); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Gets the credentials id. | ||
| * | ||
|
|
@@ -159,6 +165,14 @@ public String getCredentialsId() { | |
| public void setCredentialsId(String credentialsId) { | ||
| this.credentialsId = credentialsId; | ||
| } | ||
| @DataBoundSetter | ||
| public void setAdditionalCredentials(List<AdditionalCredentials> additionalCredentials) { | ||
| this.additionalCredentials = additionalCredentials; | ||
| } | ||
| //without getter jelly will crash | ||
| public List<AdditionalCredentials> getAdditionalCredentials() { | ||
| return(additionalCredentials); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FindBugs will grumble about exposing external implementation. Either make it
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for your comments. How do I make it restricted? Does adding "@restricted(NoExternalUse.class)" work?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be better to just |
||
| } | ||
|
|
||
| /** | ||
| * Gets the comma separated list of exclusions. | ||
|
|
@@ -273,7 +287,7 @@ protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener list | |
| String repoPath = SubversionSCM.DescriptorImpl.getRelativePath(repoURL, repository.getRepository()); | ||
| String path = SVNPathUtil.append(repoPath, head.getName()); | ||
| SVNRepositoryView.NodeEntry svnEntry = repository.getNode(path, -1); | ||
| return new SCMRevisionImpl(head, svnEntry.getRevision()); | ||
| return new SCMRevisionImpl(head, svnEntry.getRevision(), (additionalCredentials.size()>0)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not precise. Additional credentials might have been specified but not actually used. More plausibly, the server may use externals which simply do not need any distinct credentials. |
||
| } catch (SVNException e) { | ||
| throw new IOException(e); | ||
| } finally { | ||
|
|
@@ -308,7 +322,7 @@ protected SCMRevision retrieve(String unparsedRevision, TaskListener listener) t | |
| listener.getLogger().println("Could not find " + path); | ||
| return null; | ||
| } | ||
| return new SCMRevisionImpl(new SCMHead(base), revision == -1 ? resolvedRevision : revision); | ||
| return new SCMRevisionImpl(new SCMHead(base), revision == -1 ? resolvedRevision : revision, (additionalCredentials.size()>0)); | ||
| } catch (SVNException e) { | ||
| throw new IOException(e); | ||
| } finally { | ||
|
|
@@ -409,7 +423,7 @@ public boolean exists(@NonNull String path) throws IOException { | |
| }, listener)) { | ||
| listener.getLogger().println("Met criteria"); | ||
| SCMHead head = new SCMHead(childPath); | ||
| observer.observe(head, new SCMRevisionImpl(head, svnEntry.getRevision())); | ||
| observer.observe(head, new SCMRevisionImpl(head, svnEntry.getRevision(), (additionalCredentials.size()>0))); | ||
| if (!observer.isObserving()) { | ||
| return; | ||
| } | ||
|
|
@@ -689,9 +703,10 @@ public SubversionSCM build(@NonNull SCMHead head, | |
| // name contains an @ so need to ensure there is an @ at the end of the name | ||
| remote.append('@'); | ||
| } | ||
| return new SubversionSCM(remote.toString(), credentialsId, "."); | ||
| return new SubversionSCM(remote.toString(), credentialsId, ".", additionalCredentials); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Our implementation. | ||
| */ | ||
|
|
@@ -701,16 +716,29 @@ public static class SCMRevisionImpl extends SCMRevision { | |
| * The subversion revision. | ||
| */ | ||
| private long revision; | ||
| /** | ||
| * Indicates whether externals are used. If so, revision is considered non-deterministic. | ||
| */ | ||
| private boolean usesExternals; | ||
|
|
||
| public SCMRevisionImpl(SCMHead head, long revision) { | ||
| public SCMRevisionImpl(SCMHead head, long revision, boolean usesExternals) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Breaking change, the class was public |
||
| super(head); | ||
| this.revision = revision; | ||
| this.usesExternals = usesExternals; | ||
| } | ||
|
|
||
| public long getRevision() { | ||
| return revision; | ||
| } | ||
|
|
||
| public boolean isDeterministic() { | ||
| //non-deterministic when using externals, to force Jenkins to recurse into subdirectories | ||
| if(usesExternals) { | ||
| return false; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nondeterministic revisions are acceptable only for SCMs which inherently cannot support determinism, like CVS I suppose (though even there |
||
| } | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May cause merge conflicts without a reason