提交 92c81e6a 编写于 作者: K Kohsuke Kawaguchi

Merge remote-tracking branch 'origin/master' into symbol

......@@ -55,8 +55,84 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
</ul>
</div><!--=TRUNK-END=-->
<h3><a name=v2.1>What's new in 2.1</a> (2016/05/01)</h3>
<ul class=image>
<li class="major bug">
Enable disabled dependencies during plugin installations.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34494">issue 34494</a>)
<li class="major bug">
Force ordering between GPG and jarsigner to ensure correct GPG signature.
(<a href="https://github.com/jenkinsci/jenkins/pull/2285">pull 2285</a>)
<li class="major bug">
Secured Jenkins installations didn't properly safe the queue on shutdown.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34281">issue 34281</a>)
<li class="rfe">
Add dependency resolution to manually uploaded plugins.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-15057">issue 15057</a>)
<li class="rfe">
Show Jenkins version on setup wizard.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33535">issue 33535</a>)
<li class="rfe">
Update remoting to 2.57.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33999">issue 33999</a>)
<li class="rfe">
Allow retrying plugin downloads in setup wizard.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33244">issue 33244</a>)
<li class="rfe">
Add links to homepage of plugins and dependencies in setup wizard.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33936">issue 33936</a>,
<a href="https://issues.jenkins-ci.org/browse/JENKINS-33937">issue 33937</a>)
<li class="rfe">
Improved handling of the 'close' button during setup wizard.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34137">issue 34137</a>)
<li class="rfe">
Wrong spacing in flat mode of 'Create Item' screen.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-31162">issue 31162</a>)
<li class="rfe">
Add timestamp to the <tt>jarsigner</tt> signature.
(<a href="https://github.com/jenkinsci/jenkins/pull/2284">pull 2284</a>)
<li class="rfe">
Improved French translation.
(<a href="https://github.com/jenkinsci/jenkins/pull/2267">pull 2267</a>)
<li class="rfe">
Improved Lithuanian translation.
(<a href="https://github.com/jenkinsci/jenkins/pull/2286">pull 2286</a>)
<li class="rfe">
Improved Brazilian Portuguese translation.
(<a href="https://github.com/jenkinsci/jenkins/pull/2273">pull 2273</a>)
<li class="bug">
Prevent errors when hiding management links.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33683">issue 33683</a>)
<li class="bug">
Internal: Make logger field private.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34093">issue 34093</a>)
<li class="bug">
Shorter timeout for plugin downloads to prevent setup wizard from hanging.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34174">issue 34174</a>)
<li class="bug">
Check if job is buildable before showing 'Build with parameters' page.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34146">issue 34146</a>)
<li class="bug">
Fixed race condition in slave offline cause.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-34448">issue 34448</a>)
<li class="bug">
Allow enabling disabled dependencies in the plugin manager to fix broken configurations.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-32340">issue 32340</a>)
<li class="bug">
Always display clicked scrollspy items as active in setup wizard.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33948">issue 33948</a>)
<li class="bug">
Prevent multiple installations of the same dependency.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-33950">issue 33950</a>)
</ul>
<h3><a name=v2.0>What's new in 2.0</a> (2016/04/20)</h3>
<div style="margin: 10px; padding: 10px; background-color: #FFFFCE;">
<strong>More detailed information about the new features in Jenkins 2.0 <a href="/2.0/">on the overview page</a>.</strong>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.1-SNAPSHOT</version>
<version>2.2-SNAPSHOT</version>
</parent>
<artifactId>cli</artifactId>
......
......@@ -29,7 +29,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.1-SNAPSHOT</version>
<version>2.2-SNAPSHOT</version>
</parent>
<artifactId>jenkins-core</artifactId>
......@@ -39,7 +39,7 @@ THE SOFTWARE.
<properties>
<staplerFork>true</staplerFork>
<stapler.version>1.239</stapler.version>
<stapler.version>1.243</stapler.version>
<spring.version>2.5.6.SEC03</spring.version>
<groovy.version>2.4.6</groovy.version>
</properties>
......
......@@ -431,7 +431,7 @@ public abstract class ExtensionFinder implements ExtensionPoint {
if (verbose) {
LOGGER.log(Level.WARNING, "Failed to instantiate " + key + "; skipping this component", x);
} else {
LOGGER.log(Level.WARNING, "Failed to instantiate optional component {0}; skipping", key.getTypeLiteral());
LOGGER.log(Level.INFO, "Failed to instantiate optional component {0}; skipping", key.getTypeLiteral());
LOGGER.log(Level.FINE, key.toString(), x);
}
}
......
......@@ -109,6 +109,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
......@@ -452,6 +453,14 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
session.addAll(g.discoverTasks(session));
}
});
// All plugins are loaded. Now we can figure out who depends on who.
requires(PLUGINS_PREPARED).attains(COMPLETED).add("Resolving Dependant Plugins Graph", new Executable() {
@Override
public void run(Reactor reactor) throws Exception {
resolveDependantPlugins();
}
});
}});
}
......@@ -660,6 +669,14 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
* TODO: revisit where/how to expose this. This is an experiment.
*/
public void dynamicLoad(File arc) throws IOException, InterruptedException, RestartRequiredException {
dynamicLoad(arc, false);
}
/**
* Try the dynamicLoad, removeExisting to attempt to dynamic load disabled plugins
*/
@Restricted(NoExternalUse.class)
public void dynamicLoad(File arc, boolean removeExisting) throws IOException, InterruptedException, RestartRequiredException {
LOGGER.info("Attempting to dynamic load "+arc);
PluginWrapper p = null;
String sn;
......@@ -670,9 +687,21 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
p = strategy.createPluginWrapper(arc);
sn = p.getShortName();
}
if (getPlugin(sn)!=null)
throw new RestartRequiredException(Messages._PluginManager_PluginIsAlreadyInstalled_RestartRequired(sn));
PluginWrapper pw = getPlugin(sn);
if (pw!=null) {
if (removeExisting) { // try to load disabled plugins
for (Iterator<PluginWrapper> i = plugins.iterator(); i.hasNext();) {
pw = i.next();
if(sn.equals(pw.getShortName())) {
i.remove();
pw = null;
break;
}
}
} else {
throw new RestartRequiredException(Messages._PluginManager_PluginIsAlreadyInstalled_RestartRequired(sn));
}
}
if (p == null) {
p = strategy.createPluginWrapper(arc);
}
......
......@@ -224,6 +224,11 @@ public class WebAppMain implements ServletContextListener {
boolean success = false;
try {
Jenkins instance = new Hudson(_home, context);
// one last check to make sure everything is in order before we go live
if (Thread.interrupted())
throw new InterruptedException();
context.setAttribute(APP, instance);
BootFailure.getBootFailureFile(_home).delete();
......
......@@ -1405,7 +1405,52 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas
}
/**
* Enables a required plugin, provides feedback in the update center
*/
public class EnableJob extends InstallationJob {
public EnableJob(UpdateSite site, Authentication auth, @Nonnull Plugin plugin, boolean dynamicLoad) {
super(plugin, site, auth, dynamicLoad);
}
public Plugin getPlugin() {
return plugin;
}
@Override
public void run() {
try {
plugin.getInstalled().enable();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Failed to enable " + plugin.getDisplayName(), e);
error = e;
}
if (dynamicLoad) {
try {
// remove the existing, disabled inactive plugin to force a new one to load
pm.dynamicLoad(getDestination(), true);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to dynamically load " + plugin.getDisplayName(), e);
error = e;
requiresRestart = true;
}
} else {
requiresRestart = true;
}
}
}
/**
* A no-op, e.g. this plugin is already installed
*/
public class NoOpJob extends EnableJob {
public NoOpJob(UpdateSite site, Authentication auth, @Nonnull Plugin plugin) {
super(site, auth, plugin, false);
}
}
/**
* Base class for a job that downloads a file from the Jenkins project.
*/
......@@ -1575,6 +1620,15 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas
}
}
/**
* Indicates that the plugin was successfully installed.
*/
public class Skipped extends InstallationStatus {
@Override public boolean isSuccess() {
return true;
}
}
/**
* Indicates that the plugin is waiting for its turn for installation.
*/
......@@ -1619,19 +1673,19 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas
/**
* Represents the state of the installation activity of one plugin.
*/
public final class InstallationJob extends DownloadJob {
public class InstallationJob extends DownloadJob {
/**
* What plugin are we trying to install?
*/
@Exported
public final Plugin plugin;
private final PluginManager pm = Jenkins.getInstance().getPluginManager();
protected final PluginManager pm = Jenkins.getInstance().getPluginManager();
/**
* True to load the plugin into this Jenkins, false to wait until restart.
*/
private final boolean dynamicLoad;
protected final boolean dynamicLoad;
/**
* @deprecated as of 1.442
......@@ -1667,29 +1721,81 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas
@Override
public void _run() throws IOException, InstallationStatus {
super._run();
if (wasInstalled()) {
// Do this first so we can avoid duplicate downloads, too
// check to see if the plugin is already installed at the same version and skip it
LOGGER.info("Skipping duplicate install of: " + plugin.getDisplayName() + "@" + plugin.version);
//throw new Skipped(); // TODO set skipped once we have a status indicator for it
return;
}
try {
super._run();
// if this is a bundled plugin, make sure it won't get overwritten
PluginWrapper pw = plugin.getInstalled();
if (pw!=null && pw.isBundled()) {
SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM);
try {
pw.doPin();
} finally {
SecurityContextHolder.setContext(oldContext);
}
}
// if this is a bundled plugin, make sure it won't get overwritten
PluginWrapper pw = plugin.getInstalled();
if (pw!=null && pw.isBundled()) {
SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM);
try {
pw.doPin();
} finally {
SecurityContextHolder.setContext(oldContext);
if (dynamicLoad) {
try {
pm.dynamicLoad(getDestination());
} catch (RestartRequiredException e) {
throw new SuccessButRequiresRestart(e.message);
} catch (Exception e) {
throw new IOException("Failed to dynamically deploy this plugin",e);
}
} else {
throw new SuccessButRequiresRestart(Messages._UpdateCenter_DownloadButNotActivated());
}
} finally {
synchronized(this) {
// There may be other threads waiting on completion
LOGGER.fine("Install complete for: " + plugin.getDisplayName() + "@" + plugin.version);
// some status other than Installing or Downloading needs to be set here
// {@link #isAlreadyInstalling()}, it will be overwritten by {@link DownloadJob#run()}
status = new Skipped();
notifyAll();
}
}
}
if (dynamicLoad) {
try {
pm.dynamicLoad(getDestination());
} catch (RestartRequiredException e) {
throw new SuccessButRequiresRestart(e.message);
} catch (Exception e) {
throw new IOException("Failed to dynamically deploy this plugin",e);
/**
* Indicates there is another installation job for this plugin
* @since TODO
*/
protected boolean wasInstalled() {
synchronized(UpdateCenter.this) {
for (UpdateCenterJob job : getJobs()) {
if (job == this) {
// oldest entries first, if we reach this instance,
// we need it to continue installing
return false;
}
if (job instanceof InstallationJob) {
InstallationJob ij = (InstallationJob)job;
if (ij.plugin.equals(plugin) && ij.plugin.version.equals(plugin.version)) {
// wait until other install is completed
synchronized(ij) {
if(ij.status instanceof Installing || ij.status instanceof Pending) {
try {
LOGGER.fine("Waiting for other plugin install of: " + plugin.getDisplayName() + "@" + plugin.version);
ij.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
return true;
}
}
}
} else {
throw new SuccessButRequiresRestart(Messages._UpdateCenter_DownloadButNotActivated());
return false;
}
}
......
......@@ -731,6 +731,10 @@ public class UpdateSite {
else if (current.isOlderThan(requiredVersion)) {
deps.add(depPlugin);
}
// JENKINS-34494 - or if the plugin is disabled, this will allow us to enable it
else if (!current.isEnabled()) {
deps.add(depPlugin);
}
}
for(Map.Entry<String,String> e : optionalDependencies.entrySet()) {
......@@ -847,10 +851,22 @@ public class UpdateSite {
for (Plugin dep : getNeededDependencies()) {
UpdateCenter.InstallationJob job = uc.getJob(dep);
if (job == null || job.status instanceof UpdateCenter.DownloadJob.Failure) {
LOGGER.log(Level.WARNING, "Adding dependent install of " + dep.name + " for plugin " + name);
LOGGER.log(Level.INFO, "Adding dependent install of " + dep.name + " for plugin " + name);
dep.deploy(dynamicLoad);
} else {
LOGGER.log(Level.WARNING, "Dependent install of " + dep.name + " for plugin " + name + " already added, skipping");
LOGGER.log(Level.INFO, "Dependent install of " + dep.name + " for plugin " + name + " already added, skipping");
}
}
PluginWrapper pw = getInstalled();
if(pw != null) { // JENKINS-34494 - check for this plugin being disabled
Future<UpdateCenterJob> enableJob = null;
if(!pw.isEnabled()) {
UpdateCenter.EnableJob job = uc.new EnableJob(UpdateSite.this, null, this, dynamicLoad);
job.setCorrelationId(correlationId);
enableJob = uc.addJob(job);
}
if(pw.getVersionNumber().equals(new VersionNumber(version))) {
return enableJob != null ? enableJob : uc.addJob(uc.new NoOpJob(UpdateSite.this, null, this));
}
}
UpdateCenter.InstallationJob job = uc.new InstallationJob(this, UpdateSite.this, Jenkins.getAuthentication(), dynamicLoad);
......
......@@ -249,7 +249,7 @@ public class SlaveComputer extends Computer {
try {
for (ComputerListener cl : ComputerListener.all())
cl.preLaunch(SlaveComputer.this, taskListener);
offlineCause = null;
launcher.launch(SlaveComputer.this, taskListener);
} catch (AbortException e) {
taskListener.error(e.getMessage());
......@@ -266,7 +266,7 @@ public class SlaveComputer extends Computer {
throw e;
}
} finally {
if (channel==null) {
if (channel==null && offlineCause == null) {
offlineCause = new OfflineCause.LaunchFailed();
for (ComputerListener cl : ComputerListener.all())
cl.onLaunchFailure(SlaveComputer.this, taskListener);
......
......@@ -923,9 +923,6 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
System.currentTimeMillis()-itemListenerStart,l.getClass().getName()));
}
// All plugins are loaded. Now we can figure out who depends on who.
resolveDependantPlugins();
if (LOG_STARTUP_PERFORMANCE)
LOGGER.info(String.format("Took %dms for complete Jenkins startup",
System.currentTimeMillis()-start));
......@@ -934,19 +931,6 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
}
}
private void resolveDependantPlugins() throws InterruptedException, ReactorException, IOException {
TaskGraphBuilder graphBuilder = new TaskGraphBuilder();
graphBuilder.add("Resolving Dependant Plugins Graph", new Executable() {
@Override
public void run(Reactor reactor) throws Exception {
pluginManager.resolveDependantPlugins();
}
});
executeReactor(null, graphBuilder);
}
/**
* Maintains backwards compatibility. Invoked by XStream when this object is de-serialized.
*/
......
......@@ -173,6 +173,12 @@ Behaviour.specify("#filter-box", '_table', 0, function(e) {
function setEnableWidgetStates() {
for (var i = 0; i < pluginTRs.length; i++) {
var pluginMetadata = pluginTRs[i].jenkinsPluginMetadata;
if (pluginTRs[i].hasClassName('has-dependants-but-disabled')) {
if (pluginMetadata.enableInput.checked) {
pluginTRs[i].removeClassName('has-dependants-but-disabled');
}
}
markAllDependantsDisabled(pluginTRs[i]);
markHasDisabledDependencies(pluginTRs[i]);
}
......
......@@ -68,7 +68,7 @@ THE SOFTWARE.
<th width="1">${%Uninstall}</th>
</tr>
<j:forEach var="p" items="${app.pluginManager.plugins}">
<tr class="plugin ${p.hasDependants()?'has-dependants':''} ${p.isDeleted()?'deleted':''}" data-plugin-id="${p.shortName}" data-plugin-name="${p.displayName}">
<tr class="plugin ${p.hasDependants()?'has-dependants':''} ${(p.hasDependants() &amp;&amp; !p.enabled)?'has-dependants-but-disabled':''} ${p.isDeleted()?'deleted':''}" data-plugin-id="${p.shortName}" data-plugin-name="${p.displayName}">
<j:set var="state" value="${p.enabled?'true':null}"/>
<td class="center pane enable" data="${state}">
<input type="checkbox" checked="${state}" onclick="flip(event)"
......
newJob=Pra\u0161ome <a href="newJob">sukurti nauj\u0105 darb\u0105</a>, kad prad\u0117tum\u0117te.
login=<a href="{0}/{1}?from={2}">Prisijunkite</a>, kad gal\u0117tumet kurti naujus darbus.
signup=Jei dar neturite paskyros, galite dabar <a href="signup">u\u017esiregistruoti</a>.
<!--
The MIT License
Copyright (c) 2016, CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<tr id="row${it.id}">
<td style="vertical-align: top; padding-right:1em">${it.plugin.displayName}</td>
<td style="vertical-align:middle">
<l:icon class="icon-${it.error!=null?'yellow':'blue'} icon-md"/> ${%Enabled Dependency}
</td>
</tr>
</j:jelly>
<!--
The MIT License
Copyright (c) 2016, CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<tr id="row${it.id}">
<td style="vertical-align: top; padding-right:1em">${it.plugin.displayName}</td>
<td style="vertical-align:middle">
<l:icon class="icon-${it.error!=null?'yellow':'blue'} icon-md"/> ${%Already Installed}
</td>
</tr>
</j:jelly>
authenticate-security-token.getting.started=\u012evadas
authenticate-security-token.unlock.jenkins=Atrakinti Jenkins\u0105
jenkins.install.findSecurityTokenMessage=Kad u\u017etikrintum\u0117me kad Jenkins\u0105 saugiai paruo\u0161\u0117 administratorius, \
slapta\u017eodis buvo \u012fra\u0161ytas \u012f \u017eurnal\u0105 (<small><a href="https://jenkins.io/redirect/find-jenkins-logs" target="_blank">ne\u017einote, kur j\u012f rasti?</a></small>) ir \u0161\u012f fail\u0105 serveryje: <p><small><code>{0}</code></small></p>
authenticate-security-token.copy.password=Pra\u0161ome nukopijuoti slapta\u017eiod\u012f i\u0161 bet kurios vietos \u012f \u017eemiau esant\u012f lauk\u0105.
authenticate-security-token.error=KLAIDA:
authenticate-security-token.password.incorrect=\u012evestas neteisingas slapta\u017eodis, pra\u0161ome patikrinti fail\u0105 ir rasti teising\u0105 slapta\u017eod\u012f
authenticate-security-token.password.administrator=Administratoriaus slapta\u017eodis
authenticate-security-token.continue=T\u0119sti
Create\ First\ Admin\ User=Sukurti pirm\u0105 administratoriaus naudotoj\u0105
msg.before=Jus sveikina Jenkins 2!\u0020
msg.link=\u012ediegti naujas savybes
msg.after=\u0020kad baigtum\u0117te atnaujinim\u0105
installWizard_welcomePanel_title=\u012evadas
installWizard_welcomePanel_banner=Jenkins pritaikymas
installWizard_welcomePanel_message=Priedai papildo Jenkins\u0105 naujomis galimyb\u0117mis.
installWizard_welcomePanel_recommendedActionTitle=\u012ediegti si\u016blomus priedus
installWizard_welcomePanel_recommendedActionDetails=\u012ediegti priedus, kuriuos Jenkinso bendruomen\u0117 labiausiai naudoja.
installWizard_welcomePanel_customizeActionTitle=Parinkite priedus \u012fdiegimui
installWizard_welcomePanel_customizeActionDetails=Parinkite ir \u012fdiekite priedus, labiausiai patenkinan\u010dius j\u016bs\u0173 poreikius.
installWizard_jenkinsVersionTitle=Jenkins
installWizard_offline_title=Atsijung\u0119s
installWizard_offline_message=Pana\u0161u, kad \u0161is Jenkinsas yra atsijung\u0119s. \
<p style="font-size:18px; margin-top: 6%"> \
Daugiau informacijos apie tai, kaip diegti Jenkins\u0105 neprisijungus prie interneto, ie\u0161kokite \
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Offline+Jenkins+Installation" target="_blank">Neprijungto Jenkins diegimo dokumentacijoje</a>. <br/><br/> \
Galite nuspr\u0119sti t\u0119sti sukonfig\u016brav\u0119 \u0161liuz\u0105 arba praleisdami pried\u0173 diegim\u0105. \
</p>
installWizard_error_header=\u012evyko klaida
installWizard_error_message=Diegiant \u012fvyko klaida:
installWizard_error_connection=Nepavyksta prisijungti prie Jenkinso
installWizard_installCustom_title=\u012evadas
installWizard_installCustom_selectAll=Viskas
installWizard_installCustom_selectNone=Nieko
installWizard_installCustom_selectRecommended=Rekomenduojami
installWizard_installCustom_selected=Pa\u017eym\u0117ti
installWizard_installCustom_dependenciesPrefix=Priklausomyb\u0117s
installWizard_installCustom_pluginListDesc=Pasteb\u0117tina, kad \u010dia nerodomas pilnas pried\u0173 s\u0105ra\u0161as. Papildomus priedus galite \u012fdiegti <strong>Pried\u0173 tvarkykl\u0117je</strong>, kai bus baigtas pradinis diegimas. <a href="https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins#InstallingJenkins-InstallationWizard" target="_blank">Daugiau informacijos rasite vikyje</a>.
installWizard_goBack=Atgal
installWizard_goInstall=\u012ediegti
installWizard_installing_title=\u012evadas
installWizard_installing_detailsLink=Detal\u0117s...
installWizard_installComplete_title=\u012evadas
installWizard_installComplete_banner=Jenkinsas paruo\u0161tas!
installWizard_pluginsInstalled_message=J\u016bs\u0173 pried\u0173 diegimas baigtas.
installWizard_installComplete_message=J\u016bs\u0173 Jenkinso nustatymas baigtas.
installWizard_installComplete_finishButtonLabel=Prad\u0117kite naudoti Jenkins\u0105
installWizard_installComplete_restartRequiredMessage=Kai kuriems priedams reikia, kad Jenkinsas b\u016bt\u0173 i\u0161 naujo paleistas.
installWizard_installComplete_restartLabel=Paleisti i\u0161 naujo
installWizard_installIncomplete_title=T\u0119sti diegim\u0105
installWizard_installIncomplete_banner=T\u0119sti diegim\u0105
installWizard_installIncomplete_message=Jenkinsas buvo i\u0161 naujo paleistas diegimo metu ir pana\u0161u, kad kai kurie prieda ne\u012fsidieg\u0117.
installWizard_installIncomplete_resumeInstallationButtonLabel=T\u0119sti
installWizard_saveFirstUser=\u012era\u0161yti ir baigti
installWizard_skipFirstUser=T\u0119sti kaip administratoriumi
installWizard_firstUserSkippedMessage=<div class="alert alert-warning fade in">\
J\u016bs praleidote administratoriaus naudotojo k\u016brim\u0105. Nor\u0117dami prisijungti, naudokite vard\u0105: \u201eadmin\u201c ir \
administratoriaus slapta\u017eod\u012f, kur\u012f naudojote prisijungimui prie nustatymo vedlio.\
</div>
installWizard_addFirstUser_title=\u012evadas
installWizard_configureProxy_label=Konfig\u016bruoti \u0161liuz\u0105
installWizard_configureProxy_save=\u012era\u0161yti ir t\u0119sti
installWizard_skipPluginInstallations=Praleisti pried\u0173 diegim\u0105
installWizard_installIncomplete_dependenciesLabel=Priklausomyb\u0117s
installWizard_installingConsole_dependencyIndicatorNote=** - privaloma priklausomyb\u0117
installWizard_websiteLinkLabel=Svetain\u0117
installWizard_retry=Kartoti
......@@ -33,7 +33,7 @@ THE SOFTWARE.
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.1-SNAPSHOT</version>
<version>2.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Jenkins main module</name>
......
......@@ -28,7 +28,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.1-SNAPSHOT</version>
<version>2.2-SNAPSHOT</version>
</parent>
<artifactId>test</artifactId>
......
......@@ -23,18 +23,21 @@
*/
package hudson.model;
import static org.junit.Assert.*;
import com.gargoylesoftware.htmlunit.Page;
import java.io.File;
import java.net.HttpURLConnection;
import com.gargoylesoftware.htmlunit.WebResponse;
import net.sf.json.JSONObject;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import java.io.File;
import java.net.HttpURLConnection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Kohsuke Kawaguchi
*/
......@@ -53,8 +56,15 @@ public class ApiTest {
@Test public void json() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("p");
JenkinsRule.WebClient wc = j.createWebClient();
assertEquals("{\"name\":\"p\"}", wc.goTo(p.getUrl() + "api/json?tree=name", "application/json").getWebResponse().getContentAsString());
assertEquals("wrap({\"name\":\"p\"})", wc.goTo(p.getUrl() + "api/json?tree=name&jsonp=wrap", "application/javascript").getWebResponse().getContentAsString());
WebResponse response = wc.goTo(p.getUrl() + "api/json?tree=name", "application/json").getWebResponse();
JSONObject json = JSONObject.fromObject(response.getContentAsString());
assertEquals("p", json.get("name"));
String s = wc.goTo(p.getUrl() + "api/json?tree=name&jsonp=wrap", "application/javascript").getWebResponse().getContentAsString();
assertTrue(s.startsWith("wrap("));
assertEquals(')', s.charAt(s.length()-1));
json = JSONObject.fromObject(s.substring("wrap(".length(), s.length() - 1));
assertEquals("p", json.get("name"));
}
@Test
......
......@@ -68,26 +68,6 @@ import hudson.triggers.SCMTrigger.SCMTriggerCause;
import hudson.triggers.TimerTrigger.TimerTriggerCause;
import hudson.util.OneShotEvent;
import hudson.util.XStream2;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jenkins.model.Jenkins;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import jenkins.triggers.ReverseBuildTrigger;
......@@ -99,10 +79,6 @@ import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.*;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletHandler;
......@@ -119,6 +95,30 @@ import org.jvnet.hudson.test.TestBuilder;
import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.recipes.LocalData;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.*;
/**
* @author Kohsuke Kawaguchi
*/
......@@ -937,15 +937,15 @@ public class QueueTest {
webClient.login("alice");
XmlPage p2 = webClient.goToXml("queue/api/xml");
//alice does not have permission on the project and will not see it in the queue.
assertEquals("<queue></queue>", p2.getContent());
assertTrue(p2.getByXPath("/queue/node()").isEmpty());
webClient = r.createWebClient();
webClient.login("james");
XmlPage p3 = webClient.goToXml("queue/api/xml");
//james has DISCOVER permission on the project and will only be able to see the task name.
assertEquals("<queue><discoverableItem><task><name>project</name></task></discoverableItem></queue>",
p3.getContent());
//james has DISCOVER permission on the project and will only be able to see the task name.
List projects = p3.getByXPath("/queue/discoverableItem/task/name/text()");
assertEquals(1, projects.size());
assertEquals("project", projects.get(0).toString());
}
//we force the project not to be executed so that it stays in the queue
......
......@@ -8,8 +8,7 @@ package hudson.security.csrf;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.net.HttpURLConnection;
import static org.junit.Assert.*;
import net.sf.json.JSONObject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
......@@ -18,6 +17,10 @@ import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.recipes.PresetData;
import java.net.HttpURLConnection;
import static org.junit.Assert.*;
/**
*
* @author dty
......@@ -126,7 +129,9 @@ public class DefaultCrumbIssuerTest {
@Test public void apiJson() throws Exception {
WebClient wc = r.createWebClient();
String json = wc.goTo("crumbIssuer/api/json", "application/json").getWebResponse().getContentAsString();
assertTrue(json, json.matches("\\Q{\"crumb\":\"\\E[0-9a-f]+\\Q\",\"crumbRequestField\":\"" + r.jenkins.getCrumbIssuer().getCrumbRequestField() + "\"}\\E"));
JSONObject jsonObject = JSONObject.fromObject(json);
assertEquals(r.jenkins.getCrumbIssuer().getCrumbRequestField(),jsonObject.getString("crumbRequestField"));
assertTrue(jsonObject.getString("crumb").matches("[0-9a-f]+"));
wc.assertFails("crumbIssuer/api/json?jsonp=hack", HttpURLConnection.HTTP_FORBIDDEN);
}
......
......@@ -28,7 +28,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.1-SNAPSHOT</version>
<version>2.2-SNAPSHOT</version>
</parent>
<artifactId>jenkins-war</artifactId>
......
......@@ -104,7 +104,7 @@ var createPluginSetupWizard = function(appendTarget) {
return options.fn();
}
});
// Include handlebars templates here - explicitly require them and they'll be available by hbsfy as part of the bundle process
var errorPanel = require('./templates/errorPanel.hbs');
var loadingPanel = require('./templates/loadingPanel.hbs');
......@@ -166,6 +166,19 @@ var createPluginSetupWizard = function(appendTarget) {
title: text
}).tooltip('show');
});
// handle clicking links that might not get highlighted due to position on the page
$wizard.on('click', '.nav>li>a', function(){
var $li = $(this).parent();
var activateClicked = function() {
if(!$li.is('.active')) {
$li.parent().find('>li').removeClass('active');
$li.addClass('active');
}
};
setTimeout(activateClicked, 150); // this is the scroll time
setTimeout(activateClicked, 250); // this should combat timing issues
});
// localized messages
var translations = {};
......
......@@ -42,6 +42,7 @@ THE SOFTWARE.
<param-name>diagnosticThreadName</param-name>
<param-value>false</param-value>
</init-param>
<async-supported>true</async-supported>
</servlet>
<context-param>
......@@ -57,26 +58,32 @@ THE SOFTWARE.
<filter>
<filter-name>diagnostic-name-filter</filter-name>
<filter-class>org.kohsuke.stapler.DiagnosticThreadNameFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>encoding-filter</filter-name>
<filter-class>hudson.util.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>compression-filter</filter-name>
<filter-class>org.kohsuke.stapler.compression.CompressionFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>authentication-filter</filter-name>
<filter-class>hudson.security.HudsonFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>csrf-filter</filter-name>
<filter-class>hudson.security.csrf.CrumbFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>plugins-filter</filter-name>
<filter-class>hudson.util.PluginServletFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<!--
......
......@@ -1424,6 +1424,12 @@ TABLE.fingerprint-in-build TD {
opacity: 0.2;
}
#plugins tr.has-dependants-but-disabled .enable input {
pointer-events: auto;
opacity: 1.0;
visibility: visible;
}
#plugins tr.has-disabled-dependency .enable input {
opacity: 0.4;
}
......
<div>
Defina um padr&#227;o (express&#227;o regular) para checar se o nome de um job &#233; v&#225;lido ou n&#227;o.
<p>
For&#231;ando a checagem em jobs que j&#225; existem, vai permitir que voc&#234; reforce uma conven&#231;&#227;o - e.g. mesmo que os usu&#225;rios n&#227;o mudem o nome,
O job ser&#225; validado com o padr&#227;o definido em cada submiss&#227;o e atualiza&#231;&#227;o at&#233; que o nome confirme.<br>
<i>Essa op&#231;&#227;o n&#227;o afetar&#225; a execu&#231;&#227;o de jobs com nomes n&#227;o complascentes. Isto apenas controla o processo de valida&#231;&#227;o no momento de salvar as configura&#231;&#245;es de um job.</i>
</div>
<div>
Label opcional para restringir o uso deste m&#233;todo de instala&#231;&#227;o.
Esta label pode ser uma express&#227;o (por exemplo: "linux&&x64" or "windows&&x86").
Somente n&#243;s que validaram esta label (ou express&#227;o) ser&#227;o considerados.
</div>
<div>
Voc&#234; pode especificar a localiza&#231;&#227;o de certas ferramentas, sobrescrevendo a configura&#231;&#227;o global.
(Voc&#234; pode preferir o uso de instaladores autom&#225;ticos de ferramentas como alternativa, removendo a necessidade de configurar cada n&#243; separadamente)
</div>
<!--
The MIT License
Copyright (c) 2004-2016, Codeminer42, Waldyr de Souza
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<div>
Caso selecionado, apenas executores de build que podem executar jobs nessa view aparecer&#227;o.
</div>
<!--
The MIT License
Copyright (c) 2004-2016, Codeminer42, Waldyr de Souza
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<div>
Caso selecionado, apenas jobs nessa view aparecer&#227;o na fila.
</div>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册