Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
LinuxSuRen
jenkins
提交
c508620b
J
jenkins
项目概览
LinuxSuRen
/
jenkins
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jenkins
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c508620b
编写于
8月 13, 2018
作者:
D
Daniel Beck
浏览文件
操作
浏览文件
下载
差异文件
Merge commit '
817f1149
' of
git://github.com/jenkinsci/jenkins
上级
6d85033d
817f1149
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
515 addition
and
49 deletion
+515
-49
.mvn/extensions.xml
.mvn/extensions.xml
+1
-1
core/pom.xml
core/pom.xml
+1
-1
core/src/main/java/hudson/Launcher.java
core/src/main/java/hudson/Launcher.java
+19
-6
core/src/main/java/hudson/PluginWrapper.java
core/src/main/java/hudson/PluginWrapper.java
+24
-7
core/src/main/java/hudson/cli/EnablePluginCommand.java
core/src/main/java/hudson/cli/EnablePluginCommand.java
+100
-0
core/src/main/java/hudson/model/Queue.java
core/src/main/java/hudson/model/Queue.java
+1
-1
core/src/main/java/hudson/model/TaskListener.java
core/src/main/java/hudson/model/TaskListener.java
+4
-1
core/src/main/java/hudson/slaves/EnvironmentVariablesNodeProperty.java
.../java/hudson/slaves/EnvironmentVariablesNodeProperty.java
+15
-0
core/src/main/java/hudson/tools/ToolInstaller.java
core/src/main/java/hudson/tools/ToolInstaller.java
+2
-0
core/src/main/java/jenkins/security/apitoken/LegacyApiTokenAdministrativeMonitor.java
...ecurity/apitoken/LegacyApiTokenAdministrativeMonitor.java
+12
-8
core/src/main/java/jenkins/security/s2m/AdminWhitelistRule.java
...rc/main/java/jenkins/security/s2m/AdminWhitelistRule.java
+19
-12
core/src/main/resources/hudson/cli/Messages.properties
core/src/main/resources/hudson/cli/Messages.properties
+5
-0
core/src/main/resources/hudson/diagnosis/OldDataMonitor/message_zh_CN.properties
.../hudson/diagnosis/OldDataMonitor/message_zh_CN.properties
+1
-1
core/src/main/resources/hudson/slaves/EnvironmentVariablesNodeProperty/config.jelly
...dson/slaves/EnvironmentVariablesNodeProperty/config.jelly
+1
-1
core/src/test/java/hudson/PluginWrapperTest.java
core/src/test/java/hudson/PluginWrapperTest.java
+14
-3
pom.xml
pom.xml
+2
-2
test/src/test/java/hudson/LauncherTest.java
test/src/test/java/hudson/LauncherTest.java
+120
-0
test/src/test/java/hudson/cli/EnablePluginCommandTest.java
test/src/test/java/hudson/cli/EnablePluginCommandTest.java
+95
-0
test/src/test/java/hudson/model/QueueTest.java
test/src/test/java/hudson/model/QueueTest.java
+26
-0
test/src/test/java/jenkins/security/apitoken/LegacyApiTokenAdministrativeMonitorTest.java
...ity/apitoken/LegacyApiTokenAdministrativeMonitorTest.java
+52
-5
war/src/main/webapp/css/style.css
war/src/main/webapp/css/style.css
+1
-0
未找到文件。
.mvn/extensions.xml
浏览文件 @
c508620b
...
...
@@ -2,6 +2,6 @@
<extension>
<groupId>
io.jenkins.tools.incrementals
</groupId>
<artifactId>
git-changelist-maven-extension
</artifactId>
<version>
1.0-beta-
3
</version>
<version>
1.0-beta-
4
</version>
</extension>
</extensions>
core/pom.xml
浏览文件 @
c508620b
...
...
@@ -535,7 +535,7 @@ THE SOFTWARE.
<dependency>
<groupId>
net.java.dev.jna
</groupId>
<artifactId>
jna
</artifactId>
<version>
4.
2.1
</version>
<version>
4.
5.2
</version>
</dependency>
<dependency>
<groupId>
org.kohsuke
</groupId>
...
...
core/src/main/java/hudson/Launcher.java
浏览文件 @
c508620b
...
...
@@ -166,6 +166,8 @@ public abstract class Launcher {
@CheckForNull
protected
OutputStream
stdout
=
NULL_OUTPUT_STREAM
,
stderr
;
@CheckForNull
private
TaskListener
stdoutListener
;
@CheckForNull
protected
InputStream
stdin
=
NULL_INPUT_STREAM
;
@CheckForNull
protected
String
[]
envs
=
null
;
...
...
@@ -285,17 +287,20 @@ public abstract class Launcher {
*/
public
ProcStarter
stdout
(
@CheckForNull
OutputStream
out
)
{
this
.
stdout
=
out
;
stdoutListener
=
null
;
return
this
;
}
/**
* Sends the stdout to the given {@link TaskListener}.
*
* @param out Task listener
* @param out Task listener
(must be safely remotable)
* @return {@code this}
*/
public
ProcStarter
stdout
(
@Nonnull
TaskListener
out
)
{
return
stdout
(
out
.
getLogger
());
stdout
=
out
.
getLogger
();
stdoutListener
=
out
;
return
this
;
}
/**
...
...
@@ -490,6 +495,7 @@ public abstract class Launcher {
@Nonnull
public
ProcStarter
copy
()
{
ProcStarter
rhs
=
new
ProcStarter
().
cmds
(
commands
).
pwd
(
pwd
).
masks
(
masks
).
stdin
(
stdin
).
stdout
(
stdout
).
stderr
(
stderr
).
envs
(
envs
).
quiet
(
quiet
);
rhs
.
stdoutListener
=
stdoutListener
;
rhs
.
reverseStdin
=
this
.
reverseStdin
;
rhs
.
reverseStderr
=
this
.
reverseStderr
;
rhs
.
reverseStdout
=
this
.
reverseStdout
;
...
...
@@ -1041,7 +1047,7 @@ public abstract class Launcher {
}
public
Proc
launch
(
ProcStarter
ps
)
throws
IOException
{
final
OutputStream
out
=
ps
.
stdout
==
null
?
null
:
new
RemoteOutputStream
(
new
CloseProofOutputStream
(
ps
.
stdout
));
final
OutputStream
out
=
ps
.
stdout
==
null
||
ps
.
stdoutListener
!=
null
?
null
:
new
RemoteOutputStream
(
new
CloseProofOutputStream
(
ps
.
stdout
));
final
OutputStream
err
=
ps
.
stderr
==
null
?
null
:
new
RemoteOutputStream
(
new
CloseProofOutputStream
(
ps
.
stderr
));
final
InputStream
in
=
(
ps
.
stdin
==
null
||
ps
.
stdin
==
NULL_INPUT_STREAM
)
?
null
:
new
RemoteInputStream
(
ps
.
stdin
,
false
);
...
...
@@ -1049,7 +1055,7 @@ public abstract class Launcher {
final
String
workDir
=
psPwd
==
null
?
null
:
psPwd
.
getRemote
();
try
{
return
new
ProcImpl
(
getChannel
().
call
(
new
RemoteLaunchCallable
(
ps
.
commands
,
ps
.
masks
,
ps
.
envs
,
in
,
ps
.
reverseStdin
,
out
,
ps
.
reverseStdout
,
err
,
ps
.
reverseStderr
,
ps
.
quiet
,
workDir
,
listener
)));
return
new
ProcImpl
(
getChannel
().
call
(
new
RemoteLaunchCallable
(
ps
.
commands
,
ps
.
masks
,
ps
.
envs
,
in
,
ps
.
reverseStdin
,
out
,
ps
.
reverseStdout
,
err
,
ps
.
reverseStderr
,
ps
.
quiet
,
workDir
,
listener
,
ps
.
stdoutListener
)));
}
catch
(
InterruptedException
e
)
{
throw
(
IOException
)
new
InterruptedIOException
().
initCause
(
e
);
}
...
...
@@ -1265,6 +1271,7 @@ public abstract class Launcher {
private
final
@CheckForNull
OutputStream
err
;
private
final
@CheckForNull
String
workDir
;
private
final
@Nonnull
TaskListener
listener
;
private
final
@CheckForNull
TaskListener
stdoutListener
;
private
final
boolean
reverseStdin
,
reverseStdout
,
reverseStderr
;
private
final
boolean
quiet
;
...
...
@@ -1272,7 +1279,7 @@ public abstract class Launcher {
@CheckForNull
InputStream
in
,
boolean
reverseStdin
,
@CheckForNull
OutputStream
out
,
boolean
reverseStdout
,
@CheckForNull
OutputStream
err
,
boolean
reverseStderr
,
boolean
quiet
,
@CheckForNull
String
workDir
,
@Nonnull
TaskListener
listener
)
{
boolean
quiet
,
@CheckForNull
String
workDir
,
@Nonnull
TaskListener
listener
,
@CheckForNull
TaskListener
stdoutListener
)
{
this
.
cmd
=
new
ArrayList
<>(
cmd
);
this
.
masks
=
masks
;
this
.
env
=
env
;
...
...
@@ -1281,6 +1288,7 @@ public abstract class Launcher {
this
.
err
=
err
;
this
.
workDir
=
workDir
;
this
.
listener
=
listener
;
this
.
stdoutListener
=
stdoutListener
;
this
.
reverseStdin
=
reverseStdin
;
this
.
reverseStdout
=
reverseStdout
;
this
.
reverseStderr
=
reverseStderr
;
...
...
@@ -1290,7 +1298,12 @@ public abstract class Launcher {
public
RemoteProcess
call
()
throws
IOException
{
final
Channel
channel
=
getOpenChannelOrFail
();
Launcher
.
ProcStarter
ps
=
new
LocalLauncher
(
listener
).
launch
();
ps
.
cmds
(
cmd
).
masks
(
masks
).
envs
(
env
).
stdin
(
in
).
stdout
(
out
).
stderr
(
err
).
quiet
(
quiet
);
ps
.
cmds
(
cmd
).
masks
(
masks
).
envs
(
env
).
stdin
(
in
).
stderr
(
err
).
quiet
(
quiet
);
if
(
stdoutListener
!=
null
)
{
ps
.
stdout
(
stdoutListener
.
getLogger
());
}
else
{
ps
.
stdout
(
out
);
}
if
(
workDir
!=
null
)
ps
.
pwd
(
workDir
);
if
(
reverseStdin
)
ps
.
writeStdin
();
if
(
reverseStdout
)
ps
.
readStdout
();
...
...
core/src/main/java/hudson/PluginWrapper.java
浏览文件 @
c508620b
...
...
@@ -36,7 +36,6 @@ import jenkins.model.Jenkins;
import
hudson.model.UpdateCenter
;
import
hudson.model.UpdateSite
;
import
hudson.util.VersionNumber
;
import
org.jvnet.localizer.ResourceBundleHolder
;
import
org.kohsuke.accmod.Restricted
;
import
org.kohsuke.accmod.restrictions.DoNotUse
;
import
org.kohsuke.accmod.restrictions.NoExternalUse
;
...
...
@@ -54,7 +53,6 @@ import javax.annotation.CheckForNull;
import
javax.annotation.Nonnull
;
import
java.io.Closeable
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.net.URL
;
...
...
@@ -64,7 +62,6 @@ import java.util.Collection;
import
java.util.Collections
;
import
java.util.Enumeration
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -600,7 +597,7 @@ public class PluginWrapper implements Comparable<PluginWrapper>, ModelObject {
}
else
{
VersionNumber
actualVersion
=
Jenkins
.
getVersion
();
if
(
actualVersion
.
isOlderThan
(
new
VersionNumber
(
requiredCoreVersion
)))
{
dependencyErrors
.
put
(
Messages
.
PluginWrapper_obsoleteCore
(
Jenkins
.
getVersion
().
toString
(),
requiredCoreVersion
),
false
);
versionDependencyError
(
Messages
.
PluginWrapper_obsoleteCore
(
Jenkins
.
getVersion
().
toString
(),
requiredCoreVersion
),
Jenkins
.
getVersion
().
toString
(),
requiredCoreVersion
);
}
}
}
...
...
@@ -618,11 +615,11 @@ public class PluginWrapper implements Comparable<PluginWrapper>, ModelObject {
}
else
{
if
(
dependency
.
isActive
())
{
if
(
isDependencyObsolete
(
d
,
dependency
))
{
dependencyErrors
.
put
(
Messages
.
PluginWrapper_obsolete
(
dependency
.
getLongName
(),
dependency
.
getVersion
(),
d
.
version
),
false
);
versionDependencyError
(
Messages
.
PluginWrapper_obsolete
(
dependency
.
getLongName
(),
dependency
.
getVersion
(),
d
.
version
),
dependency
.
getVersion
(),
d
.
version
);
}
}
else
{
if
(
isDependencyObsolete
(
d
,
dependency
))
{
dependencyErrors
.
put
(
Messages
.
PluginWrapper_disabledAndObsolete
(
dependency
.
getLongName
(),
dependency
.
getVersion
(),
d
.
version
),
false
);
versionDependencyError
(
Messages
.
PluginWrapper_disabledAndObsolete
(
dependency
.
getLongName
(),
dependency
.
getVersion
(),
d
.
version
),
dependency
.
getVersion
(),
d
.
version
);
}
else
{
dependencyErrors
.
put
(
Messages
.
PluginWrapper_disabled
(
dependency
.
getLongName
()),
false
);
}
...
...
@@ -635,7 +632,7 @@ public class PluginWrapper implements Comparable<PluginWrapper>, ModelObject {
PluginWrapper
dependency
=
parent
.
getPlugin
(
d
.
shortName
);
if
(
dependency
!=
null
&&
dependency
.
isActive
())
{
if
(
isDependencyObsolete
(
d
,
dependency
))
{
dependencyErrors
.
put
(
Messages
.
PluginWrapper_obsolete
(
dependency
.
getLongName
(),
dependency
.
getVersion
(),
d
.
version
),
false
);
versionDependencyError
(
Messages
.
PluginWrapper_obsolete
(
dependency
.
getLongName
(),
dependency
.
getVersion
(),
d
.
version
),
dependency
.
getVersion
(),
d
.
version
);
}
else
{
dependencies
.
add
(
d
);
}
...
...
@@ -660,6 +657,26 @@ public class PluginWrapper implements Comparable<PluginWrapper>, ModelObject {
return
ENABLE_PLUGIN_DEPENDENCIES_VERSION_CHECK
&&
dependency
.
getVersionNumber
().
isOlderThan
(
new
VersionNumber
(
d
.
version
));
}
/**
* Called when there appears to be a core or plugin version which is too old for a stated dependency.
* Normally records an error in {@link #dependencyErrors}.
* But if one or both versions {@link #isSnapshot}, just issue a warning (JENKINS-52665).
*/
private
void
versionDependencyError
(
String
message
,
String
actual
,
String
minimum
)
{
if
(
isSnapshot
(
actual
)
||
isSnapshot
(
minimum
))
{
LOGGER
.
log
(
WARNING
,
"Suppressing dependency error in {0} v{1}: {2}"
,
new
Object
[]
{
getLongName
(),
getVersion
(),
message
});
}
else
{
dependencyErrors
.
put
(
message
,
false
);
}
}
/**
* Similar to {@code org.apache.maven.artifact.ArtifactUtils.isSnapshot}.
*/
static
boolean
isSnapshot
(
@Nonnull
String
version
)
{
return
version
.
contains
(
"-SNAPSHOT"
)
||
version
.
matches
(
".+-[0-9]{8}.[0-9]{6}-[0-9]+"
);
}
/**
* If the plugin has {@link #getUpdateInfo() an update},
* returns the {@link hudson.model.UpdateSite.Plugin} object.
...
...
core/src/main/java/hudson/cli/EnablePluginCommand.java
0 → 100644
浏览文件 @
c508620b
/*
* The MIT License
*
* Copyright (c) 2018 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.
*/
package
hudson.cli
;
import
hudson.Extension
;
import
hudson.PluginManager
;
import
hudson.PluginWrapper
;
import
jenkins.model.Jenkins
;
import
org.kohsuke.args4j.Argument
;
import
org.kohsuke.args4j.Option
;
import
java.io.IOException
;
import
java.util.List
;
/**
* Enables one or more installed plugins. The listed plugins must already be installed along with its dependencies.
* Any listed plugin with disabled dependencies will have its dependencies enabled transitively. Note that enabling an
* already enabled plugin does nothing.
*
* @since TODO
*/
@Extension
public
class
EnablePluginCommand
extends
CLICommand
{
@Argument
(
required
=
true
,
usage
=
"Enables the plugins with the given short names and their dependencies."
)
private
List
<
String
>
pluginNames
;
@Option
(
name
=
"-restart"
,
usage
=
"Restart Jenkins after enabling plugins."
)
private
boolean
restart
;
@Override
public
String
getShortDescription
()
{
return
Messages
.
EnablePluginCommand_ShortDescription
();
}
@Override
protected
int
run
()
throws
Exception
{
Jenkins
jenkins
=
Jenkins
.
get
();
jenkins
.
checkPermission
(
Jenkins
.
ADMINISTER
);
PluginManager
manager
=
jenkins
.
getPluginManager
();
for
(
String
pluginName
:
pluginNames
)
{
enablePlugin
(
manager
,
pluginName
);
}
if
(
restart
)
{
jenkins
.
safeRestart
();
}
return
0
;
}
private
void
enablePlugin
(
PluginManager
manager
,
String
shortName
)
throws
IOException
{
PluginWrapper
plugin
=
manager
.
getPlugin
(
shortName
);
if
(
plugin
==
null
)
{
throw
new
IllegalArgumentException
(
Messages
.
EnablePluginCommand_NoSuchPlugin
(
shortName
));
}
if
(
plugin
.
isEnabled
())
{
return
;
}
stdout
.
println
(
String
.
format
(
"Enabling plugin `%s' (%s)"
,
plugin
.
getShortName
(),
plugin
.
getVersion
()));
enableDependencies
(
manager
,
plugin
);
plugin
.
enable
();
stdout
.
println
(
String
.
format
(
"Plugin `%s' was enabled."
,
plugin
.
getShortName
()));
}
private
void
enableDependencies
(
PluginManager
manager
,
PluginWrapper
plugin
)
throws
IOException
{
for
(
PluginWrapper
.
Dependency
dep
:
plugin
.
getDependencies
())
{
PluginWrapper
dependency
=
manager
.
getPlugin
(
dep
.
shortName
);
if
(
dependency
==
null
)
{
throw
new
IllegalArgumentException
(
Messages
.
EnablePluginCommand_MissingDependencies
(
plugin
.
getShortName
(),
dep
));
}
if
(!
dependency
.
isEnabled
())
{
enableDependencies
(
manager
,
dependency
);
stdout
.
println
(
String
.
format
(
"Enabling plugin dependency `%s' (%s) for `%s'"
,
dependency
.
getShortName
(),
dependency
.
getVersion
(),
plugin
.
getShortName
()));
dependency
.
enable
();
}
}
}
}
core/src/main/java/hudson/model/Queue.java
浏览文件 @
c508620b
...
...
@@ -1470,7 +1470,7 @@ public class Queue extends ResourceController implements Saveable {
{
// update parked (and identify any pending items whose executor has disappeared)
List
<
BuildableItem
>
lostPendings
=
new
ArrayList
<
BuildableItem
>(
pendings
);
for
(
Computer
c
:
jenkins
.
getComputers
())
{
for
(
Executor
e
:
c
.
getExecutors
())
{
for
(
Executor
e
:
c
.
get
All
Executors
())
{
if
(
e
.
isInterrupted
())
{
// JENKINS-28840 we will deadlock if we try to touch this executor while interrupt flag set
// we need to clear lost pendings as we cannot know what work unit was on this executor
...
...
core/src/main/java/hudson/model/TaskListener.java
浏览文件 @
c508620b
...
...
@@ -25,6 +25,7 @@ package hudson.model;
import
hudson.console.ConsoleNote
;
import
hudson.console.HyperlinkNote
;
import
hudson.remoting.Channel
;
import
hudson.util.NullStream
;
import
hudson.util.StreamTaskListener
;
...
...
@@ -59,7 +60,9 @@ import org.kohsuke.accmod.restrictions.ProtectedExternally;
*
* <p>
* {@link StreamTaskListener} is the most typical implementation of this interface.
* All the {@link TaskListener} implementations passed to plugins from Hudson core are remotable.
*
* <p>
* Implementations are generally expected to be remotable via {@link Channel}.
*
* @author Kohsuke Kawaguchi
*/
...
...
core/src/main/java/hudson/slaves/EnvironmentVariablesNodeProperty.java
浏览文件 @
c508620b
...
...
@@ -39,6 +39,9 @@ import org.kohsuke.stapler.Stapler;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
/**
* {@link NodeProperty} that sets additional environment variables.
...
...
@@ -65,6 +68,14 @@ public class EnvironmentVariablesNodeProperty extends NodeProperty<Node> {
return
envVars
;
}
/**
* @return environment variables using same data type as constructor parameter.
* @since TODO
*/
public
List
<
Entry
>
getEnv
()
{
return
envVars
.
entrySet
().
stream
().
map
(
Entry:
:
new
).
collect
(
Collectors
.
toList
());
}
@Override
public
Environment
setUp
(
AbstractBuild
build
,
Launcher
launcher
,
BuildListener
listener
)
throws
IOException
,
InterruptedException
{
...
...
@@ -100,6 +111,10 @@ public class EnvironmentVariablesNodeProperty extends NodeProperty<Node> {
public
static
class
Entry
{
public
String
key
,
value
;
private
Entry
(
Map
.
Entry
<
String
,
String
>
e
)
{
this
(
e
.
getKey
(),
e
.
getValue
());
}
@DataBoundConstructor
public
Entry
(
String
key
,
String
value
)
{
this
.
key
=
key
;
...
...
core/src/main/java/hudson/tools/ToolInstaller.java
浏览文件 @
c508620b
...
...
@@ -42,12 +42,14 @@ import org.kohsuke.stapler.DataBoundConstructor;
/**
* An object which can ensure that a generic {@link ToolInstallation} in fact exists on a node.
* The properties can be added to {@link ToolInstallation} using the {@link InstallSourceProperty}.
*
* The subclass should have a {@link ToolInstallerDescriptor}.
* A {@code config.jelly} should be provided to customize specific fields;
* {@code <t:label xmlns:t="/hudson/tools"/>} to customize {@code label}.
* @see <a href="http://wiki.jenkins-ci.org/display/JENKINS/Tool+Auto-Installation">Tool Auto-Installation</a>
* @since 1.305
* @see InstallSourceProperty
*/
public
abstract
class
ToolInstaller
implements
Describable
<
ToolInstaller
>,
ExtensionPoint
{
...
...
core/src/main/java/jenkins/security/apitoken/LegacyApiTokenAdministrativeMonitor.java
浏览文件 @
c508620b
...
...
@@ -100,7 +100,7 @@ public class LegacyApiTokenAdministrativeMonitor extends AdministrativeMonitor {
@Restricted
(
NoExternalUse
.
class
)
public
@Nullable
ApiTokenProperty
.
TokenInfoAndStats
getLegacyStatsOf
(
@Nonnull
User
user
,
@Nullable
ApiTokenStore
.
HashedToken
legacyToken
)
{
ApiTokenProperty
apiTokenProperty
=
user
.
getProperty
(
ApiTokenProperty
.
class
);
if
(
legacyToken
!=
null
)
{
if
(
legacyToken
!=
null
)
{
ApiTokenStats
.
SingleTokenStats
legacyStats
=
apiTokenProperty
.
getTokenStats
().
findTokenStatsById
(
legacyToken
.
getUuid
());
ApiTokenProperty
.
TokenInfoAndStats
tokenInfoAndStats
=
new
ApiTokenProperty
.
TokenInfoAndStats
(
legacyToken
,
legacyStats
);
return
tokenInfoAndStats
;
...
...
@@ -116,7 +116,7 @@ public class LegacyApiTokenAdministrativeMonitor extends AdministrativeMonitor {
// used by Jelly view
@Restricted
(
NoExternalUse
.
class
)
public
boolean
hasFreshToken
(
@Nonnull
User
user
,
@Nullable
ApiTokenProperty
.
TokenInfoAndStats
legacyStats
)
{
if
(
legacyStats
==
null
)
{
if
(
legacyStats
==
null
)
{
return
false
;
}
...
...
@@ -140,12 +140,12 @@ public class LegacyApiTokenAdministrativeMonitor extends AdministrativeMonitor {
// used by Jelly view
@Restricted
(
NoExternalUse
.
class
)
public
boolean
hasMoreRecentlyUsedToken
(
@Nonnull
User
user
,
@Nullable
ApiTokenProperty
.
TokenInfoAndStats
legacyStats
)
{
if
(
legacyStats
==
null
)
{
if
(
legacyStats
==
null
)
{
return
false
;
}
ApiTokenProperty
apiTokenProperty
=
user
.
getProperty
(
ApiTokenProperty
.
class
);
return
apiTokenProperty
.
getTokenList
().
stream
()
.
filter
(
token
->
!
token
.
isLegacy
)
.
anyMatch
(
token
->
{
...
...
@@ -161,18 +161,22 @@ public class LegacyApiTokenAdministrativeMonitor extends AdministrativeMonitor {
@RequirePOST
public
HttpResponse
doRevokeAllSelected
(
@JsonBody
RevokeAllSelectedModel
content
)
throws
IOException
{
for
(
RevokeAllSelectedUserAndUuid
value
:
content
.
values
)
{
if
(
value
.
userId
==
null
)
{
// special case not managed by JSONObject
value
.
userId
=
"null"
;
}
User
user
=
User
.
getById
(
value
.
userId
,
false
);
if
(
user
==
null
)
{
LOGGER
.
log
(
Level
.
INFO
,
"User not found id={0}"
,
value
.
userId
);
}
else
{
ApiTokenProperty
apiTokenProperty
=
user
.
getProperty
(
ApiTokenProperty
.
class
);
if
(
apiTokenProperty
==
null
)
{
if
(
apiTokenProperty
==
null
)
{
LOGGER
.
log
(
Level
.
INFO
,
"User without apiTokenProperty found id={0}"
,
value
.
userId
);
}
else
{
}
else
{
ApiTokenStore
.
HashedToken
revokedToken
=
apiTokenProperty
.
getTokenStore
().
revokeToken
(
value
.
uuid
);
if
(
revokedToken
==
null
)
{
if
(
revokedToken
==
null
)
{
LOGGER
.
log
(
Level
.
INFO
,
"User without selected token id={0}, tokenUuid={1}"
,
new
Object
[]{
value
.
userId
,
value
.
uuid
});
}
else
{
}
else
{
apiTokenProperty
.
deleteApiToken
();
user
.
save
();
LOGGER
.
log
(
Level
.
INFO
,
"Revocation success for user id={0}, tokenUuid={1}"
,
new
Object
[]{
value
.
userId
,
value
.
uuid
});
...
...
core/src/main/java/jenkins/security/s2m/AdminWhitelistRule.java
浏览文件 @
c508620b
...
...
@@ -16,6 +16,8 @@ import org.kohsuke.stapler.StaplerProxy;
import
org.kohsuke.stapler.StaplerRequest
;
import
org.kohsuke.stapler.interceptor.RequirePOST
;
import
javax.annotation.CheckReturnValue
;
import
javax.annotation.Nonnull
;
import
java.io.BufferedReader
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
...
...
@@ -52,12 +54,10 @@ public class AdminWhitelistRule implements StaplerProxy {
*/
public
final
FilePathRuleConfig
filePathRules
;
private
final
Jenkins
jenkins
;
private
boolean
masterKillSwitch
;
public
AdminWhitelistRule
()
throws
IOException
,
InterruptedException
{
this
.
jenkins
=
Jenkins
.
getInstance
();
final
Jenkins
jenkins
=
Jenkins
.
get
();
// while this file is not a secret, write access to this file is dangerous,
// so put this in the better-protected part of $JENKINS_HOME, which is in secrets/
...
...
@@ -79,17 +79,21 @@ public class AdminWhitelistRule implements StaplerProxy {
whitelisted
);
this
.
filePathRules
=
new
FilePathRuleConfig
(
new
File
(
jenkins
.
getRootDir
(),
"secrets/filepath-filters.d/50-gui.conf"
));
this
.
masterKillSwitch
=
loadMasterKillSwitchFile
();
File
f
=
getMasterKillSwitchFile
(
jenkins
);
this
.
masterKillSwitch
=
loadMasterKillSwitchFile
(
f
);
}
/**
* Reads the master kill switch.
* Reads the master kill switch
from a file
.
*
* Instead of {@link FileBoolean}, we use a text file so that the admin can prevent Jenkins from
* writing this to file.
* @param f File to load
* @return {@code true} if the file was loaded, {@code false} otherwise
*/
private
boolean
loadMasterKillSwitchFile
()
{
File
f
=
getMasterKillSwitchFile
();
@CheckReturnValue
private
boolean
loadMasterKillSwitchFile
(
@Nonnull
File
f
)
{
try
{
if
(!
f
.
exists
())
return
true
;
return
Boolean
.
parseBoolean
(
FileUtils
.
readFileToString
(
f
).
trim
());
...
...
@@ -99,7 +103,8 @@ public class AdminWhitelistRule implements StaplerProxy {
}
}
private
File
getMasterKillSwitchFile
()
{
@Nonnull
private
File
getMasterKillSwitchFile
(
@Nonnull
Jenkins
jenkins
)
{
return
new
File
(
jenkins
.
getRootDir
(),
"secrets/slave-to-master-security-kill-switch"
);
}
...
...
@@ -155,7 +160,7 @@ public class AdminWhitelistRule implements StaplerProxy {
@RequirePOST
public
HttpResponse
doSubmit
(
StaplerRequest
req
)
throws
IOException
{
jenkins
.
checkPermission
(
Jenkins
.
RUN_SCRIPTS
);
Jenkins
.
get
()
.
checkPermission
(
Jenkins
.
RUN_SCRIPTS
);
String
whitelist
=
Util
.
fixNull
(
req
.
getParameter
(
"whitelist"
));
if
(!
whitelist
.
endsWith
(
"\n"
))
...
...
@@ -206,11 +211,13 @@ public class AdminWhitelistRule implements StaplerProxy {
}
public
void
setMasterKillSwitch
(
boolean
state
)
{
final
Jenkins
jenkins
=
Jenkins
.
get
();
try
{
jenkins
.
checkPermission
(
Jenkins
.
RUN_SCRIPTS
);
FileUtils
.
writeStringToFile
(
getMasterKillSwitchFile
(),
Boolean
.
toString
(
state
));
File
f
=
getMasterKillSwitchFile
(
jenkins
);
FileUtils
.
writeStringToFile
(
f
,
Boolean
.
toString
(
state
));
// treat the file as the canonical source of information in case write fails
masterKillSwitch
=
loadMasterKillSwitchFile
();
masterKillSwitch
=
loadMasterKillSwitchFile
(
f
);
}
catch
(
IOException
e
)
{
LOGGER
.
log
(
WARNING
,
"Failed to write master kill switch"
,
e
);
}
...
...
@@ -221,7 +228,7 @@ public class AdminWhitelistRule implements StaplerProxy {
*/
@Override
public
Object
getTarget
()
{
jenkins
.
checkPermission
(
Jenkins
.
RUN_SCRIPTS
);
Jenkins
.
get
()
.
checkPermission
(
Jenkins
.
RUN_SCRIPTS
);
return
this
;
}
...
...
core/src/main/resources/hudson/cli/Messages.properties
浏览文件 @
c508620b
...
...
@@ -7,6 +7,9 @@ InstallPluginCommand.NoUpdateCenterDefined=Note that no update center is defined
InstallPluginCommand.NoUpdateDataRetrieved
=
No update center data is retrieved yet from: {0}
InstallPluginCommand.NotAValidSourceName
=
{0} is neither a valid file, URL, nor a plugin artifact name in the update center
EnablePluginCommand.NoSuchPlugin
=
No such plugin found with the name {0}
EnablePluginCommand.MissingDependencies
=
Cannot enable plugin {0} as it is missing the dependency {1}
AddJobToViewCommand.ShortDescription
=
\
Adds jobs to view.
BuildCommand.ShortDescription
=
\
...
...
@@ -25,6 +28,8 @@ DeleteViewCommand.ShortDescription=\
Deletes view(s).
DeleteJobCommand.ShortDescription
=
\
Deletes job(s).
EnablePluginCommand.ShortDescription
=
\
Enables one or more installed plugins transitively.
GroovyCommand.ShortDescription
=
\
Executes the specified Groovy script.
GroovyshCommand.ShortDescription
=
\
...
...
core/src/main/resources/hudson/diagnosis/OldDataMonitor/message_zh_CN.properties
浏览文件 @
c508620b
...
...
@@ -21,6 +21,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
You\
have\
data\
stored\
in\
an\
older\
format\
and/or\
unreadable\
data.
=
\u
60A8
\u
6709\u
8CC7
\u6599\u
683C
\u
5F0F
\u
904E
\u
820A
\u6216\u
662F
\u7121\u
6CD5
\u
8B80
\u
53D6
\u3002
You\
have\
data\
stored\
in\
an\
older\
format\
and/or\
unreadable\
data.
=
\u
60A8
\u
7684\u
5B58
\u
50A8
\u
4E2D
\u6709\u
65E0
\u
6CD5
\u
8BFB
\u
53D6
\u6216\u8005\u
65E7
\u7684\u6570\u
636E
\u
683C
\u
5F0F
\u3002
Manage
=
\u
7BA1
\u7406
Dismiss
=
\u
4E0D
\u
518D
\u
663E
\u
793A
core/src/main/resources/hudson/slaves/EnvironmentVariablesNodeProperty/config.jelly
浏览文件 @
c508620b
...
...
@@ -25,7 +25,7 @@ THE SOFTWARE.
<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">
<f:entry title="${%List of variables}" help="${descriptor.getHelpPage()}">
<f:repeatable var="env" items="${instance.env
Vars.entrySet()
}">
<f:repeatable var="env" items="${instance.env}">
<table width="100%">
<f:entry title="${%Name}">
<f:textbox name="env.key" value="${env.key}" />
...
...
core/src/test/java/hudson/PluginWrapperTest.java
浏览文件 @
c508620b
...
...
@@ -15,9 +15,8 @@ import org.mockito.invocation.InvocationOnMock;
import
org.mockito.stubbing.Answer
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
fail
;
import
static
org
.
junit
.
Assert
.*;
import
org.jvnet.hudson.test.Issue
;
import
static
org
.
mockito
.
Matchers
.
any
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
when
;
...
...
@@ -180,4 +179,16 @@ public class PluginWrapperTest {
);
}
}
@Issue
(
"JENKINS-52665"
)
@Test
public
void
isSnapshot
()
{
assertFalse
(
PluginWrapper
.
isSnapshot
(
"1.0"
));
assertFalse
(
PluginWrapper
.
isSnapshot
(
"1.0-alpha-1"
));
assertFalse
(
PluginWrapper
.
isSnapshot
(
"1.0-rc9999.abc123def456"
));
assertTrue
(
PluginWrapper
.
isSnapshot
(
"1.0-SNAPSHOT"
));
assertTrue
(
PluginWrapper
.
isSnapshot
(
"1.0-20180719.153600-1"
));
assertTrue
(
PluginWrapper
.
isSnapshot
(
"1.0-SNAPSHOT (private-abcd1234-jqhacker)"
));
}
}
pom.xml
浏览文件 @
c508620b
...
...
@@ -28,7 +28,7 @@ THE SOFTWARE.
<parent>
<groupId>
org.jenkins-ci
</groupId>
<artifactId>
jenkins
</artifactId>
<version>
1.4
6
</version>
<version>
1.4
8
</version>
<relativePath
/>
</parent>
...
...
@@ -75,7 +75,7 @@ THE SOFTWARE.
</issueManagement>
<properties>
<revision>
2.13
6
</revision>
<revision>
2.13
8
</revision>
<changelist>
-SNAPSHOT
</changelist>
<!-- *.html files are in UTF-8, and *.properties are in iso-8859-1, so this configuration is actually incorrect,
...
...
test/src/test/java/hudson/LauncherTest.java
浏览文件 @
c508620b
...
...
@@ -23,8 +23,10 @@
*/
package
hudson
;
import
hudson.console.LineTransformationOutputStream
;
import
hudson.model.AbstractBuild
;
import
hudson.model.AbstractProject
;
import
hudson.model.BuildListener
;
import
hudson.model.FreeStyleBuild
;
import
hudson.model.FreeStyleProject
;
import
hudson.model.Node
;
...
...
@@ -32,15 +34,27 @@ import hudson.model.ParametersDefinitionProperty;
import
hudson.model.Slave
;
import
hudson.model.StringParameterDefinition
;
import
hudson.model.TaskListener
;
import
hudson.remoting.Channel
;
import
hudson.tasks.BatchFile
;
import
hudson.tasks.BuildStepDescriptor
;
import
hudson.tasks.Builder
;
import
hudson.tasks.CommandInterpreter
;
import
hudson.tasks.Shell
;
import
hudson.util.StreamTaskListener
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.io.PrintStream
;
import
java.nio.charset.StandardCharsets
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.apache.commons.io.FileUtils
;
import
static
org
.
hamcrest
.
Matchers
.*;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assume
.*;
import
org.junit.Rule
;
import
org.junit.Test
;
...
...
@@ -153,4 +167,110 @@ public class LauncherTest {
}
}
@Issue
(
"JENKINS-52729"
)
@Test
public
void
remotable
()
throws
Exception
{
File
log
=
new
File
(
rule
.
jenkins
.
root
,
"log"
);
TaskListener
listener
=
new
RemotableBuildListener
(
log
);
Launcher
.
ProcStarter
ps
=
rule
.
createOnlineSlave
().
createLauncher
(
listener
).
launch
();
if
(
Functions
.
isWindows
())
{
ps
.
cmds
(
"cmd"
,
"/c"
,
"echo"
,
"hello"
);
}
else
{
ps
.
cmds
(
"echo"
,
"hello"
);
}
assertEquals
(
0
,
ps
.
stdout
(
listener
).
join
());
assertThat
(
FileUtils
.
readFileToString
(
log
,
StandardCharsets
.
UTF_8
).
replace
(
"\r\n"
,
"\n"
),
containsString
(
"[master → slave0] $ "
+
(
Functions
.
isWindows
()
?
"cmd /c "
:
""
)
+
"echo hello\n"
+
"[master → slave0] hello"
));
}
private
static
class
RemotableBuildListener
implements
BuildListener
{
private
static
final
long
serialVersionUID
=
1
;
/** location of log file streamed to by multiple sources */
private
final
File
logFile
;
/** records allocation & deserialization history; e.g., {@code master → agentName} */
private
final
String
id
;
private
transient
PrintStream
logger
;
RemotableBuildListener
(
File
logFile
)
{
this
(
logFile
,
"master"
);
}
private
RemotableBuildListener
(
File
logFile
,
String
id
)
{
this
.
logFile
=
logFile
;
this
.
id
=
id
;
}
@Override
public
PrintStream
getLogger
()
{
if
(
logger
==
null
)
{
final
OutputStream
fos
;
try
{
fos
=
new
FileOutputStream
(
logFile
,
true
);
logger
=
new
PrintStream
(
new
LineTransformationOutputStream
()
{
@Override
protected
void
eol
(
byte
[]
b
,
int
len
)
throws
IOException
{
fos
.
write
((
"["
+
id
+
"] "
).
getBytes
(
StandardCharsets
.
UTF_8
));
fos
.
write
(
b
,
0
,
len
);
}
},
true
,
"UTF-8"
);
}
catch
(
IOException
x
)
{
throw
new
AssertionError
(
x
);
}
}
return
logger
;
}
private
Object
writeReplace
()
{
Thread
.
dumpStack
();
String
name
=
Channel
.
current
().
getName
();
return
new
RemotableBuildListener
(
logFile
,
id
+
" → "
+
name
);
}
}
@Issue
(
"JENKINS-52729"
)
@Test
public
void
multipleStdioCalls
()
throws
Exception
{
Node
master
=
rule
.
jenkins
;
Node
agent
=
rule
.
createOnlineSlave
();
for
(
Node
node
:
new
Node
[]
{
master
,
agent
})
{
assertMultipleStdioCalls
(
"first TaskListener then OutputStream"
,
node
,
false
,
(
ps
,
os1
,
os2
,
os2Listener
)
->
{
ps
.
stdout
(
os2Listener
).
stdout
(
os1
);
assertEquals
(
os1
,
ps
.
stdout
());
},
false
);
assertMultipleStdioCalls
(
"first OutputStream then TaskListener"
,
node
,
false
,
(
ps
,
os1
,
os2
,
os2Listener
)
->
{
ps
.
stdout
(
os1
).
stdout
(
os2Listener
);
assertEquals
(
os2Listener
.
getLogger
(),
ps
.
stdout
());
},
true
);
assertMultipleStdioCalls
(
"stdout then stderr"
,
node
,
true
,
(
ps
,
os1
,
os2
,
os2Listener
)
->
{
ps
.
stdout
(
os1
).
stderr
(
os2
);
assertEquals
(
os1
,
ps
.
stdout
());
assertEquals
(
os2
,
ps
.
stderr
());
},
true
);
assertMultipleStdioCalls
(
"stderr then stdout"
,
node
,
true
,
(
ps
,
os1
,
os2
,
os2Listener
)
->
{
ps
.
stdout
(
os1
).
stderr
(
os2
);
assertEquals
(
os1
,
ps
.
stdout
());
assertEquals
(
os2
,
ps
.
stderr
());
},
true
);
}
}
@FunctionalInterface
private
interface
ProcStarterCustomizer
{
void
run
(
Launcher
.
ProcStarter
ps
,
OutputStream
os1
,
OutputStream
os2
,
TaskListener
os2Listener
)
throws
Exception
;
}
private
void
assertMultipleStdioCalls
(
String
message
,
Node
node
,
boolean
emitStderr
,
ProcStarterCustomizer
psCustomizer
,
boolean
outputIn2
)
throws
Exception
{
message
=
node
.
getDisplayName
()
+
": "
+
message
;
Launcher
launcher
=
node
.
createLauncher
(
StreamTaskListener
.
fromStderr
());
Launcher
.
ProcStarter
ps
=
launcher
.
launch
();
assumeFalse
(
"should not be platform-dependent, not bothering for now"
,
Functions
.
isWindows
());
if
(
emitStderr
)
{
ps
.
cmds
(
"sh"
,
"-c"
,
"echo hello >&2"
).
quiet
(
true
);
}
else
{
ps
.
cmds
(
"echo"
,
"hello"
);
}
ByteArrayOutputStream
baos1
=
new
ByteArrayOutputStream
();
ByteArrayOutputStream
baos2
=
new
ByteArrayOutputStream
();
TaskListener
listener
=
new
StreamTaskListener
(
baos2
);
psCustomizer
.
run
(
ps
,
baos1
,
baos2
,
listener
);
assertEquals
(
message
,
0
,
ps
.
join
());
if
(
outputIn2
)
{
assertThat
(
message
,
baos2
.
toString
(),
containsString
(
"hello"
));
assertThat
(
message
,
baos1
.
toString
(),
isEmptyString
());
}
else
{
assertThat
(
message
,
baos1
.
toString
(),
containsString
(
"hello"
));
assertThat
(
message
,
baos2
.
toString
(),
isEmptyString
());
}
}
}
test/src/test/java/hudson/cli/EnablePluginCommandTest.java
0 → 100644
浏览文件 @
c508620b
/*
* The MIT License
*
* Copyright (c) 2018 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.
*/
package
hudson.cli
;
import
hudson.PluginManager
;
import
hudson.PluginWrapper
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.jvnet.hudson.test.JenkinsRule
;
import
java.io.IOException
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
failedWith
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
succeeded
;
import
static
org
.
hamcrest
.
Matchers
.*;
import
static
org
.
junit
.
Assert
.*;
public
class
EnablePluginCommandTest
{
@Rule
public
JenkinsRule
j
=
new
JenkinsRule
();
private
CLICommandInvoker
.
Result
installTestPlugin
(
String
name
)
{
return
new
CLICommandInvoker
(
j
,
new
InstallPluginCommand
())
.
withStdin
(
EnablePluginCommandTest
.
class
.
getResourceAsStream
(
"/plugins/"
+
name
+
".hpi"
))
.
invokeWithArgs
(
"-name"
,
name
,
"-deploy"
,
"="
);
}
private
CLICommandInvoker
.
Result
enablePlugins
(
String
...
names
)
{
return
new
CLICommandInvoker
(
j
,
new
EnablePluginCommand
()).
invokeWithArgs
(
names
);
}
@Test
public
void
enableSinglePlugin
()
throws
IOException
{
String
name
=
"token-macro"
;
PluginManager
m
=
j
.
getPluginManager
();
assertThat
(
m
.
getPlugin
(
name
),
is
(
nullValue
()));
assertThat
(
installTestPlugin
(
"token-macro"
),
succeeded
());
PluginWrapper
wrapper
=
m
.
getPlugin
(
name
);
assertThat
(
wrapper
,
is
(
notNullValue
()));
assertTrue
(
wrapper
.
isEnabled
());
wrapper
.
disable
();
assertFalse
(
wrapper
.
isEnabled
());
assertThat
(
enablePlugins
(
name
),
succeeded
());
assertTrue
(
wrapper
.
isEnabled
());
}
@Test
public
void
enableInvalidPluginFails
()
{
assertThat
(
new
CLICommandInvoker
(
j
,
"enable-plugin"
).
invokeWithArgs
(
"foobar"
),
failedWith
(
3
)
);
}
@Test
public
void
enableDependerEnablesDependee
()
throws
IOException
{
installTestPlugin
(
"dependee"
);
installTestPlugin
(
"depender"
);
PluginManager
m
=
j
.
getPluginManager
();
PluginWrapper
depender
=
m
.
getPlugin
(
"depender"
);
assertThat
(
depender
,
is
(
notNullValue
()));
PluginWrapper
dependee
=
m
.
getPlugin
(
"dependee"
);
assertThat
(
dependee
,
is
(
notNullValue
()));
depender
.
disable
();
dependee
.
disable
();
assertThat
(
enablePlugins
(
"depender"
),
succeeded
());
assertTrue
(
depender
.
isEnabled
());
assertTrue
(
dependee
.
isEnabled
());
}
}
test/src/test/java/hudson/model/QueueTest.java
浏览文件 @
c508620b
...
...
@@ -123,6 +123,7 @@ import java.util.concurrent.TimeoutException;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.logging.Level
;
import
static
org
.
hamcrest
.
Matchers
.
contains
;
import
static
org
.
hamcrest
.
Matchers
.
nullValue
;
import
static
org
.
junit
.
Assert
.*;
import
org.junit.Ignore
;
...
...
@@ -458,6 +459,31 @@ public class QueueTest {
assert
task
.
exec
instanceof
OneOffExecutor
:
task
.
exec
;
}
@Issue
(
"JENKINS-41127"
)
@Test
public
void
flyweightTasksUnwantedConcurrency
()
throws
Exception
{
Label
label
=
r
.
jenkins
.
getSelfLabel
();
AtomicInteger
cnt
=
new
AtomicInteger
();
TestFlyweightTask
task1
=
new
TestFlyweightTask
(
cnt
,
label
);
TestFlyweightTask
task2
=
new
TestFlyweightTask
(
cnt
,
label
);
assertFalse
(
task1
.
isConcurrentBuild
());
assertFalse
(
task2
.
isConcurrentBuild
());
// We need to call Queue#maintain without any interleaving Queue modification to reproduce the issue.
Queue
.
withLock
(()
->
{
r
.
jenkins
.
getQueue
().
schedule2
(
task1
,
0
);
r
.
jenkins
.
getQueue
().
maintain
();
Queue
.
Item
item1
=
r
.
jenkins
.
getQueue
().
getItem
(
task1
);
assertThat
(
r
.
jenkins
.
getQueue
().
getPendingItems
(),
contains
(
item1
));
r
.
jenkins
.
getQueue
().
schedule2
(
task2
,
0
);
r
.
jenkins
.
getQueue
().
maintain
();
Queue
.
Item
item2
=
r
.
jenkins
.
getQueue
().
getItem
(
task2
);
// Before the fix, item1 would no longer be present in the pending items (but would
// still be assigned to a live executor), and item2 would not be blocked, which would
// allow the tasks to execute concurrently.
assertThat
(
r
.
jenkins
.
getQueue
().
getPendingItems
(),
contains
(
item1
));
assertTrue
(
item2
.
isBlocked
());
});
}
@Issue
(
"JENKINS-27256"
)
@Test
public
void
inQueueTaskLookupByAPI
()
throws
Exception
{
FreeStyleProject
p
=
r
.
createFreeStyleProject
();
...
...
test/src/test/java/jenkins/security/apitoken/LegacyApiTokenAdministrativeMonitorTest.java
浏览文件 @
c508620b
...
...
@@ -38,6 +38,7 @@ import org.apache.commons.lang.StringUtils;
import
org.hamcrest.Matchers
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.jvnet.hudson.test.Issue
;
import
org.jvnet.hudson.test.JenkinsRule
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
...
...
@@ -51,6 +52,18 @@ public class LegacyApiTokenAdministrativeMonitorTest {
@Rule
public
JenkinsRule
j
=
new
JenkinsRule
();
private
enum
SelectFilter
{
ALL
(
0
),
ONLY_FRESH
(
1
),
ONLY_RECENT
(
2
);
int
index
;
SelectFilter
(
int
index
)
{
this
.
index
=
index
;
}
}
@Test
public
void
isActive
()
throws
Exception
{
ApiTokenPropertyConfiguration
config
=
ApiTokenPropertyConfiguration
.
get
();
...
...
@@ -76,6 +89,40 @@ public class LegacyApiTokenAdministrativeMonitorTest {
assertTrue
(
monitor
.
isActivated
());
}
@Test
@Issue
(
"JENKINS-52441"
)
public
void
takeCareOfUserWithIdNull
()
throws
Exception
{
ApiTokenPropertyConfiguration
config
=
ApiTokenPropertyConfiguration
.
get
();
config
.
setCreationOfLegacyTokenEnabled
(
true
);
config
.
setTokenGenerationOnCreationEnabled
(
false
);
// user created without legacy token
User
user
=
User
.
getById
(
"null"
,
true
);
ApiTokenProperty
apiTokenProperty
=
user
.
getProperty
(
ApiTokenProperty
.
class
);
assertFalse
(
apiTokenProperty
.
hasLegacyToken
());
LegacyApiTokenAdministrativeMonitor
monitor
=
j
.
jenkins
.
getExtensionList
(
AdministrativeMonitor
.
class
).
get
(
LegacyApiTokenAdministrativeMonitor
.
class
);
assertFalse
(
monitor
.
isActivated
());
apiTokenProperty
.
changeApiToken
();
assertTrue
(
monitor
.
isActivated
());
{
//revoke the legacy token
JenkinsRule
.
WebClient
wc
=
j
.
createWebClient
();
HtmlPage
page
=
wc
.
goTo
(
monitor
.
getUrl
()
+
"/manage"
);
{
// select all (only one user normally)
HtmlAnchor
filterAll
=
getFilterByIndex
(
page
,
SelectFilter
.
ALL
);
HtmlElementUtil
.
click
(
filterAll
);
}
// revoke them
HtmlButton
revokeSelected
=
getRevokeSelected
(
page
);
HtmlElementUtil
.
click
(
revokeSelected
);
}
assertFalse
(
monitor
.
isActivated
());
}
@Test
public
void
listOfUserWithLegacyTokenIsCorrect
()
throws
Exception
{
j
.
jenkins
.
setSecurityRealm
(
j
.
createDummySecurityRealm
());
...
...
@@ -254,7 +301,7 @@ public class LegacyApiTokenAdministrativeMonitorTest {
checkUserWithLegacyTokenListHasSizeOf
(
page
,
1
+
2
+
3
+
4
,
2
+
4
,
3
+
4
);
{
// select 2
HtmlAnchor
filterOnlyFresh
=
getFilterByIndex
(
page
,
1
);
HtmlAnchor
filterOnlyFresh
=
getFilterByIndex
(
page
,
SelectFilter
.
ONLY_FRESH
);
HtmlElementUtil
.
click
(
filterOnlyFresh
);
}
// revoke them
...
...
@@ -265,7 +312,7 @@ public class LegacyApiTokenAdministrativeMonitorTest {
assertTrue
(
monitor
.
isActivated
());
{
// select 1 + 3
HtmlAnchor
filterAll
=
getFilterByIndex
(
newPage
,
0
);
HtmlAnchor
filterAll
=
getFilterByIndex
(
newPage
,
SelectFilter
.
ALL
);
HtmlElementUtil
.
click
(
filterAll
);
}
// revoke them
...
...
@@ -275,13 +322,13 @@ public class LegacyApiTokenAdministrativeMonitorTest {
assertFalse
(
monitor
.
isActivated
());
}
private
HtmlAnchor
getFilterByIndex
(
HtmlPage
page
,
int
index
)
{
private
HtmlAnchor
getFilterByIndex
(
HtmlPage
page
,
SelectFilter
selectFilter
)
{
HtmlElement
document
=
page
.
getDocumentElement
();
HtmlDivision
filterDiv
=
document
.
getOneHtmlElementByAttribute
(
"div"
,
"class"
,
"selection-panel"
);
DomNodeList
<
HtmlElement
>
filters
=
filterDiv
.
getElementsByTagName
(
"a"
);
assertEquals
(
3
,
filters
.
size
());
HtmlAnchor
filter
=
(
HtmlAnchor
)
filters
.
get
(
index
);
HtmlAnchor
filter
=
(
HtmlAnchor
)
filters
.
get
(
selectFilter
.
index
);
assertNotNull
(
filter
);
return
filter
;
}
...
...
@@ -341,7 +388,7 @@ public class LegacyApiTokenAdministrativeMonitorTest {
private
void
createUserWithToken
(
boolean
legacy
,
boolean
fresh
,
boolean
recent
)
throws
Exception
{
User
user
=
User
.
getById
(
String
.
format
(
"user %b %b %b %d"
,
legacy
,
fresh
,
recent
,
nextId
++),
true
);
if
(!
legacy
)
{
return
;
return
;
}
ApiTokenProperty
apiTokenProperty
=
user
.
getProperty
(
ApiTokenProperty
.
class
);
...
...
war/src/main/webapp/css/style.css
浏览文件 @
c508620b
...
...
@@ -1067,6 +1067,7 @@ table.parameters > tbody:hover {
}
.build-row.multi-line
.build-row-cell
.pane.build-name.block
{
padding-right
:
20px
;
width
:
100%
;
}
.build-row-cell
.pane.build-controls.block
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录