Skip to content

Commit 9d9a97c

Browse files
JENKINS-66040: fix in-progress notifications for non-standard project recognizers (#463)
* JENKINS-66040: do not create FirstCheckoutCompletedInvisibleAction if revision is not known yet * JENKINS-66040: implement positive FirstCheckoutCompletedInvisibleAction test * JENKINS-66040: implement shouldNotSetFirstCheckoutCompletedInvisibleActionOnOtherCheckoutWithNonDefaultFactory * JENKINS-66040: CheckStyle * JENKINS-66040: CheckStyle * JENKINS-66040: CheckStyle * JENKINS-66040: CheckStyle Co-authored-by: Liam Newman <bitwiseman@gmail.com>
1 parent 4453ec3 commit 9d9a97c

File tree

3 files changed

+163
-2
lines changed

3 files changed

+163
-2
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@
130130
<classifier>tests</classifier>
131131
<scope>test</scope>
132132
</dependency>
133+
<dependency>
134+
<groupId>org.jenkins-ci.plugins.workflow</groupId>
135+
<artifactId>workflow-basic-steps</artifactId>
136+
<scope>test</scope>
137+
</dependency>
133138
<dependency>
134139
<groupId>org.jenkins-ci.plugins</groupId>
135140
<artifactId>handy-uri-templates-2-api</artifactId>

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketBuildStatusNotifications.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@ public void onCheckout(Run<?, ?> build, SCM scm, FilePath workspace, TaskListene
248248
return;
249249
}
250250

251+
SCMRevision r = SCMRevisionAction.getRevision(source, build);
252+
if (r == null) {
253+
return;
254+
}
255+
251256
boolean hasCompletedCheckoutBefore =
252257
build.getAction(FirstCheckoutCompletedInvisibleAction.class) != null;
253258

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketBuildStatusNotificationsTest.java

Lines changed: 153 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,68 @@
2424

2525
package com.cloudbees.jenkins.plugins.bitbucket;
2626

27+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi;
28+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketBranch;
29+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketCommit;
30+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref;
31+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository;
32+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol;
33+
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryType;
34+
import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint;
35+
import com.cloudbees.jenkins.plugins.bitbucket.filesystem.BitbucketSCMFile;
2736
import hudson.model.Action;
2837
import hudson.model.FreeStyleBuild;
2938
import hudson.model.FreeStyleProject;
39+
import hudson.model.Result;
40+
import hudson.model.TaskListener;
41+
import java.io.ByteArrayInputStream;
42+
import java.io.IOException;
43+
import java.net.URL;
44+
import java.util.Collections;
3045
import java.util.List;
46+
import jenkins.branch.BranchSource;
47+
import jenkins.plugins.git.GitSampleRepoRule;
48+
import jenkins.scm.api.SCMSource;
49+
import jenkins.scm.api.SCMSourceCriteria;
50+
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
51+
import org.jenkinsci.plugins.workflow.flow.FlowDefinition;
52+
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
53+
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
54+
import org.jenkinsci.plugins.workflow.multibranch.AbstractWorkflowBranchProjectFactory;
55+
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
56+
import org.junit.ClassRule;
3157
import org.junit.Rule;
3258
import org.junit.Test;
59+
import org.jvnet.hudson.test.BuildWatcher;
60+
import org.jvnet.hudson.test.Issue;
3361
import org.jvnet.hudson.test.JenkinsRule;
3462
import org.jvnet.hudson.test.SingleFileSCM;
63+
import org.mockito.Mockito;
64+
import org.mockito.internal.stubbing.answers.Returns;
3565

3666
import static org.hamcrest.MatcherAssert.assertThat;
3767
import static org.hamcrest.Matchers.hasItem;
3868
import static org.hamcrest.Matchers.instanceOf;
69+
import static org.hamcrest.Matchers.is;
3970
import static org.hamcrest.Matchers.not;
71+
import static org.mockito.Matchers.any;
72+
import static org.mockito.Matchers.anyString;
73+
import static org.mockito.Matchers.eq;
74+
import static org.mockito.Mockito.when;
4075

4176
public class BitbucketBuildStatusNotificationsTest {
4277

78+
@ClassRule
79+
public static BuildWatcher buildWatcher = new BuildWatcher();
4380
@Rule
44-
public JenkinsRule r = new JenkinsRule();
81+
public JenkinsRule r = new JenkinsRule() {
82+
@Override
83+
public URL getURL() throws IOException {
84+
return new URL("http://example.com:" + localPort + contextPath + "/");
85+
}
86+
};
87+
@Rule
88+
public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
4589

4690
// TODO test of effectiveness of FirstCheckoutCompletedInvisibleAction (#130)
4791

@@ -50,7 +94,114 @@ public void noInappropriateFirstCheckoutCompletedInvisibleAction() throws Except
5094
FreeStyleProject p = r.createFreeStyleProject();
5195
p.setScm(new SingleFileSCM("file", "contents"));
5296
FreeStyleBuild b = r.buildAndAssertSuccess(p);
53-
assertThat((List<Action>)b.getAllActions(), not(hasItem(instanceOf(FirstCheckoutCompletedInvisibleAction.class))));
97+
assertThat((List<Action>) b.getAllActions(), not(hasItem(instanceOf(FirstCheckoutCompletedInvisibleAction.class))));
98+
}
99+
100+
private WorkflowMultiBranchProject prepareFirstCheckoutCompletedInvisibleActionTest(String dsl) throws Exception {
101+
String repoOwner = "bob";
102+
String repositoryName = "foo";
103+
String branchName = "master";
104+
String jenkinsfile = "Jenkinsfile";
105+
sampleRepo.init();
106+
sampleRepo.write(jenkinsfile, dsl);
107+
sampleRepo.git("add", jenkinsfile);
108+
sampleRepo.git("commit", "--all", "--message=defined");
109+
110+
BitbucketApi api = Mockito.mock(BitbucketApi.class);
111+
BitbucketBranch branch = Mockito.mock(BitbucketBranch.class);
112+
List<? extends BitbucketBranch> branchList = Collections.singletonList(branch);
113+
when(api.getBranches()).thenAnswer(new Returns(branchList));
114+
when(branch.getName()).thenReturn(branchName);
115+
when(branch.getRawNode()).thenReturn(sampleRepo.head());
116+
BitbucketCommit commit = Mockito.mock(BitbucketCommit.class);
117+
when(api.resolveCommit(sampleRepo.head())).thenReturn(commit);
118+
when(commit.getDateMillis()).thenReturn(System.currentTimeMillis());
119+
when(api.checkPathExists(Mockito.anyString(), eq(jenkinsfile))).thenReturn(true);
120+
when(api.getRepositoryUri(eq(BitbucketRepositoryType.GIT),
121+
any(BitbucketRepositoryProtocol.class),
122+
anyString(),
123+
eq(repoOwner),
124+
eq(repositoryName)))
125+
.thenReturn(sampleRepo.fileUrl());
126+
BitbucketRepository repository = Mockito.mock(BitbucketRepository.class);
127+
when(api.getRepository()).thenReturn(repository);
128+
when(repository.getOwnerName()).thenReturn(repoOwner);
129+
when(repository.getRepositoryName()).thenReturn(repositoryName);
130+
when(repository.getScm()).thenReturn("git");
131+
when(repository.getLinks()).thenReturn(
132+
Collections.singletonMap("clone",
133+
Collections.singletonList(new BitbucketHref("http", sampleRepo.toString()))
134+
)
135+
);
136+
when(api.getRepository()).thenReturn(repository);
137+
when(api.getFileContent(any(BitbucketSCMFile.class))).thenReturn(
138+
new ByteArrayInputStream(dsl.getBytes()));
139+
BitbucketMockApiFactory.add(BitbucketCloudEndpoint.SERVER_URL, api);
140+
141+
BitbucketSCMSource source = new BitbucketSCMSource(repoOwner, repositoryName);
142+
WorkflowMultiBranchProject owner = r.jenkins.createProject(WorkflowMultiBranchProject.class, "p");
143+
source.setTraits(Collections.singletonList(
144+
new BranchDiscoveryTrait(true, true)
145+
));
146+
owner.setSourcesList(Collections.singletonList(new BranchSource(source)));
147+
source.setOwner(owner);
148+
return owner;
149+
}
150+
151+
@Test
152+
public void firstCheckoutCompletedInvisibleAction() throws Exception {
153+
String dsl = "node { checkout scm }";
154+
WorkflowMultiBranchProject owner = prepareFirstCheckoutCompletedInvisibleActionTest(dsl);
155+
156+
owner.scheduleBuild2(0).getFuture().get();
157+
owner.getComputation().writeWholeLogTo(System.out);
158+
assertThat(owner.getIndexing().getResult(), is(Result.SUCCESS));
159+
r.waitUntilNoActivity();
160+
WorkflowJob master = owner.getItem("master");
161+
WorkflowRun run = master.getLastBuild();
162+
run.writeWholeLogTo(System.out);
163+
assertThat(run.getResult(), is(Result.SUCCESS));
164+
assertThat((List<Action>) run.getAllActions(), hasItem(instanceOf(FirstCheckoutCompletedInvisibleAction.class)));
54165
}
55166

167+
@Issue("JENKINS-66040")
168+
@Test
169+
public void shouldNotSetFirstCheckoutCompletedInvisibleActionOnOtherCheckoutWithNonDefaultFactory() throws Exception {
170+
String dsl = "node { checkout(scm: [$class: 'GitSCM', userRemoteConfigs: [[url: 'https://github.com/jenkinsci/bitbucket-branch-source-plugin.git']], branches: [[name: 'master']]]) }";
171+
WorkflowMultiBranchProject owner = prepareFirstCheckoutCompletedInvisibleActionTest(dsl);
172+
owner.setProjectFactory(new DummyWorkflowBranchProjectFactory(dsl));
173+
174+
owner.scheduleBuild2(0).getFuture().get();
175+
owner.getComputation().writeWholeLogTo(System.out);
176+
assertThat(owner.getIndexing().getResult(), is(Result.SUCCESS));
177+
r.waitUntilNoActivity();
178+
WorkflowJob master = owner.getItem("master");
179+
WorkflowRun run = master.getLastBuild();
180+
run.writeWholeLogTo(System.out);
181+
assertThat(run.getResult(), is(Result.SUCCESS));
182+
assertThat((List<Action>) run.getAllActions(), not(hasItem(instanceOf(FirstCheckoutCompletedInvisibleAction.class))));
183+
}
184+
185+
private static class DummyWorkflowBranchProjectFactory extends AbstractWorkflowBranchProjectFactory {
186+
private final String dsl;
187+
188+
public DummyWorkflowBranchProjectFactory(String dsl) {
189+
this.dsl = dsl;
190+
}
191+
192+
@Override
193+
protected FlowDefinition createDefinition() {
194+
return new CpsFlowDefinition(dsl, true);
195+
}
196+
197+
@Override
198+
protected SCMSourceCriteria getSCMSourceCriteria(SCMSource source) {
199+
return new SCMSourceCriteria() {
200+
@Override
201+
public boolean isHead(Probe probe, TaskListener listener) throws IOException {
202+
return true;
203+
}
204+
};
205+
}
206+
}
56207
}

0 commit comments

Comments
 (0)