Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package io.jenkins.plugins.gitlabbranchsource;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import java.time.LocalDate;
import java.time.ZoneOffset;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.trait.SCMHeadFilter;
import jenkins.scm.api.trait.SCMSourceContext;
import jenkins.scm.api.trait.SCMSourceRequest;
import jenkins.scm.api.trait.SCMSourceTrait;
import jenkins.scm.api.trait.SCMSourceTraitDescriptor;
import org.gitlab4j.api.models.Branch;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* Discard all branches with head commit older than the configured days.
*/
public class DiscardOldBranchTrait extends SCMSourceTrait {

private int keepForDays = 1;

@DataBoundConstructor
public DiscardOldBranchTrait(int keepForDays) {
this.keepForDays = keepForDays;
}

public int getKeepForDays() {
return keepForDays;

Check warning on line 30 in src/main/java/io/jenkins/plugins/gitlabbranchsource/DiscardOldBranchTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 30 is not covered by tests
}

@Override
protected void decorateContext(SCMSourceContext<?, ?> context) {
context.withFilter(new ExcludeOldSCMHeadBranch(keepForDays));
}

static final class ExcludeOldSCMHeadBranch extends SCMHeadFilter {

private final int keepForDays;

public ExcludeOldSCMHeadBranch(int keepForDays) {
this.keepForDays = keepForDays;
}

@Override
public boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead head) {
GitLabSCMSourceRequest glRequest = (GitLabSCMSourceRequest) request;
String branchName = head.getName();
if (head instanceof MergeRequestSCMHead mrHead) {

Check warning on line 50 in src/main/java/io/jenkins/plugins/gitlabbranchsource/DiscardOldBranchTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 50 is only partially covered, one branch is missing
branchName = mrHead.getOriginName();

Check warning on line 51 in src/main/java/io/jenkins/plugins/gitlabbranchsource/DiscardOldBranchTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 51 is not covered by tests
}

for (Branch branch : glRequest.getBranches()) {

Check warning on line 54 in src/main/java/io/jenkins/plugins/gitlabbranchsource/DiscardOldBranchTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 54 is only partially covered, one branch is missing
if (branchName.equals(branch.getName())) {
LocalDate commitDate = LocalDate.ofInstant(
branch.getCommit().getCommittedDate().toInstant(), ZoneOffset.UTC);
LocalDate expiryDate = LocalDate.now(ZoneOffset.UTC).minusDays(keepForDays);
return commitDate.isBefore(expiryDate);
}
}
return false;

Check warning on line 62 in src/main/java/io/jenkins/plugins/gitlabbranchsource/DiscardOldBranchTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 62 is not covered by tests
}
}

@Symbol("gitLabDiscardOldBranch")
@Extension
public static class DescriptorImpl extends SCMSourceTraitDescriptor {

@NonNull
@Override
public String getDisplayName() {
return Messages.DiscardOldBranchTrait_displayName();
}

@Override
public Class<? extends SCMSourceContext> getContextClass() {
return GitLabSCMSourceContext.class;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.jenkins.plugins.gitlabbranchsource;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import java.time.LocalDate;
import java.time.ZoneOffset;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMSource;
import jenkins.scm.api.mixin.TagSCMHead;
import jenkins.scm.api.trait.SCMHeadPrefilter;
import jenkins.scm.api.trait.SCMSourceContext;
import jenkins.scm.api.trait.SCMSourceTrait;
import jenkins.scm.api.trait.SCMSourceTraitDescriptor;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* Discard all tags with creation date older than the configured days.
*/
public class DiscardOldTagTrait extends SCMSourceTrait {

private int keepForDays = 1;

@DataBoundConstructor
public DiscardOldTagTrait(int keepForDays) {
this.keepForDays = keepForDays;
}

public int getKeepForDays() {
return keepForDays;

Check warning on line 30 in src/main/java/io/jenkins/plugins/gitlabbranchsource/DiscardOldTagTrait.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 30 is not covered by tests
}

@Override
protected void decorateContext(SCMSourceContext<?, ?> context) {
context.withPrefilter(new ExcludeOldSCMTag(keepForDays));
}

static final class ExcludeOldSCMTag extends SCMHeadPrefilter {

private final int keepForDays;

public ExcludeOldSCMTag(int keepForDays) {
this.keepForDays = keepForDays;
}

@Override
public boolean isExcluded(@NonNull SCMSource source, @NonNull SCMHead head) {
if (!(head instanceof TagSCMHead tagHead) || tagHead.getTimestamp() == 0) {
return false;
}

LocalDate commitDate = asLocalDate(tagHead.getTimestamp());
LocalDate expiryDate = LocalDate.now(ZoneOffset.UTC).minusDays(keepForDays);
return commitDate.isBefore(expiryDate);
}

@NonNull
private LocalDate asLocalDate(long milliseconds) {
return new java.sql.Date(milliseconds).toLocalDate();
}
}

@Symbol("gitLabDiscardOldTag")
@Extension
public static class DescriptorImpl extends SCMSourceTraitDescriptor {

@NonNull
@Override
public String getDisplayName() {
return Messages.DiscardOldTagTrait_displayName();
}

@Override
public Class<? extends SCMSourceContext> getContextClass() {
return GitLabSCMSourceContext.class;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Days to keep}" field="keepForDays">
<f:number default="1" min="1" clazz="positive-number-required"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Number of days since the last commit in the branch before it is discarded.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Discard all branches with head commit older than the configured days.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Days to keep}" field="keepForDays">
<f:number default="1" min="1" clazz="positive-number-required"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Number of days since the commit date referred by the tag before it is discarded.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Discard all tags created before the configured days.
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ GitLabWebHookCause.ShortDescription.Push=Started by GitLab push by {0}
GitLabWebHookCause.ShortDescription.MergeRequestHook=Triggered by GitLab Merge Request #{0}: {1} => {2}
WebhookListenerBuildConditionsTrait.displayName=Webhook Listener Conditions
GitLabMarkUnstableAsSuccessTrait.displayName=Mark unstable build as successful on Gitlab
DiscardOldBranchTrait_displayName=Discard branch older than given days
DiscardOldTagTrait_displayName=Discard tag older than given days
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package io.jenkins.plugins.gitlabbranchsource;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import io.jenkins.plugins.gitlabbranchsource.DiscardOldBranchTrait.ExcludeOldSCMHeadBranch;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadObserver;
import jenkins.scm.api.trait.SCMHeadFilter;
import org.apache.commons.lang.time.DateUtils;
import org.gitlab4j.api.models.Branch;
import org.gitlab4j.api.models.Commit;
import org.junit.jupiter.api.Test;

class DiscardOldBranchTraitTest {

@Test
void should_include_branch_if_last_commit_within_range() throws Exception {
DiscardOldBranchTrait uut = new DiscardOldBranchTrait(10);
GitLabSCMSourceContext context = new GitLabSCMSourceContext(null, SCMHeadObserver.none());
uut.decorateContext(context);

Optional<SCMHeadFilter> optFilter = context.filters().stream()
.filter(it -> ExcludeOldSCMHeadBranch.class.equals(it.getClass()))
.findFirst();
assertTrue(optFilter.isPresent());

SCMHead head = mock(SCMHead.class);
when(head.getName()).thenReturn("expected");

Date today = new Date();

GitLabSCMSourceRequest request = mock(GitLabSCMSourceRequest.class);
when(request.getBranches())
.thenReturn(List.of(
buildBranch("other", DateUtils.addDays(today, -7)),
buildBranch("expected", DateUtils.addDays(today, -10))));

SCMHeadFilter filter = optFilter.get();
assertFalse(filter.isExcluded(request, head));
}

@Test
void should_exclude_branch_if_last_commit_not_within_range() throws Exception {
DiscardOldBranchTrait uut = new DiscardOldBranchTrait(10);
GitLabSCMSourceContext context = new GitLabSCMSourceContext(null, SCMHeadObserver.none());
uut.decorateContext(context);

Optional<SCMHeadFilter> optFilter = context.filters().stream()
.filter(it -> ExcludeOldSCMHeadBranch.class.equals(it.getClass()))
.findFirst();
assertTrue(optFilter.isPresent());

SCMHead head = mock(SCMHead.class);
when(head.getName()).thenReturn("expected");

Date today = new Date();

GitLabSCMSourceRequest request = mock(GitLabSCMSourceRequest.class);
when(request.getBranches())
.thenReturn(List.of(
buildBranch("other", DateUtils.addDays(today, -7)),
buildBranch("expected", DateUtils.addDays(today, -11))));

SCMHeadFilter filter = optFilter.get();
assertTrue(filter.isExcluded(request, head));
}

private Branch buildBranch(String name, Date commitDate) {
Branch branch = new Branch();
branch.setName(name);
Commit commit = new Commit();
commit.setCommittedDate(commitDate);
branch.setCommit(commit);
return branch;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.jenkins.plugins.gitlabbranchsource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import io.jenkins.plugins.gitlabbranchsource.DiscardOldTagTrait.ExcludeOldSCMTag;
import java.util.Date;
import java.util.Optional;
import java.util.stream.Stream;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadObserver;
import jenkins.scm.api.trait.SCMHeadPrefilter;
import jenkins.scm.impl.NullSCMSource;
import org.apache.commons.lang3.time.DateUtils;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class DiscardOldTagTraitTest {

static Stream<Arguments> tagSCMHeadProvider() {
return Stream.of(
Arguments.argumentSet(
"expired",
new GitLabTagSCMHead(
"tag/1234", DateUtils.addDays(new Date(), -6).getTime()),
true),
Arguments.argumentSet(
"too_recent",
new GitLabTagSCMHead(
"tag/1234", DateUtils.addDays(new Date(), -4).getTime()),
false),
Arguments.argumentSet("no_timestamp", new GitLabTagSCMHead("tag/zer0", 0L), false),
Arguments.argumentSet("not_a_tag", new BranchSCMHead("someBranch"), false));
}

@ParameterizedTest
@MethodSource("tagSCMHeadProvider")
void verify_tag_filtering(SCMHead head, boolean expectedResult) {
DiscardOldTagTrait uut = new DiscardOldTagTrait(5);
GitLabSCMSourceContext context = new GitLabSCMSourceContext(null, SCMHeadObserver.none());
uut.decorateContext(context);

Optional<SCMHeadPrefilter> optFilter = context.prefilters().stream()
.filter(it -> ExcludeOldSCMTag.class.equals(it.getClass()))
.findFirst();
assertTrue(optFilter.isPresent());

SCMHeadPrefilter filter = optFilter.get();

assertEquals(filter.isExcluded(new NullSCMSource(), head), expectedResult);
}
}
Loading