Skip to content
Permalink
Browse files

[FIXED JENKINS-18938] Added a field to specify the suffix for the var…

…iable to store the build number
  • Loading branch information...
ikedam committed Aug 10, 2015
1 parent e68ed44 commit 462bf8f9b7374300e7a8f3b445787fc22d005c4b
@@ -75,6 +75,7 @@
import org.kohsuke.stapler.StaplerRequest;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* Build step to copy artifacts from another project.
@@ -96,6 +97,7 @@
@Deprecated private transient Boolean stable;
private Boolean flatten, optional;
private boolean doNotFingerprintArtifacts;
private String resultVariableSuffix;

@Deprecated
public CopyArtifact(String projectName, String parameters, BuildSelector selector, String filter, String target,
@@ -154,6 +156,7 @@ public CopyArtifact(String projectName) {
setFlatten(false);
setOptional(false);
setFingerprintArtifacts(false);
setResultVariableSuffix(null);
}

@DataBoundSetter
@@ -196,6 +199,16 @@ public void setFingerprintArtifacts(boolean fingerprintArtifacts) {
this.doNotFingerprintArtifacts = !fingerprintArtifacts;
}

/**
* Set the suffix for variables to store copying results.
*
* @param resultVariableSuffix
*/
@DataBoundSetter
public void setResultVariableSuffix(String resultVariableSuffix) {
this.resultVariableSuffix = Util.fixEmptyAndTrim(resultVariableSuffix);
}

// Upgrade data from old format
public static class ConverterImpl extends XStream2.PassthruConverter<CopyArtifact> {
public ConverterImpl(XStream2 xstream) { super(xstream); }
@@ -302,6 +315,13 @@ public boolean isOptional() {
return optional != null && optional;
}

/**
* @return the suffix for variables to store copying results.
*/
public String getResultVariableSuffix() {
return resultVariableSuffix;
}

private boolean upgradeIfNecessary(AbstractProject<?,?> job) throws IOException {
if (isUpgradeNeeded()) {
Jenkins jenkins = Jenkins.getInstance();
@@ -386,7 +406,7 @@ public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace, @Nonn
envData = new EnvAction();
build.addAction(envData);
}
envData.add(getItemGroup(build), expandedProject, src.getNumber());
envData.add(build, src, expandedProject, getResultVariableSuffix());
if (target.length() > 0) targetDir = new FilePath(targetDir, env.expand(target));
expandedFilter = env.expand(filter);
if (expandedFilter.trim().length() == 0) expandedFilter = "**";
@@ -464,7 +484,7 @@ private boolean canReadFrom(Job<?, ?> job, Run<?, ?> build) {
return b;
}

private Job<?, ?> getRootProject(Job<?, ?> job) {
private static Job<?, ?> getRootProject(Job<?, ?> job) {
if (job instanceof AbstractProject) {
return ((AbstractProject<?,?>)job).getRootProject();
} else {
@@ -473,7 +493,7 @@ private boolean canReadFrom(Job<?, ?> job, Run<?, ?> build) {
}

// retrieve the "folder" (jenkins root if no folder used) for this build
private ItemGroup getItemGroup(Run<?, ?> build) {
private static ItemGroup getItemGroup(Run<?, ?> build) {
return getRootProject(build.getParent()).getParent();
}

@@ -616,9 +636,10 @@ public void onRenamed(Item item, String oldName, String newName) {
// Decided not to record this data in build.xml, so marked transient:
private transient Map<String,String> data = new HashMap<String,String>();

private void add(ItemGroup ctx, String projectName, int buildNumber) {
if (data==null) return;
Item item = getProject(ctx, projectName);
@Nullable
private String calculateDefaultSuffix(@Nonnull Run<?,?> build, @Nonnull Run<?,?> src, @Nonnull String projectName) {
ItemGroup<?> ctx = getItemGroup(build);
Job<?,?> item = src.getParent();
// Use full name if configured with absolute path
// and relative otherwise
projectName = projectName.startsWith("/") ? item.getFullName() : item.getRelativeNameFrom(ctx);
@@ -633,44 +654,30 @@ private void add(ItemGroup ctx, String projectName, int buildNumber) {
ctx.getFullName(),
}
);
return;
}
data.put("COPYARTIFACT_BUILD_NUMBER_"
+ projectName.toUpperCase().replaceAll("[^A-Z]+", "_"), // Only use letters and _
Integer.toString(buildNumber));
}

/**
* Retrieve root Job identified by this projectPath. For legacy reason, projectPath uses '/' as separator for
* job name and parameters or matrix axe, so can't just use {@link Jenkins#getItemByFullName(String)}.
* As a workaround, we split the path into parts and retrieve the item(group)s up to a Job.
*/
private Job getProject(ItemGroup ctx, String projectPath) {
String[] parts = projectPath.split("/");
if (projectPath.startsWith("/") || ctx == null) ctx = Jenkins.getInstance();
if (ctx == null) {
LOGGER.log(Level.SEVERE, "Jenkins instance is no longer available.");
return null;
}
for (int i =0; i<parts.length; i++) {
String part = parts[i];
if (part.length() == 0) continue;
if (part.equals("..")) {
ctx = ((Item) ctx).getParent();
continue;
}
Item item = ctx.getItem(part);
if (item == null && i == 0) {
// not a relative job name, fall back to "classic" interpretation to consider absolute
Jenkins jenkins = Jenkins.getInstance();
if (jenkins != null) {
item = jenkins.getItem(part);
}

return projectName.toUpperCase().replaceAll("[^A-Z]+", "_"); // Only use letters and _
}

private void add(
@Nonnull Run<?,?> build,
@Nonnull Run<?,?> src,
@Nonnull String projectName,
@Nullable String resultVariableSuffix
) {
if (data==null) return;

if (StringUtils.isEmpty(resultVariableSuffix)) {
resultVariableSuffix = calculateDefaultSuffix(build, src, projectName);
if (resultVariableSuffix == null) {
return;
}
if (item instanceof Job) return (Job) item;
ctx = (ItemGroup) item;
}
return null;
data.put(
String.format("COPYARTIFACT_BUILD_NUMBER_%s", resultVariableSuffix),
Integer.toString(src.getNumber())
);
}

public void buildEnvVars(AbstractBuild<?,?> build, EnvVars env) {
@@ -49,4 +49,9 @@ THE SOFTWARE.
<f:checkbox field="fingerprintArtifacts" default="true"/>
<label class="attach-previous">${%Fingerprint Artifacts}</label>
</f:entry>
<f:advanced>
<f:entry title="${%Result variable suffix}" field="resultVariableSuffix">
<f:textbox/>
</f:entry>
</f:advanced>
</j:jelly>
@@ -0,0 +1,25 @@
<div>
The build number of the selected build will be recorded
into the variable named <tt>COPYARTIFACT_BUILD_NUMBER_(SUFFIX)</tt>
for later build steps to reference.
You can specify that suffix part for that variable here.
<p>
If not specified, the source project name will be used instead
(in all uppercase, and sequences of characters other than A-Z
replaced by a single underscore).
<p><strong>Example</strong>:
<table>
<tr>
<th>Source project name</th>
<th>Suffix to be used</th>
</tr>
<tr>
<td>Project-ABC</td>
<td>PROJECT_ABC</td>
</tr>
<tr>
<td>tool1-release1.2</td>
<td>TOOL_RELEASE_</td>
</tr>
</table>
</div>
@@ -0,0 +1,23 @@
<div>
コピー元のビルドのビルド番号を <tt>COPYARTIFACT_BUILD_NUMBER_(SUFFIX)</tt>
という変数に保存し、以降のビルド処理で参照できるようにします。
その際に使用する SUFFIX の部分をここで指定します。
<p>
指定しない場合、コピー元のプロジェクト名が使用されます。
プロジェクト名はすべて大文字、A-Z 以外の文字がすべてアンダースコアに変換されます。
<p><strong>例</strong>:
<table>
<tr>
<th>Source project name</th>
<th>Suffix to be used</th>
</tr>
<tr>
<td>Project-ABC</td>
<td>PROJECT_ABC</td>
</tr>
<tr>
<td>tool1-release1.2</td>
<td>TOOL_RELEASE_</td>
</tr>
</table>
</div>
@@ -3,17 +3,7 @@
or stable build, or latest "keep forever" build. Other plugins may provide
additional selections. <br/>
The build number of the selected build will be recorded in the environment
for later build steps to reference. The name of the environment variable
is <tt>COPYARTIFACT_BUILD_NUMBER_</tt> with the source project name appended
(in all uppercase, and sequences of characters other than A-Z replaced by a
single underscore).
<p><strong>Example</strong>:
<ul>
<li>
The build number of the build for the source project <code>Project-ABC</code> is
available in <code>COPYARTIFACT_BUILD_NUMBER_PROJECT_ABC</code></li>
<li>
The build number of the build for the source project <code>tool1-release1.2</code> is
available in <code>COPYARTIFACT_BUILD_NUMBER_TOOL_RELEASE_</code></li>
</ul>
for later build steps to reference.
For details, see the help of "Result variable suffix"
in "Advanced" section.
</div>
@@ -1461,7 +1461,8 @@ public void testWebConfiguration() throws Exception {
"",
false,
true,
true
true,
""
));
p.getBuildersList().add(CopyArtifactUtil.createCopyArtifact(
upstream2.getName(),
@@ -1472,7 +1473,8 @@ public void testWebConfiguration() throws Exception {
"targetdir",
true,
false,
false
false,
"SomeSuffix"
));
p.save();

@@ -1494,6 +1496,7 @@ public void testWebConfiguration() throws Exception {
assertFalse(ca.isFlatten());
assertTrue(ca.isOptional());
assertTrue(ca.isFingerprintArtifacts());
assertNull(ca.getResultVariableSuffix());
}
{
CopyArtifact ca = caList.get(1);
@@ -1506,6 +1509,7 @@ public void testWebConfiguration() throws Exception {
assertTrue(ca.isFlatten());
assertFalse(ca.isOptional());
assertFalse(ca.isFingerprintArtifacts());
assertEquals("SomeSuffix", ca.getResultVariableSuffix());
}
}

@@ -1823,4 +1827,65 @@ public void testSimpleBuildSelectorDescriptorInOtherPlugin() throws Exception {
wc.getPage(p, "configure");
}
}

public void testResultVariableSuffix() throws Exception {
FreeStyleProject srcProject = createArtifactProject("SRC-PROJECT1");
FreeStyleBuild srcBuild = srcProject.scheduleBuild2(0).get();
assertBuildStatusSuccess(srcBuild);

// if no result variable suffix is provided
// the default suffix (SRC_PROJECT) is used.
{
FreeStyleProject p = createFreeStyleProject();
p.getBuildersList().add(CopyArtifactUtil.createCopyArtifact(
srcProject.getFullName(),
null, // parameters
new PermalinkBuildSelector("lastStableBuild"),
"*.txt", // filter
"", // excludes
"", // target
false, // flatten
false, // optional
true, // fingerprintArtifacts
"" // resultVariableSuffix
));
CaptureEnvironmentBuilder ceb = new CaptureEnvironmentBuilder();
p.getBuildersList().add(ceb);

assertBuildStatusSuccess(p.scheduleBuild2(0));

assertEquals(
Integer.toString(srcBuild.getNumber()),
ceb.getEnvVars().get("COPYARTIFACT_BUILD_NUMBER_SRC_PROJECT_")
);
}

// if result variable suffix is provided
// it is used for the variable name to store.
{
FreeStyleProject p = createFreeStyleProject();
p.getBuildersList().add(CopyArtifactUtil.createCopyArtifact(
srcProject.getFullName(),
null, // parameters
new PermalinkBuildSelector("lastStableBuild"),
"*.txt", // filter
"", // excludes
"", // target
false, // flatten
false, // optional
true, // fingerprintArtifacts
"DEST1" // resultVariableSuffix
));
CaptureEnvironmentBuilder ceb = new CaptureEnvironmentBuilder();
p.getBuildersList().add(ceb);

assertBuildStatusSuccess(p.scheduleBuild2(0));

assertEquals(
Integer.toString(srcBuild.getNumber()),
ceb.getEnvVars().get("COPYARTIFACT_BUILD_NUMBER_DEST1")
);
assertNull(ceb.getEnvVars().get("COPYARTIFACT_BUILD_NUMBER_SRC_PROJECT_"));
}
}
}
@@ -46,6 +46,11 @@ public static CopyArtifact createCopyArtifact(String projectName, String paramet

public static CopyArtifact createCopyArtifact(String projectName, String parameters, BuildSelector selector, String filter, String excludes, String target,
boolean flatten, boolean optional, boolean fingerprintArtifacts) {
return createCopyArtifact(projectName, parameters, selector, filter, null, target, flatten, optional, fingerprintArtifacts, null);
}

public static CopyArtifact createCopyArtifact(String projectName, String parameters, BuildSelector selector, String filter, String excludes, String target,
boolean flatten, boolean optional, boolean fingerprintArtifacts, String resultVariableSuffix) {
CopyArtifact copyArtifact = new CopyArtifact(projectName);
copyArtifact.setParameters(parameters);
copyArtifact.setSelector(selector);
@@ -55,6 +60,7 @@ public static CopyArtifact createCopyArtifact(String projectName, String paramet
copyArtifact.setFlatten(flatten);
copyArtifact.setOptional(optional);
copyArtifact.setFingerprintArtifacts(fingerprintArtifacts);
copyArtifact.setResultVariableSuffix(resultVariableSuffix);
return copyArtifact;
}
}

0 comments on commit 462bf8f

Please sign in to comment.
You can’t perform that action at this time.