Skip to content
Permalink
Browse files
[WIP JENKINS-24141] First work on abstracting out changelogs
Need to add tests, but first need to determine if this actually makes
sense as I've implemented it.
  • Loading branch information
abayer committed Jan 31, 2017
1 parent a6ae9c9 commit bd844821413de7a0d72f45756b52ce45b78da16b
@@ -30,6 +30,7 @@
import hudson.FilePath;
import hudson.Functions;
import hudson.Launcher;
import jenkins.scm.RunWithSCM;
import jenkins.util.SystemProperties;
import hudson.console.ModelHyperlinkNote;
import hudson.model.Fingerprint.BuildPtr;
@@ -102,7 +103,7 @@
* @author Kohsuke Kawaguchi
* @see AbstractProject
*/
public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends AbstractBuild<P,R>> extends Run<P,R> implements Queue.Executable, LazyBuildMixIn.LazyLoadingRun<P,R> {
public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends AbstractBuild<P,R>> extends Run<P,R> implements Queue.Executable, LazyBuildMixIn.LazyLoadingRun<P,R>, RunWithSCM {

/**
* Set if we want the blame information to flow from upstream to downstream build.
@@ -331,8 +332,9 @@ public final FilePath getModuleRoot() {
* @return
* can be empty but never null.
*/
@Override
@Exported
public Set<User> getCulprits() {
@Nonnull public Set<User> getCulprits() {
if (culprits==null) {
Set<User> r = new HashSet<User>();
R p = getPreviousCompletedBuild();
@@ -386,6 +388,7 @@ public int size() {
*
* @since 1.191
*/
@Override
public boolean hasParticipant(User user) {
for (ChangeLogSet.Entry e : getChangeSet())
try{
@@ -863,7 +866,7 @@ protected final boolean preBuild(BuildListener listener,Iterable<? extends Build
* @return never null.
*/
@Exported
public ChangeLogSet<? extends Entry> getChangeSet() {
@Nonnull public ChangeLogSet<? extends Entry> getChangeSet() {
synchronized (changeSetLock) {
if (scm==null) {
scm = NullChangeLogParser.INSTANCE;
@@ -887,8 +890,8 @@ protected final boolean preBuild(BuildListener listener,Iterable<? extends Build
return cs;
}

@Restricted(DoNotUse.class) // for project-changes.jelly
public List<ChangeLogSet<? extends ChangeLogSet.Entry>> getChangeSets() {
@Override
@Nonnull public List<ChangeLogSet<? extends ChangeLogSet.Entry>> getChangeSets() {
ChangeLogSet<? extends Entry> cs = getChangeSet();
return cs.isEmptySet() ? Collections.<ChangeLogSet<? extends ChangeLogSet.Entry>>emptyList() : Collections.<ChangeLogSet<? extends ChangeLogSet.Entry>>singletonList(cs);
}
@@ -1971,66 +1971,6 @@ public HttpResponse doEnable() throws IOException, ServletException {
}


/**
* RSS feed for changes in this project.
*/
public void doRssChangelog( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
class FeedItem {
ChangeLogSet.Entry e;
int idx;

public FeedItem(Entry e, int idx) {
this.e = e;
this.idx = idx;
}

AbstractBuild<?,?> getBuild() {
return e.getParent().build;
}
}

List<FeedItem> entries = new ArrayList<FeedItem>();

for(R r=getLastBuild(); r!=null; r=r.getPreviousBuild()) {
int idx=0;
for( ChangeLogSet.Entry e : r.getChangeSet())
entries.add(new FeedItem(e,idx++));
}

RSS.forwardToRss(
getDisplayName()+' '+getScm().getDescriptor().getDisplayName()+" changes",
getUrl()+"changes",
entries, new FeedAdapter<FeedItem>() {
public String getEntryTitle(FeedItem item) {
return "#"+item.getBuild().number+' '+item.e.getMsg()+" ("+item.e.getAuthor()+")";
}

public String getEntryUrl(FeedItem item) {
return item.getBuild().getUrl()+"changes#detail"+item.idx;
}

public String getEntryID(FeedItem item) {
return getEntryUrl(item);
}

public String getEntryDescription(FeedItem item) {
StringBuilder buf = new StringBuilder();
for(String path : item.e.getAffectedPaths())
buf.append(path).append('\n');
return buf.toString();
}

public Calendar getEntryTimestamp(FeedItem item) {
return item.getBuild().getTimestamp();
}

public String getEntryAuthor(FeedItem entry) {
return JenkinsLocationConfiguration.get().getAdminAddress();
}
},
req, rsp );
}

/**
* {@link AbstractProject} subtypes should implement this base class as a descriptor.
*
@@ -28,6 +28,7 @@
import hudson.EnvVars;
import hudson.Extension;
import hudson.ExtensionPoint;
import hudson.FeedAdapter;
import hudson.PermalinkList;
import hudson.Util;
import hudson.cli.declarative.CLIResolver;
@@ -36,6 +37,8 @@
import hudson.model.Fingerprint.RangeSet;
import hudson.model.PermalinkProjectAction.Permalink;
import hudson.model.listeners.ItemListener;
import hudson.scm.ChangeLogSet;
import hudson.scm.SCM;
import hudson.search.QuickSilver;
import hudson.search.SearchIndex;
import hudson.search.SearchIndexBuilder;
@@ -83,11 +86,14 @@
import jenkins.model.BuildDiscarderProperty;
import jenkins.model.DirectlyModifiableTopLevelItemGroup;
import jenkins.model.Jenkins;
import jenkins.model.JenkinsLocationConfiguration;
import jenkins.model.ModelObjectWithChildren;
import jenkins.model.ProjectNamingStrategy;
import jenkins.model.RunIdMigrator;
import jenkins.model.lazy.LazyBuildMixIn;
import jenkins.scm.RunWithSCM;
import jenkins.security.HexStringConfidentialKey;
import jenkins.triggers.SCMTriggerItem;
import jenkins.util.io.OnMaster;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
@@ -1056,7 +1062,82 @@ public PermalinkList getPermalinks() {
}
return permalinks;
}


/**
* RSS feed for changes in this project.
*/
public void doRssChangelog(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
class FeedItem {
ChangeLogSet.Entry e;
int idx;

public FeedItem(ChangeLogSet.Entry e, int idx) {
this.e = e;
this.idx = idx;
}

Run<?, ?> getBuild() {
return e.getParent().build;
}
}

List<FeedItem> entries = new ArrayList<FeedItem>();
String scmDisplayName = "";
if (this instanceof SCMTriggerItem) {
SCMTriggerItem scmItem = (SCMTriggerItem) this;
List<String> scmNames = new ArrayList<>();
for (SCM s : scmItem.getSCMs()) {
scmNames.add(s.getDescriptor().getDisplayName());
}
scmDisplayName = " " + Util.join(scmNames, ", ");

for (RunT r = getLastBuild(); r != null; r = r.getPreviousBuild()) {
int idx = 0;
if (r instanceof RunWithSCM) {
for (ChangeLogSet<? extends ChangeLogSet.Entry> c : ((RunWithSCM) r).getChangeSets()) {
for (ChangeLogSet.Entry e : c) {
entries.add(new FeedItem(e, idx++));
}
}
}
}
}
RSS.forwardToRss(
getDisplayName() + scmDisplayName + " changes",
getUrl() + "changes",
entries, new FeedAdapter<FeedItem>() {
public String getEntryTitle(FeedItem item) {
return "#" + item.getBuild().number + ' ' + item.e.getMsg() + " (" + item.e.getAuthor() + ")";
}

public String getEntryUrl(FeedItem item) {
return item.getBuild().getUrl() + "changes#detail" + item.idx;
}

public String getEntryID(FeedItem item) {
return getEntryUrl(item);
}

public String getEntryDescription(FeedItem item) {
StringBuilder buf = new StringBuilder();
for (String path : item.e.getAffectedPaths())
buf.append(path).append('\n');
return buf.toString();
}

public Calendar getEntryTimestamp(FeedItem item) {
return item.getBuild().getTimestamp();
}

public String getEntryAuthor(FeedItem entry) {
return JenkinsLocationConfiguration.get().getAdminAddress();
}
},
req, rsp);
}



@Override public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
// not sure what would be really useful here. This needs more thoughts.
// for the time being, I'm starting with permalinks

0 comments on commit bd84482

Please sign in to comment.