Author: tchemit Date: 2010-01-10 17:39:49 +0100 (Sun, 10 Jan 2010) New Revision: 76 Added: trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/LoginMojo.java Modified: trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AbstractAnnouncementMojo.java trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AnnouncementGenerator.java trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-email-announcement.vm trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-news-announcement.vm trunk/pom.xml Log: add LoginMojo + improve generate announcements with list of artifacts and attachments of release Added: trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/LoginMojo.java =================================================================== --- trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/LoginMojo.java (rev 0) +++ trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/LoginMojo.java 2010-01-10 16:39:49 UTC (rev 76) @@ -0,0 +1,309 @@ +package org.nuiton.jredmine.plugin; + +import org.apache.maven.model.IssueManagement; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.settings.Settings; +import org.nuiton.helper.plugin.ShareServerSecretPlugin; +import org.nuiton.io.rest.RestClientConfiguration; +import org.nuiton.jredmine.RedmineService; +import org.nuiton.jredmine.RedmineServiceImplementor; +import org.nuiton.plugin.AbstractPlugin; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; + +import java.net.URL; + +/** + * Obtain login for the redmine server to use. + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + * @goal login + * @since 1.2.1 + */ +public class LoginMojo extends AbstractPlugin implements RestClientConfiguration { + + /** + * Dependance du projet. + * + * @parameter default-value="${project}" + * @required + * @readonly + * @since 1.2.1 + */ + protected MavenProject project; + /** + * The real basedir redmine url. + * <p/> + * If no url is given, will use the issue management url. + * + * @parameter expression="${redmine.url}" + * @since 1.2.1 + */ + protected URL url; + /** + * Un flag pour activer le mode verbeux. + * + * @parameter expression="${redmine.verbose}" default-value="${maven.verbose}" + * @since 1.2.1 + */ + protected boolean verbose; + /** + * Un flag pour verifier le login (effectue une connexion au serveur). + * + * @parameter expression="${redmine.checkLogin}" default-value="false" + * @since 1.2.1 + */ + protected boolean checkLogin; + /** + * Un flag pour faire échouer le build si la configuration n'est pas ok. + * + * @parameter expression="${redmine.safe}" default-value="true" + * @since 1.2.1 + */ + protected boolean safe; + /** + * Redmine server id to obtain login and password. + * <p/> + * The server must be defined in your settings.xml file in servers section. + * + * @parameter expression="${redmine.serverId}" + * @required + * @since 1.2.1 + */ + protected String serverId; + + /** + * Dependance du settings. + * + * @parameter default-value="${settings}" + * @required + * @readonly + * @since 1.2.1 + */ + protected Settings settings; + /** + * password decypher + * + * @component roleHint="maven-helper-plugin" + * @since 1.2.1 + */ + protected SecDispatcher sec; + /** + * Redmine service. + * + * @component + * @since 1.2.1 + */ + protected RedmineService service; + + /** + * shared instance of delegate plugin to obtain login + * + * @since 1.2.1 + */ + protected static ShareServerSecretPlugin plugin; + + private static final String REDMINE_USERNAME = "redmine.username"; + private static final String REDMINE_PASSWORD = "redmine.password"; + + /////////////////////////////////////////////////////////////////////////// + /// Plugin + /////////////////////////////////////////////////////////////////////////// + + @Override + protected void init() throws Exception { + if (plugin == null) { + plugin = new ShareServerSecretPlugin(); + plugin.setServerId(serverId); + plugin.setUsernameOut(REDMINE_USERNAME); + plugin.setPasswordOut(REDMINE_PASSWORD); + plugin.setRunOnce(true); + + plugin.setProject(project); + plugin.setLog(getLog()); + plugin.setVerbose(isVerbose()); + plugin.setSettings(settings); + plugin.setSec(sec); + + plugin.init(); + } + + if (!checkLogin) { + // no more thing to do + return; + } + + // check issue management + + IssueManagement issueManagement = project.getIssueManagement(); + + if (issueManagement == null) { + throw new MojoExecutionException("No Issue Management set."); + } else if ((issueManagement.getUrl() == null) || (issueManagement.getUrl().trim().equals(""))) { + throw new MojoExecutionException("No URL set in Issue Management."); + } else if ((issueManagement.getSystem() != null) && !(issueManagement.getSystem().equalsIgnoreCase(AbstractRedmineMojo.REDMINE_SYSTEM))) { + throw new MojoExecutionException("Redmine's Plugin only supports 'redmine' Issue Management system."); + } + + // prepare Redmine service configuration + + URL url = getRestUrl(); + + if (url == null || url.toString().isEmpty()) { + + // no redmine url specified, guess it from issueManagement + + url = new URL(issueManagement.getUrl()); + + if (verbose) { + getLog().info("use the url from issue management : " + url); + } + } + + // apply configuration + + setRestUrl(url); + + } + + @Override + protected boolean checkSkip() { + + return plugin.checkSkip(); + } + + @Override + protected void doAction() throws Exception { + + getLog().info("Obtain redmine login for serverId '" + serverId + "'"); + plugin.execute(); + + if (!checkLogin) { + // no more thing to do + return; + } + + // init Redmine service + + try { + + ((RedmineServiceImplementor) service).init(this); + if (!((RedmineServiceImplementor) service).isInit()) { + throw new MojoExecutionException("could not logged to redmine server"); + } + + } catch (Exception e) { + if (safe) { + throw e; + } +// if (verbose) { + getLog().error("could not init Redmine service [" + getRestUrl() + "] with user '" + getRestUsername() + "'", e); +// } +// return false; + } + + getLog().info("Connection to redmine server successfull."); + } + + + @Override + protected void afterExecute() { + if (service != null) { + RedmineServiceImplementor i; + i = ((RedmineServiceImplementor) service); + + if (i.isInit()) { + try { + if (verbose) { + getLog().info("<<< Close redmine rest client..."); + } + i.destroy(); + } catch (Exception ex) { + getLog().error("could not close redmine client for reason " + ex.getMessage(), ex); + } + } + } + } + + @Override + public MavenProject getProject() { + return project; + } + + @Override + public void setProject(MavenProject project) { + this.project = project; + } + + @Override + public boolean isVerbose() { + return verbose; + } + + @Override + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + /////////////////////////////////////////////////////////////////////////// + /// RestClientConfiguration + /////////////////////////////////////////////////////////////////////////// + @Override + public String getRestPassword() { + return project.getProperties().getProperty(REDMINE_PASSWORD); + } + + @Override + public URL getRestUrl() { + return url; + } + + @Override + public String getRestUsername() { + return project.getProperties().getProperty(REDMINE_USERNAME); + } + + @Override + public void setRestPassword(String restPassword) { + } + + @Override + public void setRestUrl(URL restUrl) { + this.url = restUrl; + } + + @Override + public void setRestUsername(String restUsername) { + } + + @Override + public String getEncoding() { + return null; + } + + @Override + public void setEncoding(String encoding) { + } + + @Override + public boolean isAnonymous() { + return false; + } + + @Override + public void setAnonymous(boolean anonymous) { + } + + public boolean isSafe() { + return safe; + } + + public void setSafe(boolean safe) { + this.safe = safe; + } + +} Property changes on: trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/LoginMojo.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AbstractAnnouncementMojo.java =================================================================== --- trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AbstractAnnouncementMojo.java 2010-01-07 04:31:32 UTC (rev 75) +++ trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AbstractAnnouncementMojo.java 2010-01-10 16:39:49 UTC (rev 76) @@ -29,14 +29,14 @@ import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.velocity.VelocityComponent; +import org.nuiton.jredmine.model.Attachment; import org.nuiton.jredmine.plugin.AbstractRedmineMojo; import org.nuiton.plugin.PluginHelper; -import java.io.File; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.io.*; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author chemit @@ -86,20 +86,20 @@ * @since 1.0.0 */ protected Map<String, Object> announceParameters; -// /** -// * Template strings per system that is used to discover the URL to use to display an attchment. Each key in this -// * map denotes the (case-sensitive) identifier of the issue tracking system and its value gives the URL template. -// * <p> -// * There are 2 template tokens you can use. <code>%URL%</code>: this is computed by getting the -// * <code><issueManagement>/<url></code> value from the POM, and removing the last '/' - // * and everything that comes after it. <code>%FILE%</code>: this is the issue number. -// * </p> -// * -// * @parameter expression="${redmine.attachmentLinkTemplate}" -// * @since 1.0.0 -// */ -// protected String attachmentLinkTemplate; /** + * Template strings per system that is used to discover the URL to use to display an attchment. Each key in this + * map denotes the (case-sensitive) identifier of the issue tracking system and its value gives the URL template. + * <p> + * There are 2 template tokens you can use. <code>%URL%</code>: this is computed by getting the + * <code><issueManagement>/<url></code> value from the POM, and removing the last '/' + * and everything that comes after it. <code>%FILE%</code>: this is the issue number. + * </p> + * + * @parameter expression="${redmine.attachmentLinkTemplate}" + * @since 1.0.0 + */ + protected String attachmentLinkTemplate; + /** * @parameter expression="${project.groupId}" * @readonly * @since 1.0.0 @@ -174,12 +174,31 @@ */ protected boolean runOnce; /** + * @parameter expression="${redmine.artifactsFile}" + * @since 1.2.1 + */ + protected File artifactsFile; + /** + * @parameter expression="${redmine.deploymentUrl}" + * @readonly + */ + protected String deploymentUrl; + /** * Velocity Component. * * @component roleHint="maven-helper-plugin" */ protected VelocityComponent velocity; + protected Attachment[] attachments; + + protected Map<File, String> artifactUrls; + + protected Map<Attachment, String> attachmentUrls; + protected AnnouncementGenerator generator; + + private static final Pattern ARTIFACT_PATTERN = Pattern.compile("(.+)?--(.+)?"); + protected abstract String getAnnouncementTemplate(); protected AbstractAnnouncementMojo() { @@ -191,9 +210,6 @@ return runOnce; } - /** - * @return {@code true} if the goal was already invoked - */ @Override protected boolean checkRunOnceDone() { @@ -242,8 +258,67 @@ introduction = project.getUrl(); } + if (artifactsFile != null) { + if (!artifactsFile.exists()) { + throw new MojoExecutionException("The artifactsFile [" + artifactsFile + "] does not exists"); + + } + + List<File> files = getFiles(artifactsFile); + + String url = deploymentUrl.trim(); + + if (!url.endsWith("/")) { + deploymentUrl = (url += "/"); + } + + getLog().info("Deploy url = " + url); + + artifactUrls = new HashMap<File, String>(); + + for (File f : files) { + + String artifactInfo = f.getParentFile().getName(); + Matcher matcher = ARTIFACT_PATTERN.matcher(artifactInfo); + + if (!matcher.matches()) { + getLog().error("no matching for file " + artifactInfo + " (" + f + ")"); + } + String artifactId = matcher.group(2); + String groupId = matcher.group(1).replaceAll("\\.", "/") + "/" + artifactId; + String filename = f.getName(); + if ("pom.xml".equals(filename)) { + filename = artifactId + "-" + versionId + ".pom"; + f = new File(filename); + } + String spec = url + groupId + "/" + versionId + "/" + filename; + getLog().info("artifact file " + f.getName() + " --> " + spec); + + artifactUrls.put(f, spec); + + } + + } + super.init(); + generator = new AnnouncementGenerator(getLog(), projectUrl, attachmentLinkTemplate); + + Attachment[] attachments = service.getAttachments(projectId, versionId); + + if (attachments.length == 0) { + getLog().info("No attachments files"); + } + + attachmentUrls = generator.getAttachmentsUrls(attachments); + + for (Map.Entry<Attachment, String> e : attachmentUrls.entrySet()) { + Attachment key = e.getKey(); + String value = e.getValue(); + getLog().info("attachment file " + key.getFilename() + " --> " + value); + } + + // return true; } @@ -282,8 +357,6 @@ engine.setApplicationAttribute("baseDirectory", basedir); - AnnouncementGenerator generator = new AnnouncementGenerator(getLog(), projectUrl, ""); -// AnnouncementGenerator generator = new AnnouncementGenerator(getLog(), url, attachmentLinkTemplate); Context context = createVelocityContext(generator, releases); @@ -303,39 +376,37 @@ context.put("groupId", groupId); context.put("artifactId", artifactId); context.put("version", versionId); -// context.put("version", releaseVersion.getName()); context.put("packaging", packaging); context.put("url", projectUrl); Release release = generator.getLatestRelease(releases, versionId); -// Release release = generator.getLatestRelease(releases, releaseVersion.getName()); context.put("release", release); context.put("introduction", introduction); context.put("developmentTeam", developmentTeam); context.put("finalName", finalName); context.put("urlDownload", urlDownload); + context.put("mavenRepoUrl", this.deploymentUrl); context.put("project", project); -// -// if (downloads != null && downloads.length > 0) { -// Map<Attachment, String> attachmentsUrls = generator.getAttachmentsUrls(downloads); -// Object urls; -// if (attachmentsUrls == null || attachmentsUrls.isEmpty()) { -// urls = Collections.EMPTY_MAP; -// } else { -// urls = attachmentsUrls; -// } -// -// if (verbose) { -// getLog().info("nb attachments : " + ((Map<?, ?>) urls).size()); -// } -// -// if (getLog().isDebugEnabled()) { -// getLog().debug("attachmentsUrls :\n" + urls); -// } -// context.put("attachmentsUrls", urls); -// } + // add artifacts in context + if (artifactUrls == null || artifactUrls.isEmpty()) { + context.put("withArtifacts", false); + + } else { + context.put("withArtifacts", true); + context.put("artifactUrls", artifactUrls); + } + // add attachments in context + + if (attachmentUrls == null || attachmentUrls.isEmpty()) { + context.put("withAttachments", false); + + } else { + context.put("withAttachments", true); + context.put("attachmentUrls", attachmentUrls); + } + if (announceParameters == null) { // empty Map to prevent NPE in velocity execution context.put("announceParameters", Collections.EMPTY_MAP); @@ -344,4 +415,24 @@ } return context; } + + /** + * Read a file containing on each line the path of a file. + * + * @param input the file containing the list of files + * @return the list of files read from the given file + * @throws java.io.IOException if any pb while reading file + */ + public List<File> getFiles(File input) throws IOException { + List<File> result = new ArrayList<File>(); + BufferedReader stream = new BufferedReader(new InputStreamReader(new FileInputStream(input))); + while (stream.ready()) { + String line = stream.readLine().trim(); + if (!line.isEmpty()) { + File f = new File(line); + result.add(f); + } + } + return result; + } } Modified: trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AnnouncementGenerator.java =================================================================== --- trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AnnouncementGenerator.java 2010-01-07 04:31:32 UTC (rev 75) +++ trunk/maven-jredmine-plugin/src/main/java/org/nuiton/jredmine/plugin/announcement/AnnouncementGenerator.java 2010-01-10 16:39:49 UTC (rev 76) @@ -30,11 +30,13 @@ import org.apache.velocity.exception.ResourceNotFoundException; import org.codehaus.plexus.util.StringUtils; import org.nuiton.jredmine.model.Attachment; +import org.nuiton.plugin.PluginHelper; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -83,11 +85,9 @@ if (hasAttachmentLinks) { urls = new HashMap<Attachment, String>(); - if (hasAttachmentLinks) { - for (Attachment a : attachments) { - String u = parseAttachmentLink(a.getId() + ""); - urls.put(a, u); - } + for (Attachment a : attachments) { + String u = parseAttachmentLink(a.getId() + ""); + urls.put(a, u); } } else { getLog().warn("can not render attachments urls"); @@ -101,9 +101,7 @@ try { - if (!out.getParentFile().exists()) { - out.getParentFile().mkdirs(); - } + PluginHelper.createDirectoryIfNecessary(out.getParentFile()); Writer writer = new OutputStreamWriter(new FileOutputStream(out), templateEncoding); @@ -128,7 +126,7 @@ * @return <code>true</code> if issue links can be generated, <code>false</code> otherwise. */ public boolean canGenerateAttachmentLinks() { - return !StringUtils.isBlank(attachmentLinkTemplate) && (!StringUtils.isBlank(url) || attachmentLinkTemplate.indexOf(URL_TOKEN) < 0); + return !StringUtils.isBlank(attachmentLinkTemplate) && attachmentLinkTemplate.indexOf(ATTACHMENT_TOKEN) > 0 && (!StringUtils.isBlank(url) || attachmentLinkTemplate.indexOf(URL_TOKEN) < 0); } protected String parseAttachmentLink(String id) { @@ -151,7 +149,7 @@ * @param releases list of releases * @param releaseVersion the release version * @return A <code>Release</code> that matches the next release of the current project - * @throws MojoExecutionException + * @throws MojoExecutionException if any pb */ public Release getLatestRelease(List<?> releases, String releaseVersion) throws MojoExecutionException { Modified: trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-email-announcement.vm =================================================================== --- trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-email-announcement.vm 2010-01-07 04:31:32 UTC (rev 75) +++ trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-email-announcement.vm 2010-01-10 16:39:49 UTC (rev 76) @@ -18,6 +18,9 @@ ${introduction} +Changes +------- + #if ($release.getActions().size() == 0) No changes defined in this version. #else @@ -133,22 +136,36 @@ #end ## TODO make a short description from the packaging type (pom, plugin, jar, war,...) -#if ($urlDownload) +Downloads +--------- + +#if ($withAttachments) For a manual installation, you can download files here: -${urlDownload} +${urlDownload}. + +#foreach($a in $attachmentUrls.entrySet()) +#set($attachment=$a.getKey()) + * ${attachment.getFilename()} - ${a.getValue()} #end +#else +No release file deployed. +#end -#if ($attachmentsUrls) +Maven artifacts +--------------- -Release files: +#if ($withArtifacts) +Artifacts are deployed in nuiton maven repository +(${mavenRepoUrl}). -#foreach($a in $attachmentsUrls.entrySet()) -#set($attachment=$a.getKey()) -o ${attachment.getFilename()} - ${a.getValue()} +#foreach($a in $artifactUrls.entrySet()) +#set($artifact=$a.getKey()) + * ${a.getValue()} #end +#else +No artifact deployed. #end - Have fun! -${developmentTeam} Modified: trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-news-announcement.vm =================================================================== --- trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-news-announcement.vm 2010-01-07 04:31:32 UTC (rev 75) +++ trunk/maven-jredmine-plugin/src/main/resources/org/nuiton/jredmine/plugin/announcement/release-news-announcement.vm 2010-01-10 16:39:49 UTC (rev 76) @@ -135,19 +135,30 @@ h3. Downloads -#if ($urlDownload) +#if ($withAttachments) For a manual installation, you can download files here: -${urlDownload} +${urlDownload}. + +#foreach($a in $attachmentUrls.entrySet()) +#set($attachment=$a.getKey()) + * ${attachment.getFilename()} - ${a.getValue()} #end +#else + No release file deployed. +#end -#if ($attachmentsUrls) +h3. Maven artifacts -Release files: +#if ($withArtifacts) +Artifacts are deployed in nuiton maven repository +(${mavenRepoUrl}). -#foreach($a in $attachmentsUrls.entrySet()) -#set($attachment=$a.getKey()) -* ${attachment.getFilename()} - ${a.getValue()} +#foreach($a in $artifactUrls.entrySet()) +#set($artifact=$a.getKey()) + * ${a.getValue()} #end +#else + No artifact deployed. #end Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2010-01-07 04:31:32 UTC (rev 75) +++ trunk/pom.xml 2010-01-10 16:39:49 UTC (rev 76) @@ -108,10 +108,10 @@ <artifactId>plexus-cipher</artifactId> </exclusion> - <exclusion> + <!--exclusion> <groupId>org.sonatype.plexus</groupId> <artifactId>plexus-sec-dispatcher</artifactId> - </exclusion> + </exclusion--> </exclusions> @@ -402,7 +402,7 @@ <projectId>jredmine</projectId> - <helper.version>1.2.0</helper.version> + <helper.version>1.2.1-SNAPSHOT</helper.version> <!--<jredmine.version>1.0.2</jredmine.version>--> <!-- test config -->