Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
jenkins
提交
b2651f22
J
jenkins
项目概览
xxadev
/
jenkins
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
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,发现更多精彩内容 >>
提交
b2651f22
编写于
10月 16, 2013
作者:
O
Oliver Gondža
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[JENKINS-19996] Support nested views in Jenkins CLI
上级
29d44133
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
290 addition
and
17 deletion
+290
-17
core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java
.../src/main/java/hudson/cli/handlers/ViewOptionHandler.java
+48
-5
core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java
.../test/java/hudson/cli/handlers/ViewOptionHandlerTest.java
+232
-0
test/src/test/java/hudson/cli/DeleteViewCommandTest.java
test/src/test/java/hudson/cli/DeleteViewCommandTest.java
+5
-5
test/src/test/java/hudson/cli/GetViewCommandTest.java
test/src/test/java/hudson/cli/GetViewCommandTest.java
+1
-3
test/src/test/java/hudson/cli/UpdateViewCommandTest.java
test/src/test/java/hudson/cli/UpdateViewCommandTest.java
+4
-4
未找到文件。
core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java
浏览文件 @
b2651f22
...
@@ -23,7 +23,11 @@
...
@@ -23,7 +23,11 @@
*/
*/
package
hudson.cli.handlers
;
package
hudson.cli.handlers
;
import
hudson.model.ViewGroup
;
import
hudson.model.View
;
import
hudson.model.View
;
import
java.util.StringTokenizer
;
import
jenkins.model.Jenkins
;
import
jenkins.model.Jenkins
;
import
org.kohsuke.MetaInfServices
;
import
org.kohsuke.MetaInfServices
;
...
@@ -37,6 +41,20 @@ import org.kohsuke.args4j.spi.Setter;
...
@@ -37,6 +41,20 @@ import org.kohsuke.args4j.spi.Setter;
/**
/**
* Refers to {@link View} by its name.
* Refers to {@link View} by its name.
*
*
* <p>
* For example:
* <dl>
* <dt>my_view_name</dt><dd>refers to a top level view with given name.</dd>
* <dt>nested/inner</dt><dd>refers to a view named <tt>inner</tt> inside of a top level view group named <tt>nested</tt>.</dd>
* </dl>
*
* <p>
* View name is a non-empty sequence of {@link View} names delimited by '/'.
* Handler traverse the view names from left to right. First one is expected to
* be a top level view and all but the last one are expected to be instances of
* {@link ViewGroup}. Handler fails to resolve view provided a view with given
* name does not exist or a user was not granted {@link View.READ} permission.
*
* @author ogondza
* @author ogondza
* @since TODO
* @since TODO
*/
*/
...
@@ -51,13 +69,38 @@ public class ViewOptionHandler extends OptionHandler<View> {
...
@@ -51,13 +69,38 @@ public class ViewOptionHandler extends OptionHandler<View> {
@Override
@Override
public
int
parseArguments
(
Parameters
params
)
throws
CmdLineException
{
public
int
parseArguments
(
Parameters
params
)
throws
CmdLineException
{
String
viewName
=
params
.
getParameter
(
0
);
setter
.
addValue
(
getView
(
params
.
getParameter
(
0
)));
return
1
;
}
final
View
view
=
Jenkins
.
getInstance
().
getView
(
viewName
);
private
View
getView
(
String
name
)
throws
CmdLineException
{
if
(
view
==
null
)
throw
new
CmdLineException
(
owner
,
"No such view '"
+
viewName
+
"'"
);
setter
.
addValue
(
view
);
View
view
=
null
;
return
1
;
ViewGroup
group
=
Jenkins
.
getInstance
();
final
StringTokenizer
tok
=
new
StringTokenizer
(
name
,
"/"
);
while
(
tok
.
hasMoreTokens
())
{
String
viewName
=
tok
.
nextToken
();
view
=
group
.
getView
(
viewName
);
if
(
view
==
null
)
throw
new
CmdLineException
(
owner
,
String
.
format
(
"No view named %s inside view %s"
,
viewName
,
group
.
getDisplayName
()
));
view
.
checkPermission
(
View
.
READ
);
if
(
view
instanceof
ViewGroup
)
{
group
=
(
ViewGroup
)
view
;
}
else
if
(
tok
.
hasMoreTokens
())
{
throw
new
CmdLineException
(
owner
,
view
.
getViewName
()
+
" view can not contain views"
);
}
}
return
view
;
}
}
@Override
@Override
...
...
core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java
0 → 100644
浏览文件 @
b2651f22
/*
* The MIT License
*
* Copyright (c) 2013 Red Hat, 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.handlers
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
fail
;
import
static
org
.
mockito
.
Mockito
.
doThrow
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
verifyNoMoreInteractions
;
import
static
org
.
mockito
.
Mockito
.
verifyZeroInteractions
;
import
static
org
.
mockito
.
Mockito
.
when
;
import
hudson.model.ViewGroup
;
import
hudson.model.View
;
import
jenkins.model.Jenkins
;
import
org.acegisecurity.AccessDeniedException
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.kohsuke.args4j.CmdLineException
;
import
org.kohsuke.args4j.spi.Parameters
;
import
org.kohsuke.args4j.spi.Setter
;
import
org.mockito.Mock
;
import
org.mockito.MockitoAnnotations
;
import
org.powermock.api.mockito.PowerMockito
;
import
org.powermock.core.classloader.annotations.PrepareForTest
;
import
org.powermock.modules.junit4.PowerMockRunner
;
@PrepareForTest
(
Jenkins
.
class
)
@RunWith
(
PowerMockRunner
.
class
)
public
class
ViewOptionHandlerTest
{
@Mock
private
Setter
<
View
>
setter
;
private
ViewOptionHandler
handler
;
// Hierarchy of views used as a shared fixture:
// $JENKINS_URL/view/outer/view/nested/view/inner/
@Mock
private
View
inner
;
@Mock
private
CompositeView
nested
;
@Mock
private
CompositeView
outer
;
@Mock
private
Jenkins
jenkins
;
@Before
public
void
setUp
()
{
MockitoAnnotations
.
initMocks
(
this
);
handler
=
new
ViewOptionHandler
(
null
,
null
,
setter
);
when
(
inner
.
getViewName
()).
thenReturn
(
"inner"
);
when
(
inner
.
getDisplayName
()).
thenCallRealMethod
();
when
(
nested
.
getViewName
()).
thenReturn
(
"nested"
);
when
(
nested
.
getDisplayName
()).
thenCallRealMethod
();
when
(
nested
.
getView
(
"inner"
)).
thenReturn
(
inner
);
when
(
outer
.
getViewName
()).
thenReturn
(
"outer"
);
when
(
outer
.
getDisplayName
()).
thenCallRealMethod
();
when
(
outer
.
getView
(
"nested"
)).
thenReturn
(
nested
);
PowerMockito
.
mockStatic
(
Jenkins
.
class
);
PowerMockito
.
when
(
Jenkins
.
getInstance
()).
thenReturn
(
jenkins
);
when
(
jenkins
.
getView
(
"outer"
)).
thenReturn
(
outer
);
when
(
jenkins
.
getDisplayName
()).
thenReturn
(
"Jenkins"
);
}
@Test
public
void
resolveTopLevelView
()
throws
Exception
{
parse
(
"outer"
);
verify
(
setter
).
addValue
(
outer
);
}
@Test
public
void
resolveNestedView
()
throws
Exception
{
parse
(
"outer/nested"
);
verify
(
setter
).
addValue
(
nested
);
}
@Test
public
void
resolveOuterView
()
throws
Exception
{
parse
(
"outer/nested/inner"
);
verify
(
setter
).
addValue
(
inner
);
}
@Test
public
void
ignoreLeadingAndTrailingSlashes
()
throws
Exception
{
parse
(
"/outer/nested/inner/"
);
verify
(
setter
).
addValue
(
inner
);
}
@Test
public
void
reportNonexistentTopLevelView
()
throws
Exception
{
assertEquals
(
"No view named missing_view inside view Jenkins"
,
parseFailedWith
(
CmdLineException
.
class
,
"missing_view"
)
);
verifyZeroInteractions
(
setter
);
}
@Test
public
void
reportNonexistentNestedView
()
throws
Exception
{
assertEquals
(
"No view named missing_view inside view outer"
,
parseFailedWith
(
CmdLineException
.
class
,
"outer/missing_view"
)
);
verifyZeroInteractions
(
setter
);
}
@Test
public
void
reportNonexistentInnerView
()
throws
Exception
{
assertEquals
(
"No view named missing_view inside view nested"
,
parseFailedWith
(
CmdLineException
.
class
,
"outer/nested/missing_view"
)
);
verifyZeroInteractions
(
setter
);
}
@Test
public
void
reportTraversingViewThatIsNotAViewGroup
()
throws
Exception
{
assertEquals
(
"inner view can not contain views"
,
parseFailedWith
(
CmdLineException
.
class
,
"outer/nested/inner/missing"
)
);
verifyZeroInteractions
(
setter
);
}
@Test
public
void
refuseToReadOuterView
()
throws
Exception
{
denyAccessOn
(
outer
);
parseFailedWith
(
AccessDeniedException
.
class
,
"outer/nested/inner"
);
verify
(
outer
).
checkPermission
(
View
.
READ
);
verifyNoMoreInteractions
(
outer
);
verifyZeroInteractions
(
nested
);
verifyZeroInteractions
(
inner
);
verifyZeroInteractions
(
setter
);
}
@Test
public
void
refuseToReadNestedView
()
throws
Exception
{
denyAccessOn
(
nested
);
parseFailedWith
(
AccessDeniedException
.
class
,
"outer/nested/inner"
);
verify
(
nested
).
checkPermission
(
View
.
READ
);
verifyNoMoreInteractions
(
nested
);
verifyZeroInteractions
(
inner
);
verifyZeroInteractions
(
setter
);
}
@Test
public
void
refuseToReadInnerView
()
throws
Exception
{
denyAccessOn
(
inner
);
parseFailedWith
(
AccessDeniedException
.
class
,
"outer/nested/inner"
);
verify
(
inner
).
checkPermission
(
View
.
READ
);
verifyNoMoreInteractions
(
inner
);
verifyZeroInteractions
(
setter
);
}
private
void
denyAccessOn
(
View
view
)
{
doThrow
(
new
AccessDeniedException
(
null
)).
when
(
view
).
checkPermission
(
View
.
READ
);
}
private
String
parseFailedWith
(
Class
<?
extends
Exception
>
type
,
final
String
...
params
)
throws
Exception
{
try
{
parse
(
params
);
}
catch
(
Exception
ex
)
{
if
(!
type
.
isAssignableFrom
(
ex
.
getClass
()))
throw
ex
;
return
ex
.
getMessage
();
}
fail
(
"No exception thrown. Expected "
+
type
.
getClass
());
return
null
;
}
private
void
parse
(
final
String
...
params
)
throws
CmdLineException
{
handler
.
parseArguments
(
new
Parameters
()
{
public
String
getParameter
(
int
idx
)
throws
CmdLineException
{
return
params
[
idx
];
}
public
int
size
()
{
return
params
.
length
;
}
});
}
private
static
abstract
class
CompositeView
extends
View
implements
ViewGroup
{
protected
CompositeView
(
String
name
)
{
super
(
name
);
}
}
}
test/src/test/java/hudson/cli/DeleteViewCommandTest.java
浏览文件 @
b2651f22
...
@@ -60,7 +60,7 @@ public class DeleteViewCommandTest {
...
@@ -60,7 +60,7 @@ public class DeleteViewCommandTest {
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
Jenkins
.
READ
)
.
invokeWithArgs
(
"aView"
)
.
invokeWithArgs
(
"aView"
)
;
;
...
@@ -74,7 +74,7 @@ public class DeleteViewCommandTest {
...
@@ -74,7 +74,7 @@ public class DeleteViewCommandTest {
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
View
.
DELETE
,
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
View
.
DELETE
,
Jenkins
.
READ
)
.
invokeWithArgs
(
"aView"
)
.
invokeWithArgs
(
"aView"
)
;
;
...
@@ -87,20 +87,20 @@ public class DeleteViewCommandTest {
...
@@ -87,20 +87,20 @@ public class DeleteViewCommandTest {
@Test
public
void
deleteViewShouldFailIfViewDoesNotExist
()
{
@Test
public
void
deleteViewShouldFailIfViewDoesNotExist
()
{
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
View
.
DELETE
,
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
View
.
DELETE
,
Jenkins
.
READ
)
.
invokeWithArgs
(
"never_created"
)
.
invokeWithArgs
(
"never_created"
)
;
;
assertThat
(
result
,
failedWith
(-
1
));
assertThat
(
result
,
failedWith
(-
1
));
assertThat
(
result
,
hasNoStandardOutput
());
assertThat
(
result
,
hasNoStandardOutput
());
assertThat
(
result
.
stderr
(),
containsString
(
"No
such view 'never_created'
"
));
assertThat
(
result
.
stderr
(),
containsString
(
"No
view named never_created inside view Jenkins
"
));
}
}
// ViewGroup.canDelete()
// ViewGroup.canDelete()
@Test
public
void
deleteViewShouldFailIfViewGroupDoesNotAllowDeletion
()
{
@Test
public
void
deleteViewShouldFailIfViewGroupDoesNotAllowDeletion
()
{
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
View
.
DELETE
,
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
View
.
DELETE
,
Jenkins
.
READ
)
.
invokeWithArgs
(
"All"
)
.
invokeWithArgs
(
"All"
)
;
;
...
...
test/src/test/java/hudson/cli/GetViewCommandTest.java
浏览文件 @
b2651f22
...
@@ -26,9 +26,7 @@ package hudson.cli;
...
@@ -26,9 +26,7 @@ package hudson.cli;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
hamcrest
.
Matchers
.
startsWith
;
import
static
org
.
hamcrest
.
Matchers
.
startsWith
;
import
static
org
.
hamcrest
.
text
.
IsEmptyString
.
isEmptyString
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
failedWith
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
failedWith
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
hasNoStandardOutput
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
hasNoStandardOutput
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
hasNoErrorOutput
;
import
static
hudson
.
cli
.
CLICommandInvoker
.
Matcher
.
hasNoErrorOutput
;
...
@@ -94,6 +92,6 @@ public class GetViewCommandTest {
...
@@ -94,6 +92,6 @@ public class GetViewCommandTest {
assertThat
(
result
,
failedWith
(-
1
));
assertThat
(
result
,
failedWith
(-
1
));
assertThat
(
result
,
hasNoStandardOutput
());
assertThat
(
result
,
hasNoStandardOutput
());
assertThat
(
result
.
stderr
(),
containsString
(
"No
such view 'never_created'
"
));
assertThat
(
result
.
stderr
(),
containsString
(
"No
view named never_created inside view Jenkins
"
));
}
}
}
}
test/src/test/java/hudson/cli/UpdateViewCommandTest.java
浏览文件 @
b2651f22
...
@@ -57,7 +57,7 @@ public class UpdateViewCommandTest {
...
@@ -57,7 +57,7 @@ public class UpdateViewCommandTest {
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
Jenkins
.
READ
)
.
withStdin
(
this
.
getClass
().
getResourceAsStream
(
"/hudson/cli/view.xml"
))
.
withStdin
(
this
.
getClass
().
getResourceAsStream
(
"/hudson/cli/view.xml"
))
.
invokeWithArgs
(
"aView"
)
.
invokeWithArgs
(
"aView"
)
;
;
...
@@ -72,7 +72,7 @@ public class UpdateViewCommandTest {
...
@@ -72,7 +72,7 @@ public class UpdateViewCommandTest {
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
j
.
jenkins
.
addView
(
new
ListView
(
"aView"
));
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
View
.
CONFIGURE
,
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
View
.
CONFIGURE
,
Jenkins
.
READ
)
.
withStdin
(
this
.
getClass
().
getResourceAsStream
(
"/hudson/cli/view.xml"
))
.
withStdin
(
this
.
getClass
().
getResourceAsStream
(
"/hudson/cli/view.xml"
))
.
invokeWithArgs
(
"aView"
)
.
invokeWithArgs
(
"aView"
)
;
;
...
@@ -91,13 +91,13 @@ public class UpdateViewCommandTest {
...
@@ -91,13 +91,13 @@ public class UpdateViewCommandTest {
@Test
public
void
updateViewShouldFailIfViewDoesNotExist
()
{
@Test
public
void
updateViewShouldFailIfViewDoesNotExist
()
{
final
CLICommandInvoker
.
Result
result
=
command
final
CLICommandInvoker
.
Result
result
=
command
.
authorizedTo
(
View
.
CONFIGURE
,
Jenkins
.
READ
)
.
authorizedTo
(
View
.
READ
,
View
.
CONFIGURE
,
Jenkins
.
READ
)
.
withStdin
(
this
.
getClass
().
getResourceAsStream
(
"/hudson/cli/view.xml"
))
.
withStdin
(
this
.
getClass
().
getResourceAsStream
(
"/hudson/cli/view.xml"
))
.
invokeWithArgs
(
"not_created"
)
.
invokeWithArgs
(
"not_created"
)
;
;
assertThat
(
result
,
failedWith
(-
1
));
assertThat
(
result
,
failedWith
(-
1
));
assertThat
(
result
,
hasNoStandardOutput
());
assertThat
(
result
,
hasNoStandardOutput
());
assertThat
(
result
.
stderr
(),
containsString
(
"No
such view 'not_created'
"
));
assertThat
(
result
.
stderr
(),
containsString
(
"No
view named not_created inside view Jenkins
"
));
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录