Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parameter to change archive repository URL and check Jenkins version against archive repositories #759

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ class CliOptions {
handler = URLOptionHandler.class)
private URL jenkinsIncrementalsRepoMirror;

@Option(name = "--jenkins-archive-repo-mirror",
usage = "Set the custom URL for the Jenkins plugin archive repository, will override " +
"the JENKINS_ARCHIVE_REPO_MIRROR environment variable. If not set via CLI option or " +
"environment variable, will default to " + Settings.DEFAULT_ARCHIVE_REPO_MIRROR_LOCATION,
handler = URLOptionHandler.class)
private URL jenkinsArchiveRepoMirror;

@Option(name = "--jenkins-plugin-info",
usage = "Sets the location of plugin information; will override JENKINS_PLUGIN_INFO environment variable. " +
"If not set via CLI option or environment variable, will default to " +
Expand Down Expand Up @@ -143,6 +150,12 @@ class CliOptions {
handler = ExplicitBooleanOptionHandler.class)
private boolean useLatestAll = true;

@Option(name = "--archive", usage = "Set to true to check archived update center repositories for plugin dependencies metadata first. " +
"If the metadata is found in the archive, it will be used instead of the latest update center metadata. " +
"By default, the latest update center metadata is used.",
handler = ExplicitBooleanOptionHandler.class)
private boolean useArchiveAll = false;

@Option(name = "--help", aliases = {"-h"}, help = true)
private boolean showHelp;

Expand All @@ -168,6 +181,7 @@ Config setup() {
.withJenkinsUc(getUpdateCenter())
.withJenkinsUcExperimental(getExperimentalUpdateCenter())
.withJenkinsIncrementalsRepoMirror(getIncrementalsMirror())
.withJenkinsArchiveRepoMirror(getArchiveMirror())
.withJenkinsPluginInfo(getPluginInfo())
.withJenkinsVersion(getJenkinsVersion())
.withJenkinsWar(getJenkinsWar())
Expand All @@ -181,6 +195,7 @@ Config setup() {
.withDoDownload(!isNoDownload())
.withUseLatestSpecified(isUseLatestSpecified())
.withUseLatestAll(isUseLatestAll())
.withUseArchiveAll(isUseArchiveAll())
.withSkipFailedPlugins(isSkipFailedPlugins())
.withCredentials(credentials)
.withHashFunction(getHashFunction())
Expand Down Expand Up @@ -444,6 +459,34 @@ private URL getIncrementalsMirror() {
return jenkinsIncrementalsRepo;
}

/**
* Determines the archive repository mirror URL. If a value is set via CLI option, it will override a
* value set via environment variable. If neither are set, the default in the Settings class will be used.
*
* @return the archive repository mirror URL
*/
private URL getArchiveMirror() {
URL archiveRepoMirror;
String archiveRepoEnv = System.getenv("JENKINS_ARCHIVE_REPO_MIRROR");
if (jenkinsArchiveRepoMirror != null) {
archiveRepoMirror = jenkinsArchiveRepoMirror;
logVerbose("Using archive repository mirror " + archiveRepoMirror + " specified with CLI option");
} else if (!StringUtils.isEmpty(archiveRepoEnv)) {
try {
archiveRepoMirror = new URL(archiveRepoEnv);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
logVerbose("Using archive repository mirror " + archiveRepoMirror +
" from JENKINS_ARCHIVE_REPO_MIRROR environment variable");
} else {
archiveRepoMirror = Settings.DEFAULT_ARCHIVE_REPO_MIRROR;
logVerbose("No CLI option or environment variable set for archive repository mirror, using default of " +
archiveRepoMirror);
}
return archiveRepoMirror;
}

/**
* Determines the plugin information url string. If a value is set via CLI option, it will override a value
* set via environment variable. If neither are set, the default in the Settings class will be used.
Expand Down Expand Up @@ -542,6 +585,17 @@ public boolean isUseLatestAll() {
return useLatestAll;
}

/**
* Returns whether the user wants to check archived update center repositories for plugin dependencies metadata first.
* If the metadata is found in the archive, it will be used instead of the latest update center metadata.
* This flag takes precedence over the latest versions preference.
*
* @return true if the user wants to check archived repositories first, false otherwise
*/
public boolean isUseArchiveAll() {
return useArchiveAll;
}

// visible for testing
public InputStream getPropertiesInputStream(String path) {
return this.getClass().getResourceAsStream(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;


public class CliOptionsTest {
private CliOptions options;
private CmdLineParser parser;
Expand Down Expand Up @@ -77,6 +76,7 @@ public void setupDefaultsTest() throws Exception {
assertThat(cfg.isShowAllWarnings()).isFalse();
assertThat(cfg.isShowWarnings()).isFalse();
assertThat(cfg.isHideWarnings()).isFalse();
assertThat(cfg.isUseArchiveAll()).isFalse();
assertThat(cfg.getJenkinsUc()).hasToString(Settings.DEFAULT_UPDATE_CENTER_LOCATION);
assertThat(cfg.getJenkinsUcExperimental()).hasToString(Settings.DEFAULT_EXPERIMENTAL_UPDATE_CENTER_LOCATION);
assertThat(cfg.getJenkinsIncrementalsRepoMirror()).hasToString(Settings.DEFAULT_INCREMENTALS_REPO_MIRROR_LOCATION);
Expand Down Expand Up @@ -197,23 +197,27 @@ public void setupUpdateCenterCliTest() throws Exception {
String ucEnvVar = "https://updates.jenkins.io/env";
String experimentalUcEnvVar = "https://updates.jenkins.io/experimental/env";
String incrementalsEnvVar = "https://repo.jenkins-ci.org/incrementals/env";
String archiveEnvVar = "https://mirrors.jenkins-ci.org/archive/env";
String pluginInfoEnvVar = "https://updates.jenkins.io/current/plugin-versions/env";

String ucCli = "https://updates.jenkins.io/cli";
String experiementalCli = "https://updates.jenkins.io/experimental/cli";
String incrementalsCli = "https://repo.jenkins-ci.org/incrementals/cli";
String archiveCli = "https://mirrors.jenkins-ci.org/archive/cli";
String pluginInfoCli = "https://updates.jenkins.io/current/plugin-versions/cli";

parser.parseArgument("--jenkins-update-center", ucCli,
"--jenkins-experimental-update-center", experiementalCli,
"--jenkins-incrementals-repo-mirror", incrementalsCli,
"--jenkins-archive-repo-mirror", archiveCli,
"--jenkins-plugin-info", pluginInfoCli);

Config cfg = options.setup();

assertThat(cfg.getJenkinsUc()).hasToString(ucCli + "/update-center.json");
assertThat(cfg.getJenkinsUcExperimental()).hasToString(experiementalCli + "/update-center.json");
assertThat(cfg.getJenkinsIncrementalsRepoMirror()).hasToString(incrementalsCli);
assertThat(cfg.getJenkinsArchiveRepoMirror()).hasToString(archiveCli);
assertThat(cfg.getJenkinsPluginInfo()).hasToString(pluginInfoCli);
}

Expand Down Expand Up @@ -303,6 +307,20 @@ public void useNotLatestTest() throws CmdLineException {
assertThat(cfg.isUseLatestAll()).isFalse();
}

@Test
public void useArchiveTest() throws CmdLineException {
parser.parseArgument("--archive");
Config cfg = options.setup();
assertThat(cfg.isUseArchiveAll()).isTrue();
}

@Test
public void useNotArchiveTest() throws CmdLineException {
parser.parseArgument("--archive", "false");
Config cfg = options.setup();
assertThat(cfg.isUseArchiveAll()).isFalse();
}

@Test
public void useLatestSpecifiedAndLatestAllTest() throws CmdLineException {
parser.parseArgument("--latest", "--latest-specified");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ public class Config {
private final URL jenkinsUc;
private final URL jenkinsUcExperimental;
private final URL jenkinsIncrementalsRepoMirror;
private final URL jenkinsArchiveRepoMirror;
private final URL jenkinsPluginInfo;
private final boolean doDownload;
private final boolean useLatestSpecified;
private final boolean useLatestAll;
private final boolean useArchiveAll;
private final boolean skipFailedPlugins;
@NonNull
private final OutputFormat outputFormat;
Expand All @@ -71,10 +73,12 @@ private Config(
URL jenkinsUc,
URL jenkinsUcExperimental,
URL jenkinsIncrementalsRepoMirror,
URL jenkinsArchiveRepoMirror,
URL jenkinsPluginInfo,
boolean doDownload,
boolean useLatestSpecified,
boolean useLatestAll,
boolean useArchiveAll,
boolean skipFailedPlugins,
OutputFormat outputFormat,
HashFunction hashFunction,
Expand All @@ -94,10 +98,12 @@ private Config(
this.jenkinsUc = jenkinsUc;
this.jenkinsUcExperimental = jenkinsUcExperimental;
this.jenkinsIncrementalsRepoMirror = jenkinsIncrementalsRepoMirror;
this.jenkinsArchiveRepoMirror = jenkinsArchiveRepoMirror;
this.jenkinsPluginInfo = jenkinsPluginInfo;
this.doDownload = doDownload;
this.useLatestSpecified = useLatestSpecified;
this.useLatestAll = useLatestAll;
this.useArchiveAll = useArchiveAll;
this.skipFailedPlugins = skipFailedPlugins;
this.outputFormat = outputFormat;
this.credentials = credentials;
Expand Down Expand Up @@ -160,6 +166,10 @@ public URL getJenkinsIncrementalsRepoMirror() {
return jenkinsIncrementalsRepoMirror;
}

public URL getJenkinsArchiveRepoMirror() {
return jenkinsArchiveRepoMirror;
}

public URL getJenkinsPluginInfo() {
return jenkinsPluginInfo;
}
Expand All @@ -184,6 +194,8 @@ public boolean isUseLatestSpecified() {

public boolean isUseLatestAll() { return useLatestAll; }

public boolean isUseArchiveAll() { return useArchiveAll; }

public boolean isSkipFailedPlugins() {
return skipFailedPlugins;
}
Expand Down Expand Up @@ -228,10 +240,12 @@ public static class Builder {
private URL jenkinsUc = Settings.DEFAULT_UPDATE_CENTER;
private URL jenkinsUcExperimental = Settings.DEFAULT_EXPERIMENTAL_UPDATE_CENTER;
private URL jenkinsIncrementalsRepoMirror = Settings.DEFAULT_INCREMENTALS_REPO_MIRROR;
private URL jenkinsArchiveRepoMirror = Settings.DEFAULT_ARCHIVE_REPO_MIRROR;
private URL jenkinsPluginInfo = Settings.DEFAULT_PLUGIN_INFO;
private boolean doDownload;
private boolean useLatestSpecified;
private boolean useLatestAll;
private boolean useArchiveAll;
private boolean skipFailedPlugins;
private OutputFormat outputFormat = OutputFormat.STDOUT;
private List<Credentials> credentials = Collections.emptyList();
Expand Down Expand Up @@ -317,6 +331,11 @@ public Builder withJenkinsIncrementalsRepoMirror(URL jenkinsIncrementalsRepoMirr
return this;
}

public Builder withJenkinsArchiveRepoMirror(URL jenkinsArchiveRepoMirror) {
this.jenkinsArchiveRepoMirror = jenkinsArchiveRepoMirror;
return this;
}

public Builder withJenkinsPluginInfo(URL jenkinsPluginInfo) {
this.jenkinsPluginInfo = jenkinsPluginInfo;
return this;
Expand All @@ -337,6 +356,11 @@ public Builder withUseLatestAll(boolean useLatestAll) {
return this;
}

public Builder withUseArchiveAll(boolean useArchiveAll) {
this.useArchiveAll = useArchiveAll;
return this;
}

public Builder withSkipFailedPlugins(boolean skipFailedPlugins) {
this.skipFailedPlugins = skipFailedPlugins;
return this;
Expand Down Expand Up @@ -383,10 +407,12 @@ public Config build() {
jenkinsUc,
jenkinsUcExperimental,
jenkinsIncrementalsRepoMirror,
jenkinsArchiveRepoMirror,
jenkinsPluginInfo,
doDownload,
useLatestSpecified,
useLatestAll,
useArchiveAll,
skipFailedPlugins,
outputFormat,
hashFunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class Settings {
public static final String DEFAULT_EXPERIMENTAL_UPDATE_CENTER_LOCATION = "https://updates.jenkins.io/experimental" + DEFAULT_UPDATE_CENTER_FILENAME;
public static final URL DEFAULT_INCREMENTALS_REPO_MIRROR;
public static final String DEFAULT_INCREMENTALS_REPO_MIRROR_LOCATION = "https://repo.jenkins-ci.org/incrementals";
public static final URL DEFAULT_ARCHIVE_REPO_MIRROR;
public static final String DEFAULT_ARCHIVE_REPO_MIRROR_LOCATION = "https://archives.jenkins.io/";
public static final URL DEFAULT_PLUGIN_INFO;
public static final String DEFAULT_PLUGIN_INFO_LOCATION = "https://updates.jenkins.io/plugin-versions.json";
public static final Path DEFAULT_CACHE_PATH;
Expand All @@ -45,6 +47,7 @@ public class Settings {
DEFAULT_UPDATE_CENTER = new URL(DEFAULT_UPDATE_CENTER_LOCATION);
DEFAULT_EXPERIMENTAL_UPDATE_CENTER = new URL(DEFAULT_EXPERIMENTAL_UPDATE_CENTER_LOCATION);
DEFAULT_INCREMENTALS_REPO_MIRROR = new URL(DEFAULT_INCREMENTALS_REPO_MIRROR_LOCATION);
DEFAULT_ARCHIVE_REPO_MIRROR = new URL(DEFAULT_ARCHIVE_REPO_MIRROR_LOCATION);
DEFAULT_PLUGIN_INFO = new URL(DEFAULT_PLUGIN_INFO_LOCATION);
} catch (MalformedURLException e) {
/* Spotbugs 4.7.0 warns when throwing a runtime exception,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import static io.jenkins.tools.pluginmanager.util.PluginManagerUtils.dirName;
import static io.jenkins.tools.pluginmanager.util.PluginManagerUtils.removePath;
import static io.jenkins.tools.pluginmanager.util.PluginManagerUtils.removePossibleWrapperText;
import static io.jenkins.tools.pluginmanager.util.PluginManagerUtils.resolveArchiveUpdateCenterUrl;

public class PluginManager implements Closeable {
private static final VersionNumber LATEST = new VersionNumber(Plugin.LATEST);
Expand Down Expand Up @@ -120,7 +121,6 @@ public class PluginManager implements Closeable {
private final LogOutput logOutput;

private static final int DEFAULT_MAX_RETRIES = 3;
private static final String MIRROR_FALLBACK_BASE_URL = "https://archives.jenkins.io/";

@SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "we want the user to be able to specify a path")
public PluginManager(Config cfg) {
Expand Down Expand Up @@ -853,7 +853,25 @@ public void getUCJson(VersionNumber jenkinsVersion) {

String cacheSuffix = getCacheSuffix(jenkinsVersion);
try {
URIBuilder uriBuilder = new URIBuilder(cfg.getJenkinsUc().toURI());

URL ucUrl = cfg.getJenkinsUc();

if (cfg.isUseArchiveAll()) {
URL archiveUcUrl = resolveArchiveUpdateCenterUrl(cacheSuffix, cfg.getJenkinsArchiveRepoMirror());
if (archiveUcUrl != null) {
ucUrl = archiveUcUrl;
} else {
logVerbose("No valid archive repository found for version " + jenkinsVersion + ". Falling back to the default repository.");
}
}

if (ucUrl == null) {
throw new IllegalStateException("No valid update center URL found for version " + jenkinsVersion);
}

URI ucUri = ucUrl.toURI();

URIBuilder uriBuilder = new URIBuilder(ucUri);
if (jenkinsVersion != null) {
uriBuilder.addParameter("version", jenkinsVersion.toString()).build();
}
Expand Down Expand Up @@ -1305,10 +1323,10 @@ public boolean downloadToFile(String urlString, Plugin plugin, @CheckForNull Fil
if(urlString.startsWith("http://") || urlString.startsWith("https://")){
success = downloadHttpToFile(urlString, plugin, pluginFile, maxRetries);

if (!success && !urlString.startsWith(MIRROR_FALLBACK_BASE_URL)) {
logMessage("Downloading from mirrors failed, falling back to " + MIRROR_FALLBACK_BASE_URL);
if (!success && !urlString.startsWith(cfg.getJenkinsArchiveRepoMirror().toString())) {
logMessage("Downloading from mirrors failed, falling back to " + cfg.getJenkinsArchiveRepoMirror().toString());
// as fallback try to directly download from Jenkins server (only if mirrors fail)
urlString = appendPathOntoUrl(MIRROR_FALLBACK_BASE_URL, "/plugins", plugin.getName(), plugin.getVersion(), plugin.getName() + ".hpi");
urlString = appendPathOntoUrl(cfg.getJenkinsArchiveRepoMirror().toString(), "/plugins", plugin.getName(), plugin.getVersion(), plugin.getName() + ".hpi");
return downloadToFile(urlString, plugin, fileLocation, 1);
}
} else if (urlString.startsWith("file://")){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.jenkins.tools.pluginmanager.util;

public class InvalidUrlException extends RuntimeException {
public InvalidUrlException(String message) {
super(message);
}

public InvalidUrlException(String message, Throwable cause) {
super(message, cause);
}
}
Loading
Loading