diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..4efa5281 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,10 @@ +# This configuration file was automatically generated by Gitpod. +# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) +# and commit this file to your remote git repository to share the goodness with others. + +# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart + +tasks: + - init: mvn install -DskipTests=false + + diff --git a/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/CliOptions.java b/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/CliOptions.java index bcfe0bd3..b1f96f09 100644 --- a/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/CliOptions.java +++ b/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/CliOptions.java @@ -1,5 +1,4 @@ package io.jenkins.tools.pluginmanager.cli; - import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -73,7 +72,7 @@ class CliOptions { handler = BooleanOptionHandler.class) private boolean showAvailableUpdates; - @Option(name = "--output", usage = "Output format for available updates", aliases = "-o") + @Option(name = "--output", usage = "Output format for available updates", aliases = "-o") private OutputFormat outputFormat = OutputFormat.STDOUT; /** @@ -155,6 +154,8 @@ class CliOptions { handler = MultiCredentialsOptionHandler.class) private List credentials; + + /** * Creates a configuration class with configurations specified from the CLI and/or environment variables. * @@ -272,6 +273,9 @@ private String getJenkinsWar() { private List getPlugins() { PluginListParser pluginParser = new PluginListParser(verbose); List requestedPlugins = new ArrayList<>(pluginParser.parsePluginsFromCliOption(plugins)); + for(Plugin plugin:requestedPlugins){ + logVerbose(plugin.getName()+" Added By Mukund "); + } File pluginFile = getPluginFile(); if (pluginFile != null) { @@ -427,10 +431,10 @@ private URL getIncrementalsMirror() { try { jenkinsIncrementalsRepo = new URL(System.getenv("JENKINS_INCREMENTALS_REPO_MIRROR")); } catch (MalformedURLException e) { - /* Spotbugs 4.7.0 warns when throwing a runtime exception, - * but the program cannot do anything with a malformed URL. - * Spotbugs warning is ignored. - */ + /* Spotbugs 4.7.0 warns when throwing a runtime exception, + * but the program cannot do anything with a malformed URL. + * Spotbugs warning is ignored. + */ throw new RuntimeException(e); } @@ -509,6 +513,13 @@ public boolean isShowHelp() { return showHelp; } + /** + * Shows if the version was made by mukund + */ + public boolean isVersionMadeBy() { + return true; + } + /** * Returns the boolean corresponding to if user wants dependencies of plugins with latest version specified to also * be the latest version diff --git a/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/Main.java b/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/Main.java index 9285052b..9534822c 100644 --- a/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/Main.java +++ b/plugin-management-cli/src/main/java/io/jenkins/tools/pluginmanager/cli/Main.java @@ -42,6 +42,7 @@ public static void main(String[] args) throws IOException { return; } + Config cfg = options.setup(); try (PluginManager pm = new PluginManager(cfg)) { if (options.isShowAvailableUpdates()) { diff --git a/plugin-management-library/plugins.yaml b/plugin-management-library/plugins.yaml new file mode 100644 index 00000000..bc9b0825 --- /dev/null +++ b/plugin-management-library/plugins.yaml @@ -0,0 +1,6 @@ +plugins: + - artifactId: git + source: + url: file:///usr/share/jenkins/ref/plugins/git-4.8.2_CMT.hpi + - artifactId: junit + - artifactId: javadoc \ No newline at end of file diff --git a/plugin-management-library/pom.xml b/plugin-management-library/pom.xml index d2bc0d25..eff05b85 100644 --- a/plugin-management-library/pom.xml +++ b/plugin-management-library/pom.xml @@ -71,6 +71,29 @@ snakeyaml 2.0 + + org.hamcrest + hamcrest-core + 2.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.9.2 + test + + + org.junit.vintage + junit-vintage-engine + 5.9.2 + test + + + org.mockito + mockito-core + test + com.github.spotbugs spotbugs-annotations diff --git a/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/Plugin.java b/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/Plugin.java index 169d6eec..3d28f5b9 100644 --- a/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/Plugin.java +++ b/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/Plugin.java @@ -34,6 +34,7 @@ public Plugin(String name, String version, String url, String groupId) { } this.version = new VersionNumber(version); this.url = url; + this.dependencies = new ArrayList<>(); this.parent = this; this.groupId = groupId; diff --git a/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/PluginManager.java b/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/PluginManager.java index c5be5a14..7bead609 100644 --- a/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/PluginManager.java +++ b/plugin-management-library/src/main/java/io/jenkins/tools/pluginmanager/impl/PluginManager.java @@ -121,7 +121,7 @@ public class PluginManager implements Closeable { private static final int DEFAULT_MAX_RETRIES = 3; private static final String MIRROR_FALLBACK_BASE_URL = "https://archives.jenkins.io/"; - + //See how the cfg files work @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "we want the user to be able to specify a path") public PluginManager(Config cfg) { this.cfg = cfg; @@ -151,7 +151,7 @@ private String getUserAgentInformation() { Properties properties = new Properties(); try (InputStream propertiesStream = this.getClass().getClassLoader().getResourceAsStream("version.properties")) { properties.load(propertiesStream); - userAgentInformation = "JenkinsPluginManager/" + properties.getProperty("project.version"); + userAgentInformation = "JenkinsPluginManager/" + properties.getProperty("project.version"); } catch (IOException e) { logVerbose("Not able to load/detect version.properties file"); } @@ -167,16 +167,16 @@ private String getUserAgentInformation() { private HttpClient getHttpClient() { if (httpClient == null) { RequestConfig globalConfig = RequestConfig.custom() - .setCookieSpec(CookieSpecs.STANDARD) // use modern cookie policy (RFC 6265) - .build(); + .setCookieSpec(CookieSpecs.STANDARD) // use modern cookie policy (RFC 6265) + .build(); httpClient = HttpClients.custom().useSystemProperties() - // there is a more complex retry handling in downloadToFile(...) on the whole flow - // this affects only the single request - .setRetryHandler(new DefaultHttpRequestRetryHandler(DEFAULT_MAX_RETRIES, true)) - .setConnectionManager(new PoolingHttpClientConnectionManager()) - .setUserAgent(userAgentInformation) - .setDefaultRequestConfig(globalConfig) - .build(); + // there is a more complex retry handling in downloadToFile(...) on the whole flow + // this affects only the single request + .setRetryHandler(new DefaultHttpRequestRetryHandler(DEFAULT_MAX_RETRIES, true)) + .setConnectionManager(new PoolingHttpClientConnectionManager()) + .setUserAgent(userAgentInformation) + .setDefaultRequestConfig(globalConfig) + .build(); } return httpClient; } @@ -242,7 +242,10 @@ public void start(boolean downloadUc) { if (cfg.doDownload()) { downloadPlugins(pluginsToBeDownloaded); } - logMessage("Done"); + String noPlugins = "No new plugins"; + if(cfg.getPlugins().isEmpty()) + logVerbose(noPlugins); + } void createPluginDir(boolean failIfExists) { @@ -361,7 +364,8 @@ private void logPlugins(String description, List plugins) { /** * Generate plugin list in the format requested by the user and output to standard out. - * @param plugins plugins to include in the list + * + * @param plugins plugins to include in the list * @param stdOutConverter if the output format is STDOUT, use the supplied converter. */ public void outputPluginList(@NonNull List plugins, @NonNull Supplier stdOutConverter) { @@ -370,7 +374,8 @@ public void outputPluginList(@NonNull List plugins, @NonNull Supplier plugins, @NonNull Supplier stdOutConverter) { @@ -470,7 +475,7 @@ public void showSpecificSecurityWarnings(List plugins) { logMessage(plugin.getSecurityWarnings().stream() .map(warning -> String.format("%s (%s): %s %s %s", pluginName, plugin.getVersion(), warning.getId(), warning.getMessage(), warning.getUrl())). - collect(Collectors.joining("\n"))); + collect(Collectors.joining("\n"))); } } } @@ -479,6 +484,7 @@ public void showSpecificSecurityWarnings(List plugins) { /** * Takes a list of plugins and returns the latest version * Returns existing version if no update + * * @param plugins updated list of plugins * @return latest plugin versions */ @@ -547,7 +553,7 @@ public boolean warningExists(Plugin plugin) { * Checks that required Jenkins version of all plugins to be downloaded is less than the Jenkins version in the * user specified Jenkins war file * - * @param jenkinsVersion the current version of Jenkins + * @param jenkinsVersion the current version of Jenkins * @param pluginsToBeDownloaded list of plugins to check version compatibility with the Jenkins version */ public void checkVersionCompatibility(VersionNumber jenkinsVersion, List pluginsToBeDownloaded) { @@ -558,15 +564,15 @@ public void checkVersionCompatibility(VersionNumber jenkinsVersion, List * Checks that required Jenkins version of all plugins to be downloaded is less than the Jenkins version in the * user specified Jenkins war file * - * @param jenkinsVersion the current version of Jenkins + * @param jenkinsVersion the current version of Jenkins * @param pluginsToBeDownloaded list of plugins to check version compatibility with the Jenkins version - * @param exceptions if not null populated with the list of exception which occurred during this call, otherwise the exception is not caught + * @param exceptions if not null populated with the list of exception which occurred during this call, otherwise the exception is not caught */ public void checkVersionCompatibility(VersionNumber jenkinsVersion, List pluginsToBeDownloaded, @CheckForNull List exceptions) { if (jenkinsVersion != null && !StringUtils.isEmpty(jenkinsVersion.toString())) { for (Plugin p : pluginsToBeDownloaded) { final VersionNumber pluginJenkinsVersion = p.getJenkinsVersion(); - if (pluginJenkinsVersion!= null) { + if (pluginJenkinsVersion != null) { if (pluginJenkinsVersion.isNewerThan(jenkinsVersion)) { VersionCompatibilityException exception = new VersionCompatibilityException( String.format("%n%s (%s) requires a greater version of Jenkins (%s) than %s", @@ -681,7 +687,7 @@ public Map findPluginsAndDependencies(List requestedPlug * versions of the same plugin, the higher version required will replace the lower version dependency * * @param requestedPlugins list of plugins to find all dependencies for - * @param exceptions if not null populated with the list of exception which occurred during this call, otherwise the exception is not caught + * @param exceptions if not null populated with the list of exception which occurred during this call, otherwise the exception is not caught * @return set of all requested plugins and their recursive dependencies */ public Map findPluginsAndDependencies(List requestedPlugins, @CheckForNull List exceptions) { @@ -785,8 +791,8 @@ public void outputPluginReplacementInfo(Plugin lowerVersion, Plugin higherVersio * Gets the json object at the given url * * @param urlString string representing the url from which to get the json object - * @deprecated see {@link #getJson(URL, String)} * @return JSON object from data provided by the URL at urlString + * @deprecated see {@link #getJson(URL, String)} */ @Deprecated public JSONObject getJson(String urlString) { @@ -807,7 +813,7 @@ private URL stringToUrlQuietly(String urlString) { /** * Retrieves JSON from a URL and caches it * - * @param url the url to retrieve json from + * @param url the url to retrieve json from * @param cacheKey a key to use for caching i.e. 'update-center' * @return the JSON */ @@ -823,11 +829,11 @@ public JSONObject getJson(URL url, String cacheKey) { try { if (url.getProtocol().equalsIgnoreCase("http") || url.getProtocol().equalsIgnoreCase("https")) { response = getViaHttpWithResponseHandler( - url.toString(), - new BasicResponseHandler(), - cacheKey, - e -> String.format("Unable to retrieve JSON from %s: %s", url, e.getMessage()), - 3); + url.toString(), + new BasicResponseHandler(), + cacheKey, + e -> String.format("Unable to retrieve JSON from %s: %s", url, e.getMessage()), + 3); } else { response = IOUtils.toString(url, StandardCharsets.UTF_8); } @@ -842,6 +848,7 @@ public JSONObject getJson(URL url, String cacheKey) { /** * Gets update center json, which is later used to determine plugin dependencies and security warnings + * * @param jenkinsVersion the version of Jenkins to use */ public void getUCJson(VersionNumber jenkinsVersion) { @@ -910,7 +917,7 @@ public JSONArray getPluginDependencyJsonArray(Plugin plugin, JSONObject ucJson) * Retrieves the latest available version of a specified plugin. * * @param dependendantPlugin the plugin depending on the given plugin - * @param pluginName the name of the plugin + * @param pluginName the name of the plugin * @return latest version of the specified plugin * @throws IllegalStateException Update Center JSON has not been retrieved yet */ @@ -1133,7 +1140,7 @@ public Map resolveRecursiveDependencies(Plugin plugin, @CheckFor } } else { logVerbose(String.format("Skipping dependency %s:%s and its sub-dependencies, because there is a higher version defined on the top level - %s:%s", - p.getName(), p.getVersion(), pinnedPlugin.getName(), pinnedPlugin.getVersion())); + p.getName(), p.getVersion(), pinnedPlugin.getName(), pinnedPlugin.getVersion())); continue; } } else if (useLatestSpecified && dependency.isLatest() || useLatestAll) { @@ -1146,9 +1153,9 @@ public Map resolveRecursiveDependencies(Plugin plugin, @CheckFor throw e; } logVerbose(String.format( - "%s unable to find optional plugin %s in update center %s. " + - "Ignoring until it becomes required.", e.getOriginatorPluginAndDependencyChain(), - dependencyName, jenkinsUcLatest)); + "%s unable to find optional plugin %s in update center %s. " + + "Ignoring until it becomes required.", e.getOriginatorPluginAndDependencyChain(), + dependencyName, jenkinsUcLatest)); } } @@ -1223,7 +1230,7 @@ public String getPluginDownloadUrl(Plugin plugin) { pluginVersion = Plugin.LATEST; } - String jenkinsUcDownload = System.getenv("JENKINS_UC_DOWNLOAD"); + String jenkinsUcDownload = System.getenv("JENKINS_UC_DOWNLOAD"); String jenkinsUcDownloadUrl = System.getenv("JENKINS_UC_DOWNLOAD_URL"); if (StringUtils.isNotEmpty(pluginUrl)) { urlString = pluginUrl; @@ -1284,7 +1291,7 @@ public boolean downloadToFile(String urlString, Plugin plugin, @CheckForNull Fil boolean success = true; - if(urlString.startsWith("http://") || urlString.startsWith("https://")){ + if (urlString.startsWith("http://") || urlString.startsWith("https://")) { success = downloadHttpToFile(urlString, plugin, pluginFile, maxRetries); if (!success && !urlString.startsWith(MIRROR_FALLBACK_BASE_URL)) { @@ -1293,7 +1300,7 @@ public boolean downloadToFile(String urlString, Plugin plugin, @CheckForNull Fil urlString = appendPathOntoUrl(MIRROR_FALLBACK_BASE_URL, "/plugins", plugin.getName(), plugin.getVersion(), plugin.getName() + ".hpi"); return downloadToFile(urlString, plugin, fileLocation, 1); } - } else if (urlString.startsWith("file://")){ + } else if (urlString.startsWith("file://")) { success = copyLocalFile(urlString, plugin, pluginFile); } @@ -1321,14 +1328,14 @@ public boolean downloadToFile(String urlString, Plugin plugin, @CheckForNull Fil /** * Downloads a plugin from HTTP(s) location * - * @param pluginUrl location to download plugin to. - * @param plugin to download - * @param pluginFile location to store the plugin file. - * If file already exists, it will be overrided. - * @param maxRetries Maximum number of times to retry the download before failing - * @return boolean signifying if plugin was successfully downloaded + * @param pluginUrl location to download plugin to. + * @param plugin to download + * @param pluginFile location to store the plugin file. + * If file already exists, it will be overrided. + * @param maxRetries Maximum number of times to retry the download before failing + * @return boolean signifying if plugin was successfully downloaded */ - protected boolean downloadHttpToFile(String pluginUrl, Plugin plugin, File pluginFile, int maxRetries){ + protected boolean downloadHttpToFile(String pluginUrl, Plugin plugin, File pluginFile, int maxRetries) { try { getViaHttpWithResponseHandler(pluginUrl, new FileDownloadResponseHandler(pluginFile), plugin.getName(), e -> String.format("Unable to resolve plugin URL %s, or download plugin %s to file: %s", pluginUrl, @@ -1394,18 +1401,18 @@ private T getViaHttpWithResponseHandler(String url, ResponseHandler parsePluginYamlFile(File pluginYamlFile) { if (!isURL(url)) { url = null; } + else if(isHpi(url)){ + System.out.println(url+" is a local .hpi file"); + } plugin = new Plugin(name, version, url, groupId); } pluginsFromYaml.add(plugin); @@ -167,7 +170,11 @@ private Plugin parsePluginLine(String pluginLine) { if (pluginInfo.length >= 3) { if (isURL(pluginInfo[2])) { pluginUrl = pluginInfo[2]; - } else { + } + else if(isHpi(pluginUrl)){ + System.out.println(pluginName + " was supplied with a .hpi file"); + } + else { System.err.println("Invalid URL " + pluginInfo[2] + " , will ignore"); } } @@ -182,4 +189,15 @@ public static boolean isURL(String url) { return false; } } + + public static boolean isHpi(String url){ + try{ + if(url.endsWith("hpi")){ + return true; + } + return false; + }catch(Exception notAnHPI){ + return false; + } + } }