package org.jenkinsci.plugins.p4.scm; import com.google.gson.Gson; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.TaskListener; import jenkins.scm.api.SCMHead; import jenkins.scm.api.SCMHeadCategory; import jenkins.scm.api.SCMRevision; import jenkins.scm.impl.ChangeRequestSCMHeadCategory; import jenkins.scm.impl.UncategorizedSCMHeadCategory; import jenkins.util.NonLocalizable; import org.jenkinsci.plugins.p4.PerforceScm; import org.jenkinsci.plugins.p4.browsers.P4Browser; import org.jenkinsci.plugins.p4.browsers.SwarmBrowser; import org.jenkinsci.plugins.p4.client.ClientHelper; import org.jenkinsci.plugins.p4.review.P4Review; import org.jenkinsci.plugins.p4.scm.swarm.SwarmProjectAPI; import org.jenkinsci.plugins.p4.scm.swarm.SwarmReviewAPI; import org.jenkinsci.plugins.p4.scm.swarm.SwarmReviewsAPI; import org.jenkinsci.plugins.p4.tasks.CheckoutStatus; import org.kohsuke.stapler.DataBoundConstructor; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class SwarmScmSource extends AbstractP4ScmSource { private final String url; private final String project; @DataBoundConstructor public SwarmScmSource(String id, String credential, String url, String project, String charset, String format) throws MalformedURLException { super(id, credential, charset, format); this.url = url; this.project = project; } public String getUrl() { return url; } public String getProject() { return project; } @Override public P4Browser getBrowser() { return new SwarmBrowser(url); } @Override public List<P4ChangeRequestSCMHead> getTags(@NonNull TaskListener listener) throws Exception { List<P4ChangeRequestSCMHead> list = new ArrayList<>(); List<SwarmReviewsAPI.Reviews> reviews = getActiveReviews(project, listener); for (SwarmReviewsAPI.Reviews review : reviews) { String reviewID = String.valueOf(review.getId()); List<String> branches = getBranchesInReview(reviewID, project, listener); for (String branch : branches) { List<String> paths = getPathsInBranch(branch, project, listener); String trgName = branch + "-" + reviewID; P4Head target = new P4Head(trgName, paths, false); P4ChangeRequestSCMHead tag = new P4ChangeRequestSCMHead(trgName, reviewID, paths, target, false); list.add(tag); } } return list; } @Override public List<P4Head> getHeads(@NonNull TaskListener listener) throws Exception { List<P4Head> list = new ArrayList<>(); List<SwarmProjectAPI.Branch> branches = getBranchesInProject(project, listener); for(SwarmProjectAPI.Branch branch : branches) { List<String> paths = branch.getPaths(); P4Head head = new P4Head(branch.getId(), paths, false); list.add(head); } return list; } @Override public P4Revision getRevision(P4Head head, TaskListener listener) throws Exception { if(head instanceof P4ChangeRequestSCMHead) { P4ChangeRequestSCMHead changeRequest = (P4ChangeRequestSCMHead) head; String review = changeRequest.getReview(); long change = getLastChangeInReview(review, project, listener); P4Revision revision = new P4Revision(head, change); return revision; } return super.getRevision(head, listener); } @Override public PerforceScm build(SCMHead head, SCMRevision revision) { PerforceScm scm = super.build(head, revision); if (head instanceof P4ChangeRequestSCMHead) { P4Review review = new P4Review(head.getName(), CheckoutStatus.SHELVED); scm.setReview(review); } return scm; } protected boolean isCategoryEnabled(@NonNull SCMHeadCategory category) { return true; } private List<SwarmReviewsAPI.Reviews> getActiveReviews(String project, TaskListener listener) throws Exception { // https://swarm.perforce.com/api/v6/reviews?max=2&fields=id,state,changes&project=swarm String fields = "id,state,changes"; String max = "10"; String state = "state[]=needsReview&state[]=needsRevision"; StringBuffer params = new StringBuffer("?"); params.append("max=" + max).append("&"); params.append("fields=" + fields).append("&"); params.append("project=" + project).append("&"); params.append(state); URL urlApi = new URL(url + "/api/v6/reviews" + params); String apiString = apiGET(urlApi, listener); Gson gson = new Gson(); SwarmReviewsAPI api = gson.fromJson(apiString.toString(), SwarmReviewsAPI.class); return api.getReviews(); } private SwarmReviewAPI getSwarmReview(String review, String project, TaskListener listener) throws Exception { // https://swarm.perforce.com/api/v6/reviews/1520872?fields=projects,changes,commits String fields = "projects,changes,commits"; StringBuffer params = new StringBuffer("?"); params.append("fields=" + fields); URL urlApi = new URL(url + "/api/v6/reviews/" + review + params); String apiString = apiGET(urlApi, listener); Gson gson = new Gson(); SwarmReviewAPI api = gson.fromJson(apiString.toString(), SwarmReviewAPI.class); return api; } private List<String> getBranchesInReview(String review, String project, TaskListener listener) throws Exception { SwarmReviewAPI api = getSwarmReview(review, project, listener); HashMap<String, List<String>> projects = api.getReview().getProjects(); List<String> branches = projects.get(project); return branches; } private long getLastChangeInReview(String review, String project, TaskListener listener) throws Exception { SwarmReviewAPI api = getSwarmReview(review, project, listener); List<Long> changes = api.getReview().getChanges(); long lastChange = 0; for (Long change : changes) { if (change > lastChange) { lastChange = change; } } return lastChange; } private List<String> getPathsInBranch(String id, String project, TaskListener listener) throws Exception { List<SwarmProjectAPI.Branch> branches = getBranchesInProject(project, listener); for (SwarmProjectAPI.Branch branch : branches) { if (id.equals(branch.getId())) { List<String> paths = branch.getPaths(); return paths; } } return new ArrayList<String>(); } private List<SwarmProjectAPI.Branch> getBranchesInProject(String project, TaskListener listener) throws Exception { // https://swarm.perforce.com/api/v6/projects/swarm?fields=branches String fields = "branches"; StringBuffer params = new StringBuffer("?"); params.append("fields=" + fields); URL urlApi = new URL(url + "/api/v6/projects/" + project + params); String apiString = apiGET(urlApi, listener); Gson gson = new Gson(); SwarmProjectAPI api = gson.fromJson(apiString.toString(), SwarmProjectAPI.class); List<SwarmProjectAPI.Branch> branches = api.getProject().getBranches(); return branches; } private String apiGET(URL url, TaskListener listener) throws IOException { String auth = getBasicAuth(listener); HttpURLConnection http = (HttpURLConnection) url.openConnection(); http.setDoInput(true); http.setDoOutput(true); http.setUseCaches(false); http.setRequestMethod("GET"); http.setRequestProperty("Authorization", "Basic " + auth); http.connect(); StringBuffer apiString = new StringBuffer(); String inputLine; BufferedReader in = new BufferedReader(new InputStreamReader(http.getInputStream(), "UTF-8")); while ((inputLine = in.readLine()) != null) { apiString.append(inputLine); } in.close(); return apiString.toString(); } private String getBasicAuth(TaskListener listener) { try (ClientHelper p4 = new ClientHelper(getOwner(), credential, listener, scmSourceClient, getCharset())) { String user = p4.getUser(); String ticket = p4.getTicket(); byte[] message = (user + ":" + ticket).getBytes("UTF-8"); String encoded = javax.xml.bind.DatatypeConverter.printBase64Binary(message); return encoded; } catch (Exception e) { return null; } } @Extension public static final class DescriptorImpl extends P4ScmSourceDescriptor { @Override public String getDisplayName() { return "Perforce Reviews"; } @NonNull @Override protected SCMHeadCategory[] createCategories() { return new SCMHeadCategory[]{ new UncategorizedSCMHeadCategory(new NonLocalizable("Branches")), new ChangeRequestSCMHeadCategory(new NonLocalizable("Reviews")) }; } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#32 | 30143 | Sandeep Kumar |
Merge pull request #[197] from [skumar7322/SwarmAPI] Change Swarm API version to v11 |
||
#31 | 29673 | Sandeep Kumar |
Merge pull request #188 from jenkinsci/CodeRefactoring Code Cleanup |
||
#30 | 28015 | Paul Allen |
MultiBranch exclude filter. A regular expression exclude filter for Swarm branches, Stream names and Branch paths. JENKINS-58346 JENKINS-63625 |
||
#29 | 27770 | Paul Allen | Update Swarm API to v9 | ||
#28 | 26955 | Paul Allen |
Merge pull request #125 from dvilaverde/master Add ContributorMetadataAction to SwarmScmSource to enable CHANGE_AUTHOR env variable in build |
||
#27 | 26938 | Paul Allen |
Merge pull request #122 from dvilaverde/master Have P4ChangeRequestSCMHead implement interface ChangeRequestSCMHead2 |
||
#26 | 26930 | Paul Allen |
Merge pull request #124 from dvilaverde/case-sensitive SwarmSCMSource#getHeads uses swarm id instead of name for P4SCMHead |
||
#25 | 26673 | Paul Allen |
Code cleanup - remove calls to Deprecated methods - Deprecated classes like AbstractStepImpl, AbstractStepDescriptorImpl and AbstractSynchronousStepExecution for P4TaggingStep |
||
#24 | 26602 | Paul Allen |
Reuse temp client connections for the multi-branch scan. TempClientHelper is set in retrieve and updated for different heads. |
||
#23 | 25844 | Paul Allen | Change Swarm Reviews so that they are only identified by review number in the multi branch (for better rendering in BlueOcean). | ||
#22 | 25610 | Paul Allen |
Merge pull request #98 from stuartrowe/JENKINS-57358 [JENKINS-57358] Add null check before using P4Path object returned by method SwarmScmSource#getPathsInBranch |
||
#21 | 25564 | Paul Allen |
Merge branch 'local_map' MultiBranch support for 'HelixBranches' local and remote Mappings. Allows MultiBranches to map Depot paths external to the MultiBranch projects root. For example, a MultiBranch project with the following Jenkinsfiles: ProjA >> main //depot/projA/main/Jenkinsfile //depot/projA/main/src/... ProjA>> dev //depot/projA/dev/Jenkinsfile //depot/projA/dev/src/... An 'Includes' path for Branch Sources set to: //depot/projA/... Jenkins will now create two branches 'main' and 'dev'. The default Mapping is '...' so the 'src/...' and any other files under the branch root will appear in the project's workspace. To import an extenal location we can add another line to the mapping: ... //depot/external/stuff/... Now both branches 'main' and 'dev' will have a folder 'depot/external/stuff' with the mapped files. We can also use the `BRANCH_NAME` environment variable in the remote path uses the branch name. ... //depot/external/${BRANCH_NAME}/... and in 'main' you will now see the remote files in ' depot/external/main' along with the local project files mapped with '...' |
||
#20 | 25006 | Paul Allen |
Support for remote Jenkinsfiles in a MultiBranch project. Jenkinsfile are idenitified by the Include branches path (e.g. //depot/Remote/...), but you must add a Mapping in the BranchSource->Advanced->View Mappings to locate the projects source and use a special ${BRANCH_NAME} in the path. e.g. //depot/ProjectA/${BRANCH_NAME}/... JENKINS-53936 |
||
#19 | 24829 | Paul Allen |
Support Jenkinsfiles in sub directories. Preserve Jenkinsfile path in Client View. JENKINS-54382 |
||
#18 | 24670 | Paul Allen |
Swarm review support for MultiBranch scanning. Changed TempClient view map to add Jenkinsfile at the bottom. |
||
#17 | 24662 | Paul Allen |
Undo *SCMSource rename to original *ScmSource. Reslove configuration loading issue due to 1.9.0 bad release. |
||
#16 | 24504 | Paul Allen |
Tree walter for BranchSCMSource Events. On a change-submit event use the change number and grab a submitted file. Walk up the path looking for a Jenkinsfile, then derive 'Project' path, 'Branch' name and 'Path' for the SCMHead/Revision. This assumes that the Jenkinsfile is in the route of your projects. Alternatively use the Swarm Event and pass your own 'Project', 'Branch' and 'Path'. |
||
#15 | 24501 | Paul Allen | Refactor to use P4SCMXxx naming convention. | ||
#14 | 24497 | Paul Allen |
Force use of revision for Head. Update P4Head->P4Path revision with P4Revision to avoid builds on unbounded 'latest'. |
||
#13 | 24492 | Paul Allen |
Initial work for MultiBranch Event trigger. JENKINS-52066 (Triggered Events and not Polling per change) |
||
#12 | 24454 | Paul Allen |
Exclude and Include mapping support. Refactored P4Path usage and added P4SwarmPath. JENKINS-49804 |
||
#11 | 23320 | Paul Allen | Remove deprecated ID for SCMSource constructor. | ||
#10 | 22937 | Paul Allen | Use Unirest for all Swarm API calls. | ||
#9 | 22881 | Paul Allen | Cache the BasicAuth token to avoid multiple login calls. | ||
#8 | 22875 | Paul Allen | Refactor P4Path and Swarm API | ||
#7 | 22866 | Paul Allen |
Merge pull request #55 from jenkinsci/hth Global Pipeline Library support. JENKINS-46121 JENKINS-46550 |
||
#6 | 22863 | Paul Allen | Store change in P4Revision as P4Ref. | ||
#5 | 22841 | Paul Allen |
Switch to `P4.Swarm.URL` property for Swarm url. JENKINS-45464 |
||
#4 | 22684 | Paul Allen | Added @Symbol to Extension classes for Pipeline Syntax. | ||
#3 | 22678 | Paul Allen |
MultiBranch support for Helix4Git (GitHub PR model). Update MultiBranch product names to Helix. |
||
#2 | 22398 | Paul Allen | Pass Perforce ticket using BasicAuth to Swarm API. | ||
#1 | 22396 | Paul Allen |
MultiBranch support for Perforce Swarm Reviews. A work in progress - adds Swarm API support to find branches and reviews from a Swarm project. #review-22354 |
||
//guest/perforce_software/p4jenkins/main/src/main/java/org/jenkinsci/plugins/p4/scm/SwarmSCMSource.java | |||||
#5 | 24597 | Paul Allen | Fix P4Path bug on MultiBranch to include branch. | ||
#4 | 24571 | Paul Allen |
Support for Swarm pre-commit review events. Swarm pre-commit review event creates a new 'Reviews' Tag in the MultiBranch and builds with specified change and shelf. |
||
#3 | 24536 | Paul Allen |
Improved Swarm SCMRevision builder. Started to add Swarm Review Event support and exteded test case. JENKINS-52066 |
||
#2 | 24529 | Paul Allen |
Swarm Commit Event support, refactoring and test. JENKINS-52605 (Fix doc in 'Includes' help bubble for MultiBranch) JENKINS-52066 (Improve Swarm Commit and Branch Event support) |
||
#1 | 24504 | Paul Allen |
Tree walter for BranchSCMSource Events. On a change-submit event use the change number and grab a submitted file. Walk up the path looking for a Jenkinsfile, then derive 'Project' path, 'Branch' name and 'Path' for the SCMHead/Revision. This assumes that the Jenkinsfile is in the route of your projects. Alternatively use the Swarm Event and pass your own 'Project', 'Branch' and 'Path'. |
||
# | Change | User | Description | Committed | |
#15 | 24501 | Paul Allen | Refactor to use P4SCMXxx naming convention. | ||
#14 | 24497 | Paul Allen |
Force use of revision for Head. Update P4Head->P4Path revision with P4Revision to avoid builds on unbounded 'latest'. |
||
#13 | 24492 | Paul Allen |
Initial work for MultiBranch Event trigger. JENKINS-52066 (Triggered Events and not Polling per change) |
||
#12 | 24454 | Paul Allen |
Exclude and Include mapping support. Refactored P4Path usage and added P4SwarmPath. JENKINS-49804 |
||
#11 | 23320 | Paul Allen | Remove deprecated ID for SCMSource constructor. | ||
#10 | 22937 | Paul Allen | Use Unirest for all Swarm API calls. | ||
#9 | 22881 | Paul Allen | Cache the BasicAuth token to avoid multiple login calls. | ||
#8 | 22875 | Paul Allen | Refactor P4Path and Swarm API | ||
#7 | 22866 | Paul Allen |
Merge pull request #55 from jenkinsci/hth Global Pipeline Library support. JENKINS-46121 JENKINS-46550 |
||
#6 | 22863 | Paul Allen | Store change in P4Revision as P4Ref. | ||
#5 | 22841 | Paul Allen |
Switch to `P4.Swarm.URL` property for Swarm url. JENKINS-45464 |
||
#4 | 22684 | Paul Allen | Added @Symbol to Extension classes for Pipeline Syntax. | ||
#3 | 22678 | Paul Allen |
MultiBranch support for Helix4Git (GitHub PR model). Update MultiBranch product names to Helix. |
||
#2 | 22398 | Paul Allen | Pass Perforce ticket using BasicAuth to Swarm API. | ||
#1 | 22396 | Paul Allen |
MultiBranch support for Perforce Swarm Reviews. A work in progress - adds Swarm API support to find branches and reviews from a Swarm project. #review-22354 |