Skip to content

Commit

Permalink
Merge pull request #2141 from jenkinsci/JENKINS-33662
Browse files Browse the repository at this point in the history
[FIXED JENKINS-33662] upgrade wizard step #0
  • Loading branch information
kohsuke committed Mar 22, 2016
2 parents c4fb608 + b4f2840 commit c3e33df
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 0 deletions.
26 changes: 26 additions & 0 deletions core/src/main/java/jenkins/install/SetupWizard.java
@@ -1,5 +1,26 @@
package jenkins.install;

import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import hudson.util.VersionNumber;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import hudson.BulkChange;
import hudson.FilePath;
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy;
Expand Down Expand Up @@ -128,6 +149,11 @@ public HttpResponse doCompleteInstall() throws IOException, ServletException {
PluginServletFilter.removeFilter(FORCE_SETUP_WIZARD_FILTER);
// Also, clean up the setup wizard if it's completed
jenkins.setSetupWizard(null);

UpgradeWizard uw = jenkins.getInjector().getInstance(UpgradeWizard.class);
if (uw!=null)
uw.setCurrentLevel(new VersionNumber("2.0"));

return HttpResponses.okJSON();
}

Expand Down
147 changes: 147 additions & 0 deletions core/src/main/java/jenkins/install/UpgradeWizard.java
@@ -0,0 +1,147 @@
package jenkins.install;

import hudson.Extension;
import hudson.model.PageDecorator;
import hudson.model.UpdateSite.Plugin;
import hudson.util.HttpResponses;
import hudson.util.VersionNumber;
import jenkins.model.Jenkins;
import org.apache.commons.io.FileUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.interceptor.RequirePOST;

import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import static java.util.logging.Level.*;
import static org.apache.commons.io.FileUtils.*;
import static org.apache.commons.lang.StringUtils.*;

/**
* This is a stop-gap measure until JENKINS-33663 comes in.
* This call may go away. Please don't use it from outside.
*
* @author Kohsuke Kawaguchi
*/
@Restricted(NoExternalUse.class)
@Extension
public class UpgradeWizard extends PageDecorator {
@Inject
private Jenkins jenkins;

/**
* Is this instance fully upgraded?
*/
private volatile boolean upToDate;

/**
* File that captures the state of upgrade.
*
* This file records the vesrion number that the installation has upgraded to.
*/
/*package*/ File getStateFile() {
return new File(Jenkins.getInstance().getRootDir(),"upgraded");
}

public UpgradeWizard() throws IOException {
updateUpToDate();
}

private void updateUpToDate() throws IOException {
upToDate = new VersionNumber("2.0").compareTo(getCurrentLevel()) <= 0;
}

/**
* What is the version the upgrade wizard has run the last time and upgraded to?
*/
private VersionNumber getCurrentLevel() throws IOException {
VersionNumber from = new VersionNumber("1.0");
File state = getStateFile();
if (state.exists()) {
from = new VersionNumber(defaultIfBlank(readFileToString(state), "1.0").trim());
}
return from;
}

/*package*/
public void setCurrentLevel(VersionNumber v) throws IOException {
FileUtils.writeStringToFile(getStateFile(), v.toString());
updateUpToDate();
}

/**
* Do we need to show the upgrade wizard prompt?
*/
public boolean isDue() {
if (upToDate)
return false;

// only admin users should see this
if (!jenkins.hasPermission(Jenkins.ADMINISTER))
return false;

return System.currentTimeMillis() > getStateFile().lastModified();
}

/**
* Snooze the upgrade wizard notice.
*/
@RequirePOST
public HttpResponse doSnooze() throws IOException {
jenkins.checkPermission(Jenkins.ADMINISTER);
File f = getStateFile();
FileUtils.touch(f);
f.setLastModified(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1));
LOGGER.log(FINE, "Snoozed the upgrade wizard notice");
return HttpResponses.redirectToContextRoot();
}

/**
* Performs the upgrade activity.
*/
@RequirePOST
public HttpResponse doUpgrade() throws IOException {
jenkins.checkPermission(Jenkins.ADMINISTER);
try {
if (new VersionNumber("2.0").compareTo(getCurrentLevel())>0) {
// 1.0 -> 2.0 upgrade
LOGGER.log(WARNING, "Performing 1.0 to 2.0 upgrade");

for (String shortName : Arrays.asList("workflow-aggregator", "pipeline-stage-view", "github-organization-folder")) {
Plugin p = jenkins.getUpdateCenter().getPlugin(shortName);
if (p==null) {
LOGGER.warning("Plugin not found in the update center: " + shortName);
} else {
p.deploy(true);
}
}

// upgrade to 2.0 complete (if plugin installations fail, that's too bad)
FileUtils.writeStringToFile(getStateFile(),"2.0");

// send the user to the update center so that people can see the installation & restart if need be.
return HttpResponses.redirectViaContextPath("updateCenter/");
}

// in the future...
// if (new VersionNumber("3.0").compareTo(getCurrentLevel())>0) {
//
// }

return NOOP;
} finally {
updateUpToDate();
}
}

/*package*/ static final HttpResponse NOOP = HttpResponses.redirectToContextRoot();


private static final Logger LOGGER = Logger.getLogger(UpgradeWizard.class.getName());
}
49 changes: 49 additions & 0 deletions core/src/main/resources/jenkins/install/UpgradeWizard/footer.jelly
@@ -0,0 +1,49 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<j:if test="${it.due}">
<style>
#upgrade-fragment {
background-color: #fce94f;
}

#upgrade-notice {
font-weight: bold;
text-align: center;
font-size: 20px;
height: 60px;

display: flex;
justify-content: center;
align-items: center;
}

#upgrade-snooze {
float:right;
margin: 3px;
text-decoration: none;
display: block;
}
</style>
<div style="display:none">
<div id="upgrade-fragment">
<a id="upgrade-snooze" class="post" href="${rootURL}/${it.url}/snooze">
x
</a>
<div id="upgrade-notice">
<div>
<j:whitespace>${%msg.before}</j:whitespace>
<f:link href="${rootURL}/${it.url}/upgrade" post="true">${%msg.link}</f:link>
<j:whitespace>${%msg.after}</j:whitespace>
</div>
</div>
</div>
</div>
<script>
(function() {
var e = $('upgrade-fragment');
e.remove();
$('page-body').insert({ top: e });
})();
</script>
</j:if>
</j:jelly>
@@ -0,0 +1,3 @@
msg.before=Welcome to Jenkins v2!\u0020
msg.link=Click here to install the rest of v2 functionalities
msg.after=\u0020and finish the upgrade process
86 changes: 86 additions & 0 deletions test/src/test/java/jenkins/install/UpgradeWizardTest.java
@@ -0,0 +1,86 @@
package jenkins.install;

import hudson.util.VersionNumber;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import javax.inject.Inject;

import java.io.IOException;

import static org.junit.Assert.*;

/**
* @author Kohsuke Kawaguchi
*/
public class UpgradeWizardTest {
@Rule
public final JenkinsRule j = new JenkinsRule();

@Inject
UpgradeWizard uw;

@Before
public void setup() {
j.jenkins.getInjector().injectMembers(this);
}

@Test
public void snooze() throws Exception {
assertTrue(uw.isDue());
uw.doSnooze();
assertFalse(uw.isDue());
}

/**
* If not upgraded, the upgrade should cause some side effect.
*/
@Test
public void upgrade() throws Exception {
assertTrue(j.jenkins.getUpdateCenter().getJobs().size() == 0);
assertTrue(newInstance().isDue());
assertNotSame(UpgradeWizard.NOOP, uw.doUpgrade());

// can't really test this because UC metadata is empty
// assertTrue(j.jenkins.getUpdateCenter().getJobs().size() > 0);
}

/**
* If already upgraded, don't show anything
*/
@Test
public void fullyUpgraded() throws Exception {
FileUtils.writeStringToFile(uw.getStateFile(), "2.0");
assertFalse(newInstance().isDue());
assertSame(UpgradeWizard.NOOP, uw.doUpgrade());
}

/**
* If downgraded from future version, don't prompt upgrade wizard.
*/
@Test
public void downgradeFromFuture() throws Exception {
FileUtils.writeStringToFile(uw.getStateFile(), "3.0");
assertFalse(newInstance().isDue());
assertSame(UpgradeWizard.NOOP, uw.doUpgrade());
}

@Test
public void freshInstallation() throws Exception {
assertTrue(uw.isDue());
uw.setCurrentLevel(new VersionNumber("2.0"));
assertFalse(uw.isDue());
}

/**
* Fresh instance of {@link UpgradeWizard} to test its behavior.
*/
private UpgradeWizard newInstance() throws IOException {
UpgradeWizard uw2 = new UpgradeWizard();
j.jenkins.getInjector().injectMembers(uw2);
return uw2;
}
}

0 comments on commit c3e33df

Please sign in to comment.