Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/hudson/plugins/git/GitSCM.java
Original file line number Diff line number Diff line change
Expand Up @@ -512,12 +512,12 @@ public List<RemoteConfig> getParamExpandedRepos(Run<?, ?> build, TaskListener li
}

/**
* Expand Parameters in the supplied remote repository with the parameter values provided in the given environment variables }
* Expand Parameters in the supplied remote repository with the parameter values provided in the given environment variables
* @param env Environment variables with parameter values
* @param remoteRepository Remote repository with parameters
* @return remote repository with expanded parameters
*/
public RemoteConfig getParamExpandedRepo(EnvVars env, RemoteConfig remoteRepository){
public RemoteConfig getParamExpandedRepo(EnvVars env, RemoteConfig remoteRepository) {
List<RefSpec> refSpecs = getRefSpecs(remoteRepository, env);
return newRemoteConfig(
getParameterString(remoteRepository.getName(), env),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
import hudson.plugins.git.util.GitUtils;
import hudson.slaves.NodeProperty;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
Expand All @@ -26,6 +28,7 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.CheckForNull;

/**
* @author Kohsuke Kawaguchi
Expand Down Expand Up @@ -139,6 +142,9 @@ public void decorateCloneCommand(GitSCM scm, Run<?, ?> build, GitClient git, Tas
listener.getLogger().println("Avoid fetching tags");
cmd.tags(false);
}

Node node = GitUtils.workspaceToNode(git.getWorkTree());

if (honorRefspec) {
listener.getLogger().println("Honoring refspec on initial clone");
// Read refspec configuration from the first configured repository.
Expand All @@ -148,13 +154,12 @@ public void decorateCloneCommand(GitSCM scm, Run<?, ?> build, GitClient git, Tas
// configuration is treated as authoritative.
// Git plugin does not support multiple independent repositories
// in a single job definition.
EnvVars buildEnv = build.getEnvironment(listener);
RemoteConfig rc = scm.getRepositories().get(0);
List<RefSpec> refspecs = rc.getFetchRefSpecs();
cmd.refspecs(refspecs);
cmd.refspecs(getRefSpecs(rc, buildEnv));
}
cmd.timeout(timeout);

Node node = GitUtils.workspaceToNode(git.getWorkTree());
EnvVars env = build.getEnvironment(listener);
Computer comp = node.toComputer();
if (comp != null) {
Expand All @@ -166,6 +171,18 @@ public void decorateCloneCommand(GitSCM scm, Run<?, ?> build, GitClient git, Tas
cmd.reference(env.expand(reference));
}

private static String getParameterString(@CheckForNull String original, @NonNull EnvVars env) {
return env.expand(original);
}

private static List<RefSpec> getRefSpecs(RemoteConfig repo, EnvVars env) {
List<RefSpec> refSpecs = new ArrayList<>();
for (RefSpec refSpec : repo.getFetchRefSpecs()) {
refSpecs.add(new RefSpec(getParameterString(refSpec.toString(), env)));
}
return refSpecs;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package hudson.plugins.git.extensions.impl;

import hudson.Functions;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Result;
import hudson.model.StringParameterDefinition;
import hudson.plugins.git.AbstractGitTestCase;
import hudson.plugins.git.BranchSpec;
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.UserRemoteConfig;
import hudson.tasks.BatchFile;
import hudson.tasks.Builder;
import hudson.tasks.Shell;
import org.jenkinsci.plugins.gitclient.JGitTool;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.jvnet.hudson.test.Issue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;

@RunWith(Parameterized.class)
public class CloneOptionHonorRefSpecTest extends AbstractGitTestCase {

private final String refSpecName;
private final Boolean honorRefSpec;

private static final Random random = new Random();
private FreeStyleProject project;
private String refSpecExpectedValue;

public CloneOptionHonorRefSpecTest(String refSpecName, Boolean honorRefSpec) {
this.refSpecName = refSpecName;
this.honorRefSpec = honorRefSpec;
}

@Parameterized.Parameters(name = "{0}-{1}")
public static Collection permuteRefSpecVariable() {
List<Object[]> values = new ArrayList<>();
// Should behave same with honor refspec enabled or disabled
boolean honorRefSpec = random.nextBoolean();

String[] keys = {
"JOB_NAME", // Variable set by Jenkins
(Functions.isWindows() ? "USERNAME" : "USER"), // Variable set by the operating system
"USER_SELECTED_BRANCH_NAME" // Parametrised build param
};

for (String refSpecName : keys) {
Object[] combination = {refSpecName, true};
values.add(combination);
honorRefSpec = !honorRefSpec;
}

return values;
}

private static Builder createEnvEchoBuilder(String envVarName) {
if (Functions.isWindows()) {
return new BatchFile(String.format("echo %s=%%%s%%", envVarName, envVarName));
}
return new Shell(String.format("echo \"%s=${%s}\"", envVarName, envVarName));
}

@Before
public void setUp() throws Exception {
super.setUp();

// Setup job beforehand to get expected value of the environment variable
project = createFreeStyleProject();
project.addProperty(new ParametersDefinitionProperty(
new StringParameterDefinition("USER_SELECTED_BRANCH_NAME", "user_branch")
));
project.getBuildersList().add(createEnvEchoBuilder(refSpecName));

final FreeStyleBuild b = project.scheduleBuild2(0).get();
rule.assertBuildStatus(Result.SUCCESS, b);

List<String> logs = b.getLog(50);
for (String line : logs) {
if (line.startsWith(refSpecName + '=')) {
refSpecExpectedValue = line.split("=")[1];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MarkEWaite this seems to be causing a test failure in the BOM, perhaps because there is some environment variable with an empty value: https://github.com/jenkinsci/bom/pull/393/checks?check_run_id=1643221348 (CC @timja)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1023 applies a fix for that case. I'll try to release a new version of the git plugin with that fix within the next 7 days.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git plugin 4.5.2 released with this fix to the test.

}
}

if (refSpecExpectedValue == null) {
throw new Exception("Could not obtain env var expected value");
}
}

/**
* This test confirms behavior of refspecs on initial clone with expanded
* variables. When an environment variable reference is embedded in the
* refspec, it should be expanded in all cases.
*
* @throws Exception on error
*/
@Test
@Issue("JENKINS-56063")
public void testRefSpecWithExpandedVariables() throws Exception {
// Create initial commit
final String commitFile1 = "commitFile1";
commit(commitFile1, johnDoe, "Commit in master branch");

// Create branch and make initial commit
git.checkout().ref("master").branch(refSpecExpectedValue).execute();
commit(commitFile1, johnDoe, "Commit in '" + refSpecExpectedValue + "' branch");

// Use the variable reference in the refspec
// Should be expanded by the clone option whether or not honor refspec is enabled
List<UserRemoteConfig> repos = new ArrayList<>();
repos.add(new UserRemoteConfig(
testRepo.gitDir.getAbsolutePath(),
"origin",
"+refs/heads/${" + refSpecName + "}:refs/remotes/origin/${" + refSpecName + "}", null));

/* Use the variable or its value as the branch name.
* Same result expected in either case.
*/
String branchName = random.nextBoolean() ? "${" + refSpecName + "}" : refSpecExpectedValue;
GitSCM scm = new GitSCM(
repos,
Collections.singletonList(new BranchSpec(branchName)),
false, Collections.emptyList(),
null, random.nextBoolean() ? JGitTool.MAGIC_EXENAME : null,
Collections.emptyList());
project.setScm(scm);

// Same result expected whether refspec honored or not
CloneOption cloneOption = new CloneOption(false, null, null);
cloneOption.setHonorRefspec(honorRefSpec);
scm.getExtensions().add(cloneOption);

FreeStyleBuild b = build(project, Result.SUCCESS, commitFile1);

// Check that unexpanded refspec name is not in the log
List<String> buildLog = b.getLog(50);
assertThat(buildLog, not(hasItem(containsString("${" + refSpecName + "}"))));
}
}