|
31 | 31 | import hudson.ExtensionList;
|
32 | 32 | import hudson.FilePath;
|
33 | 33 | import hudson.Functions;
|
34 |
| -import hudson.model.BuildVariableContributor; |
| 34 | +import hudson.model.Computer; |
35 | 35 | import hudson.model.EnvironmentContributingAction;
|
36 | 36 | import hudson.model.EnvironmentContributor;
|
37 | 37 | import hudson.model.Item;
|
38 | 38 | import hudson.model.Job;
|
| 39 | +import hudson.model.Node; |
39 | 40 | import hudson.model.Result;
|
40 | 41 | import hudson.model.Run;
|
41 | 42 | import hudson.model.TaskListener;
|
42 | 43 | import hudson.plugins.git.GitSCM;
|
43 | 44 | import hudson.plugins.git.BranchSpec;
|
| 45 | +import hudson.remoting.VirtualChannel; |
44 | 46 | import hudson.scm.ChangeLogSet;
|
45 | 47 | import hudson.scm.SCM;
|
46 | 48 | import hudson.slaves.EnvironmentVariablesNodeProperty;
|
47 | 49 | import hudson.slaves.NodeProperty;
|
48 | 50 | import hudson.slaves.NodePropertyDescriptor;
|
| 51 | +import hudson.slaves.OfflineCause; |
| 52 | +import hudson.slaves.WorkspaceList; |
49 | 53 | import hudson.slaves.WorkspaceList;
|
50 | 54 | import java.io.File;
|
51 | 55 | import java.io.IOException;
|
| 56 | +import java.lang.reflect.Field; |
52 | 57 | import java.nio.charset.StandardCharsets;
|
53 | 58 | import java.nio.file.Files;
|
54 | 59 | import java.nio.file.Path;
|
|
57 | 62 | import java.util.Collections;
|
58 | 63 | import java.util.Iterator;
|
59 | 64 | import java.util.List;
|
60 |
| -import java.util.TreeMap; |
61 | 65 | import hudson.util.DescribableList;
|
62 | 66 | import jenkins.branch.BranchProperty;
|
63 | 67 | import jenkins.branch.BranchSource;
|
64 | 68 | import jenkins.branch.DefaultBranchPropertyStrategy;
|
| 69 | +import jenkins.model.Jenkins; |
65 | 70 | import jenkins.plugins.git.GitSCMSource;
|
66 | 71 | import jenkins.plugins.git.GitSampleRepoRule;
|
67 | 72 | import jenkins.scm.api.SCMHead;
|
@@ -1020,7 +1025,7 @@ public class SCMSourceRetrieverTest {
|
1020 | 1025 | // TEST_VAR_NAME injected into env, use its value for library checkout
|
1021 | 1026 | // https://github.com/jenkinsci/envinject-plugin/blob/master/src/test/java/org/jenkinsci/plugins/envinject/EnvInjectPluginActionTest.java
|
1022 | 1027 | WorkflowJob p1 = r.jenkins.createProject(WorkflowJob.class, "p1");
|
1023 |
| - p1.setDefinition(new CpsFlowDefinition("@Library('branchylib@${env.TEST_VAR_NAME}') import myecho; myecho(); echo \"Groovy TEST_VAR_NAME='${TEST_VAR_NAME}'\"; echo \"env.TEST_VAR_NAME='${env.TEST_VAR_NAME}'\"", true)); |
| 1028 | + p1.setDefinition(new CpsFlowDefinition("@Library('branchylib@${env.TEST_VAR_NAME}') import myecho; myecho(); try { echo \"Groovy TEST_VAR_NAME='${TEST_VAR_NAME}'\"; } catch (groovy.lang.MissingPropertyException mpe) { echo \"Groovy TEST_VAR_NAME missing: ${mpe.getMessage()}\"; } ; echo \"env.TEST_VAR_NAME='${env.TEST_VAR_NAME}'\"", true)); |
1024 | 1029 |
|
1025 | 1030 | // Inject envvar to server global settings:
|
1026 | 1031 | DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = r.jenkins.getGlobalNodeProperties();
|
@@ -1116,13 +1121,168 @@ public class SCMSourceRetrieverTest {
|
1116 | 1121 | r.assertLogContains("Loading library branchylib@feature", b3);
|
1117 | 1122 | r.assertLogContains("something very special", b3);
|
1118 | 1123 |
|
1119 |
| - // TODO: similar trick with built-in agent settings |
1120 |
| - // which has lowest priority behind global and injected |
1121 |
| - // envvars (see Run::getEnvironment()). Check with the |
1122 |
| - // override above, and with ecList contents restored to |
1123 |
| - // ecOrig state only. |
1124 |
| - //p1.setAssignedNode(r.createSlave()); |
1125 |
| - //p1.getEnvironment(r.jenkins.getNode("built-in"), null).put("TEST_VAR_NAME", "feature"); |
| 1124 | + // Below we do a similar trick with built-in agent settings |
| 1125 | + // which (as a Computer=>Node) has lowest priority behind |
| 1126 | + // global and injected envvars (see Run::getEnvironment()). |
| 1127 | + // Check with the injected envvars (they override) like above |
| 1128 | + // first, and with ecList contents restored to ecOrig state |
| 1129 | + // only (so only Computer envvars are applied). |
| 1130 | + // Trick here is that the "jenkins.model.Jenkins" is inherited |
| 1131 | + // from Node and its toComputer() returns the "built-in" (nee |
| 1132 | + // "master"), instance of "hudson.model.Hudson$MasterComputer" |
| 1133 | + // whose String getName() is actually empty. |
| 1134 | + // Pipeline scripts are initially processed only by this node, |
| 1135 | + // further run on the controller, and then the actual work is |
| 1136 | + // distributed to agents (often via remoting proxy methods) |
| 1137 | + // if any are defined. |
| 1138 | + Computer builtInComputer = r.jenkins.toComputer(); |
| 1139 | + Node builtInNode = builtInComputer.getNode(); |
| 1140 | +/* |
| 1141 | + EnvironmentVariablesNodeProperty builtInEnvProp = builtInNode.getNodeProperty(EnvironmentVariablesNodeProperty.class); |
| 1142 | +
|
| 1143 | + if (builtInEnvProp == null) { |
| 1144 | + builtInEnvProp = new EnvironmentVariablesNodeProperty(); |
| 1145 | + //builtInEnvProp.setNode(builtInNode); |
| 1146 | + builtInNode.getNodeProperties().add(builtInEnvProp); |
| 1147 | + } |
| 1148 | + EnvVars builtInEnvVars = builtInEnvProp.getEnvVars(); |
| 1149 | + builtInEnvVars.put("TEST_VAR_NAME", "stable"); |
| 1150 | + builtInEnvProp.buildEnvVars(new EnvVars("TEST_VAR_NAME", "stable"), null); |
| 1151 | + */ |
| 1152 | + builtInNode.getNodeProperties().add(new EnvironmentVariablesNodeProperty(new EnvironmentVariablesNodeProperty.Entry("TEST_VAR_NAME", "stable"))); |
| 1153 | + r.jenkins.save(); |
| 1154 | + builtInNode.save(); |
| 1155 | + |
| 1156 | + System.out.println("[DEBUG] Restart the 'built-in' Computer connection to clear its cachedEnvironment and recognize added envvar"); |
| 1157 | + builtInComputer.setTemporarilyOffline(true, new OfflineCause.ByCLI("Restart built-in to reread envvars config")); |
| 1158 | + builtInComputer.waitUntilOffline(); |
| 1159 | + builtInComputer.disconnect(new OfflineCause.ByCLI("Restart built-in to reread envvars config")); |
| 1160 | + r.waitUntilNoActivity(); |
| 1161 | + Thread.sleep(3000); |
| 1162 | + builtInComputer.setTemporarilyOffline(false, null); |
| 1163 | + builtInComputer.connect(true); |
| 1164 | + builtInComputer.waitUntilOnline(); |
| 1165 | + |
| 1166 | + System.out.println("[DEBUG] builtIn node env: " + builtInComputer.getEnvironment()); |
| 1167 | + |
| 1168 | + // Both injected var and build node envvar setting present; |
| 1169 | + // injected var wins: |
| 1170 | + WorkflowRun b4 = r.buildAndAssertSuccess(p1); |
| 1171 | + System.out.println("[DEBUG:EXT:p1b4] wfJob env: " + p1.getEnvironment(null, null)); |
| 1172 | + System.out.println("[DEBUG:EXT:p1b4] wfRun env: " + b4.getEnvironment()); |
| 1173 | + System.out.println("[DEBUG:EXT:p1b4] wfRun envContribActions: " + b4.getActions(EnvironmentContributingAction.class)); |
| 1174 | + r.assertLogContains("Loading library branchylib@feature", b4); |
| 1175 | + r.assertLogContains("something very special", b4); |
| 1176 | + r.assertLogContains("Groovy TEST_VAR_NAME='feature'", b4); |
| 1177 | + r.assertLogContains("env.TEST_VAR_NAME='feature'", b4); |
| 1178 | + |
| 1179 | + // Only build agent envvars are present: drop all, |
| 1180 | + // add back original (before our mock above): |
| 1181 | + List<EnvironmentContributor> ecCurr = new ArrayList(); |
| 1182 | + for (EnvironmentContributor ec : ecList) { |
| 1183 | + ecCurr.add(ec); |
| 1184 | + } |
| 1185 | + ecList.removeAll(ecCurr); |
| 1186 | + for (EnvironmentContributor ec : ecOrig) { |
| 1187 | + ecList.add(ec); |
| 1188 | + } |
| 1189 | + |
| 1190 | + System.out.println("[DEBUG:EXT:p1b5] EnvironmentContributor.all(): " + EnvironmentContributor.all()); |
| 1191 | + System.out.println("[DEBUG:EXT:p1b5] builtIn node env: " + builtInComputer.getEnvironment()); |
| 1192 | + System.out.println("[DEBUG:EXT:p1b5] wfJob env in builtIn: " + p1.getEnvironment(builtInNode, null)); |
| 1193 | + System.out.println("[DEBUG:EXT:p1b5] wfJob env (without node): " + p1.getEnvironment(null, null)); |
| 1194 | + WorkflowRun b5 = r.buildAndAssertSuccess(p1); |
| 1195 | + System.out.println("[DEBUG:EXT:p1b5] wfRun env: " + b5.getEnvironment()); |
| 1196 | + System.out.println("[DEBUG:EXT:p1b5] wfRun envContribActions: " + b5.getActions(EnvironmentContributingAction.class)); |
| 1197 | + r.assertLogContains("Loading library branchylib@stable", b5); |
| 1198 | + r.assertLogContains("something reliable", b5); |
| 1199 | + // Why oh why is the build agent's (cached) envvar not resolved |
| 1200 | + // even after reconnect?.. Probably a burden of "built-in" until |
| 1201 | + // Jenkins restart?.. |
| 1202 | + r.assertLogContains("Groovy TEST_VAR_NAME missing", b5); |
| 1203 | + r.assertLogContains("env.TEST_VAR_NAME='null'", b5); |
| 1204 | + |
| 1205 | + // Let's try just that - restart Jenkins to fully reinit the |
| 1206 | + // built-in node with its config: |
| 1207 | + r.jenkins.reload(); |
| 1208 | + r.waitUntilNoActivity(); |
| 1209 | + |
| 1210 | + WorkflowRun b6 = r.buildAndAssertSuccess(p1); |
| 1211 | + r.assertLogContains("Loading library branchylib@stable", b6); |
| 1212 | + r.assertLogContains("something reliable", b6); |
| 1213 | + r.assertLogContains("Groovy TEST_VAR_NAME missing", b6); |
| 1214 | + r.assertLogContains("env.TEST_VAR_NAME='null'", b6); |
| 1215 | + |
| 1216 | + Thread.sleep(160000); |
| 1217 | + } |
| 1218 | + |
| 1219 | + @Issue("JENKINS-69731") |
| 1220 | + @Test public void checkDefaultVersion_inline_allowVersionEnvvar_builtIn() throws Exception { |
| 1221 | + // Test that @Library('branchylib@${env.TEST_VAR_NAME}') |
| 1222 | + // is resolved with the TEST_VAR_NAME="feature" in the |
| 1223 | + // "built-in" node environment settings. |
| 1224 | + |
| 1225 | + // Do not let caller-provided BRANCH_NAME interfere here |
| 1226 | + assumeFalse("An externally provided TEST_VAR_NAME envvar interferes with tested logic", |
| 1227 | + System.getenv("TEST_VAR_NAME") != null); |
| 1228 | + |
| 1229 | + // First apply the "built-in node", then touch Jenkins jobs: |
| 1230 | + Computer builtInComputer = r.jenkins.toComputer(); |
| 1231 | + Node builtInNode = builtInComputer.getNode(); |
| 1232 | + builtInNode.getNodeProperties().add(new EnvironmentVariablesNodeProperty(new EnvironmentVariablesNodeProperty.Entry("TEST_VAR_NAME", "stable"))); |
| 1233 | + r.jenkins.save(); |
| 1234 | + builtInNode.save(); |
| 1235 | + |
| 1236 | + System.out.println("[DEBUG] Restart the 'built-in' Computer connection to clear its cachedEnvironment and recognize added envvar"); |
| 1237 | + builtInComputer.setTemporarilyOffline(true, new OfflineCause.ByCLI("Restart built-in to reread envvars config")); |
| 1238 | + builtInComputer.disconnect(new OfflineCause.ByCLI("Restart built-in to reread envvars config")); |
| 1239 | + builtInComputer.waitUntilOffline(); |
| 1240 | + r.waitUntilNoActivity(); |
| 1241 | + builtInComputer.getChannel().close(); |
| 1242 | + Thread.sleep(3000); |
| 1243 | + r.jenkins.reload(); |
| 1244 | + builtInComputer.setTemporarilyOffline(false, null); |
| 1245 | + builtInComputer.connect(true); |
| 1246 | + builtInComputer.waitUntilOnline(); |
| 1247 | + r.waitUntilNoActivity(); |
| 1248 | + |
| 1249 | + // Feed it to Java reflection, to clear the internal cache... |
| 1250 | + Field ccc = Computer.class.getDeclaredField("cachedEnvironment"); |
| 1251 | + ccc.setAccessible(true); |
| 1252 | + ccc.set(builtInComputer, null); |
| 1253 | + |
| 1254 | + System.out.println("[DEBUG] builtIn node env: " + builtInComputer.getEnvironment()); |
| 1255 | + |
| 1256 | + sampleRepo.init(); |
| 1257 | + sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}"); |
| 1258 | + sampleRepo.git("add", "vars"); |
| 1259 | + sampleRepo.git("commit", "--message=init"); |
| 1260 | + sampleRepo.git("checkout", "-b", "feature"); |
| 1261 | + sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something very special'}"); |
| 1262 | + sampleRepo.git("add", "vars"); |
| 1263 | + sampleRepo.git("commit", "--message=init"); |
| 1264 | + sampleRepo.git("checkout", "-b", "stable"); |
| 1265 | + sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something reliable'}"); |
| 1266 | + sampleRepo.git("add", "vars"); |
| 1267 | + sampleRepo.git("commit", "--message=init"); |
| 1268 | + SCMSourceRetriever scm = new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)); |
| 1269 | + LibraryConfiguration lc = new LibraryConfiguration("branchylib", scm); |
| 1270 | + lc.setDefaultVersion("master"); |
| 1271 | + lc.setIncludeInChangesets(false); |
| 1272 | + lc.setAllowVersionOverride(true); |
| 1273 | + lc.setAllowVersionEnvvar(true); |
| 1274 | + lc.setTraceDefaultedVersion(true); |
| 1275 | + GlobalLibraries.get().setLibraries(Collections.singletonList(lc)); |
| 1276 | + |
| 1277 | + WorkflowJob p1 = r.jenkins.createProject(WorkflowJob.class, "p1"); |
| 1278 | + p1.setDefinition(new CpsFlowDefinition("@Library('branchylib@${env.TEST_VAR_NAME}') import myecho; myecho(); try { echo \"Groovy TEST_VAR_NAME='${TEST_VAR_NAME}'\"; } catch (groovy.lang.MissingPropertyException mpe) { echo \"Groovy TEST_VAR_NAME missing: ${mpe.getMessage()}\"; } ; echo \"env.TEST_VAR_NAME='${env.TEST_VAR_NAME}'\"", true)); |
| 1279 | + |
| 1280 | + WorkflowRun b6 = r.buildAndAssertSuccess(p1); |
| 1281 | + r.assertLogContains("Loading library branchylib@stable", b6); |
| 1282 | + r.assertLogContains("something reliable", b6); |
| 1283 | + r.assertLogContains("Groovy TEST_VAR_NAME missing", b6); |
| 1284 | + r.assertLogContains("env.TEST_VAR_NAME='null'", b6); |
| 1285 | + |
1126 | 1286 | }
|
1127 | 1287 |
|
1128 | 1288 | @Issue("JENKINS-43802")
|
|
0 commit comments