1 package com.atlassian.amps.sdk.mpac;
2
3 import java.io.IOException;
4 import java.net.PasswordAuthentication;
5 import java.net.URI;
6 import java.text.MessageFormat;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import com.atlassian.amps.sdk.util.PropertiesReader;
11 import com.atlassian.jira.rest.client.api.JiraRestClient;
12 import com.atlassian.jira.rest.client.api.domain.Issue;
13 import com.atlassian.jira.rest.client.api.domain.SearchResult;
14 import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
15 import com.atlassian.marketplace.client.HttpConfiguration;
16 import com.atlassian.marketplace.client.MpacException;
17 import com.atlassian.marketplace.client.api.PluginDetailQuery;
18 import com.atlassian.marketplace.client.api.PluginVersionUpdate;
19 import com.atlassian.marketplace.client.impl.DefaultMarketplaceClient;
20 import com.atlassian.marketplace.client.model.LicenseIdentifier;
21 import com.atlassian.marketplace.client.model.Plugin;
22 import com.atlassian.marketplace.client.model.PluginVersion;
23 import com.atlassian.upm.api.util.Option;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29
30
31
32 public class MpacPublisher
33 {
34 final private static Logger LOG = LoggerFactory.getLogger(MpacPublisher.class);
35
36 final public static String MPAC_STAGING_SERVER = "https://mpac-5.dev.internal.atlassian.com/";
37 final public static String MPAC_PRODUCTION_SERVER = "https://marketplace.atlassian.com/";
38 final public static String JIRA_SERVER_URL = "https://ecosystem.atlassian.net/";
39 final private String[] sdkPluginKeys = new String[] { "mac", "tgz", "windows", "rpm", "deb" };
40 final private static URI JIRA_SERVER_URI = URI.create(JIRA_SERVER_URL);
41 final private static URI MPAC_STAGING_SERVER_URI = URI.create(MPAC_STAGING_SERVER);
42 final private static URI MPAC_PRODUCTION_SERVER_URI = URI.create(MPAC_PRODUCTION_SERVER);
43 private DefaultMarketplaceClient mpacClient;
44 final private PropertiesReader releaseProperties;
45
46 final private PasswordAuthentication mpacCredentials;
47 final private PasswordAuthentication ecoCredentials;
48 final private String version;
49 private String releaseNotes;
50
51 private MpacPublisher(final PasswordAuthentication mpacCredentials, final PasswordAuthentication ecoCredentials, final String version)
52 throws IOException
53 {
54 this.mpacCredentials = mpacCredentials;
55 this.ecoCredentials = ecoCredentials;
56 this.version = version;
57 this.releaseProperties = PropertiesReader.getInstance();
58 }
59
60 public void publish() throws IOException, MpacException
61 {
62 mpacClient = initializeMpacClient();
63 final List<SDKPlugin> sdkPlugins = processSdkPlugins();
64 for (SDKPlugin sdkPlugin : sdkPlugins)
65 {
66 releaseNewPluginVersion(sdkPlugin);
67 }
68 }
69
70 private List<SDKPlugin> processSdkPlugins()
71 {
72 final List<SDKPlugin> sdkPlugins = new ArrayList<SDKPlugin>(5);
73 for (int i = 0; i < sdkPluginKeys.length; i++)
74 {
75 final SDKPlugin sdkPlugin = SDKPlugin.SDKPluginBuilder
76 .aSDKPlugin()
77 .name("atlassian-plugin-sdk-" + sdkPluginKeys[i])
78 .binaryURI(formatURI(releaseProperties.getBinaryURI(sdkPluginKeys[i])))
79 .build();
80 sdkPlugins.add(sdkPlugin);
81 }
82 return sdkPlugins;
83 }
84
85 private String formatURI(String uri)
86 {
87 LOG.debug(uri);
88 return MessageFormat.format(uri, version);
89 }
90
91 private String initializeReleaseNotes(final String latestAmpsVersion, final String newAmpsVersion,
92 final String latestSdkVersion, final String newSdkVersion) throws IOException
93 {
94 final AsynchronousJiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
95 final JiraRestClient restClient = factory.createWithBasicHttpAuthentication(JIRA_SERVER_URI,
96 ecoCredentials.getUserName(), ecoCredentials.getPassword().toString());
97 final String query = MessageFormat.format("(project IN (AMPS, AMPSDEV) and status = resolved and fixVersion > {0} and fixVersion <= {1}) "
98 + "or (project IN (ATLASSDK ) and status = resolved and fixVersion > {2} and fixVersion <= {3})",
99 latestAmpsVersion, newAmpsVersion,
100 latestSdkVersion, newSdkVersion);
101 LOG.debug("initializeReleaseNotes query: " + query);
102 final StringBuilder releaseNotes = new StringBuilder();
103 final SearchResult searchResult = restClient.getSearchClient().searchJql(query).claim();
104 for (Issue issue : searchResult.getIssues())
105 {
106 releaseNotes.append("<p>");
107 releaseNotes.append(issue.getKey());
108 releaseNotes.append(": ");
109 releaseNotes.append(issue.getSummary());
110 releaseNotes.append("</p>");
111 }
112 restClient.close();
113 return releaseNotes.toString();
114 }
115
116 private DefaultMarketplaceClient initializeMpacClient()
117 {
118 final HttpConfiguration myHttpConfiguration = HttpConfiguration.builder()
119 .username(mpacCredentials.getUserName())
120 .password(mpacCredentials.getPassword().toString())
121 .connectTimeoutMillis(300000)
122 .build();
123 final URI serverURI = releaseProperties.isReleaseProduction() ? MPAC_PRODUCTION_SERVER_URI : MPAC_STAGING_SERVER_URI;
124 final DefaultMarketplaceClient defaultMarketplaceClient = new DefaultMarketplaceClient(serverURI, myHttpConfiguration);
125 return defaultMarketplaceClient;
126 }
127
128 private void releaseNewPluginVersion(final SDKPlugin sdkPlugin) throws MpacException, IOException
129 {
130 final Option<Plugin> sdkPlugins = mpacClient.plugins().get(PluginDetailQuery.builder(sdkPlugin.getName()).build());
131 final Plugin sdk = sdkPlugins.get();
132 final PluginVersion latestPluginVersion = sdk.getVersion();
133 if (!version.equals(latestPluginVersion.getVersion()))
134 {
135 if(StringUtils.isEmpty(releaseNotes))
136 {
137 try
138 {
139 releaseNotes = initializeReleaseNotes(releaseProperties.getAMPSLatestVersion(),
140 releaseProperties.getAMPSCurrentVersion(),
141 latestPluginVersion.getVersion(),
142 version);
143 }catch(IOException io)
144 {
145 throw new IOException("Could not generate release notes, please check your Ecosystem again", io);
146 }
147 }
148 LOG.debug("Create new version for plugin: " + sdkPlugin.getName() + " - binary URI: " + sdkPlugin.getBinaryURI());
149 LOG.debug("Release summary:\n " + releaseSummary());
150 LOG.debug("Release notes:\n " + releaseNotes);
151 PluginVersionUpdate newVersionData = PluginVersionUpdate.newVersion(
152 sdkPlugin.getName(),
153 latestPluginVersion.getBuildNumber() + 10,
154 version,
155 PluginVersionUpdate.Deployment
156 .nonDeployable(URI.create(sdkPlugin.getBinaryURI())),
157 LicenseIdentifier.ASL
158 ).summary(Option.some(releaseSummary()))
159 .releaseNotes(Option.some(releaseNotes))
160 .build();
161 mpacClient.plugins().putVersion(newVersionData);
162 }
163 }
164
165 private String releaseSummary()
166 {
167 return MessageFormat.format(releaseProperties.getReleaseSummary(),
168 version,
169 releaseProperties.getAMPSCurrentVersion());
170 }
171
172 public static class MpacPublisherBuilder
173 {
174 private PasswordAuthentication mpacCredentials;
175 private PasswordAuthentication ecoCredentials;
176 private String version;
177
178 private MpacPublisherBuilder()
179 {
180 }
181
182 public static MpacPublisherBuilder aMpacPublisher()
183 {
184 return new MpacPublisherBuilder();
185 }
186
187 public MpacPublisherBuilder mpacCredentials(PasswordAuthentication mpacCredentials)
188 {
189 this.mpacCredentials = mpacCredentials;
190 return this;
191 }
192
193 public MpacPublisherBuilder ecoCredentials(PasswordAuthentication ecoCredentials)
194 {
195 this.ecoCredentials = ecoCredentials;
196 return this;
197 }
198
199 public MpacPublisherBuilder version(String version)
200 {
201 this.version = version;
202 return this;
203 }
204
205 public MpacPublisherBuilder but()
206 {
207 return aMpacPublisher().mpacCredentials(mpacCredentials).ecoCredentials(ecoCredentials).version(version);
208 }
209
210 public MpacPublisher build() throws IOException
211 {
212 MpacPublisher mpacPublisher = new MpacPublisher(mpacCredentials, ecoCredentials, version);
213 return mpacPublisher;
214 }
215 }
216 }