Skip to content

Commit

Permalink
Enable job selection for BuildStatusFolderIcon (#246) (#248)
Browse files Browse the repository at this point in the history
  • Loading branch information
strangelookingnerd committed Oct 20, 2023
1 parent 29f66ab commit 6ff2849
Show file tree
Hide file tree
Showing 26 changed files with 213 additions and 67 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ on:

jobs:
coverage:

runs-on: [ ubuntu-latest ]
runs-on: ubuntu-latest
name: Coverage on Ubuntu

steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/delete-workflow-runs.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
name: Delete old workflow runs

on:
schedule:
# Run monthly, at 00:00 on the 1st day of month.
- cron: '0 0 1 * *'
workflow_dispatch:

jobs:
del_runs:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/jenkins-security-scan.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Jenkins Security Scan

on:
push:
branches:
- "main"
- main
pull_request:
types: [ opened, synchronize, reopened ]
workflow_dispatch:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
# Publishes a new GH Release automatically once a tag gets pushed
publish: startsWith(github.ref, "refs/tags")
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5 changes: 1 addition & 4 deletions .github/workflows/updatecli.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
name: Update CLI

on:
workflow_dispatch:
schedule:
# * is a special character in YAML so you have to quote this string
# Run once a day
- cron: '0 0 * * *'
workflow_dispatch:

jobs:
updatecli:
Expand All @@ -15,14 +14,12 @@ jobs:
uses: actions/checkout@v4
- name: Setup updatecli
uses: updatecli/updatecli-action@v2

- name: Diff
continue-on-error: true
run: |
updatecli diff --config updatecli/updatecli.d --values updatecli/values.yml
env:
UPDATECLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Apply
if: github.ref == 'refs/heads/main'
run: |
Expand Down
9 changes: 8 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Release notes are recorded in https://github.com/jenkinsci/custom-folder-icon-pl

This version requires Jenkins 2.357 and above in order to support the transition to https://www.jenkins.io/blog/2022/06/28/require-java-11/[Java 11].

* Version 2.10 enables users to select the jobs to be considered for the combined build status in `BuildStatusFolderIcon`.
* Version 2.9 introduces a new type of icon.
The `FontAwesomeFolderIcon` provides https://fontawesome.com[Font Awesome] icons.
* Version 2.6 enables users to select and re-use an already existing `CustomFolderIcon`. Further an icon file will now be deleted automatically if the folder it used is being deleted - unless of course the file is still used by another folder.
Expand Down Expand Up @@ -95,6 +96,10 @@ image:images/build-status-folder-icon.png[]

Select the _Build Status Folder Icon_ option to use the combined build status of the jobs within a folder as icon.

You can select which jobs should be considered when the combined build status is determined.

When no jobs are selected every job within the folder is considered for the combined build status.

image:images/build-status-folder-icon-configuration.png[]

===== Job DSL
Expand All @@ -105,7 +110,9 @@ Configuration via https://github.com/jenkinsci/job-dsl-plugin[job-dsl-plugin]:
----
folder('build-status') {
icon {
buildStatusFolderIcon()
buildStatusFolderIcon {
jobs('main', 'dev')
}
}
}
----
Expand Down
Binary file modified images/build-status-folder-icon-configuration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/build-status-folder-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/custom-folder-icon-configuration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/custom-folder-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/emoji-folder-icon-configuration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/emoji-folder-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/fontawesome-folder-icon-configuration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/fontawesome-folder-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/global-configuration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/ionicon-folder-icon-configuration.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/ionicon-folder-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/overview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 75 additions & 25 deletions src/main/java/jenkins/plugins/foldericon/BuildStatusFolderIcon.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
import org.kohsuke.stapler.Stapler;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
* A Build Status Folder Icon.
Expand All @@ -46,47 +50,97 @@
*/
public class BuildStatusFolderIcon extends FolderIcon {

private final Set<String> jobs;

private AbstractFolder<?> owner;

/**
* Ctor.
*
* @param jobs the jobs to consider for combined build status (null / empty means all jobs).
*/
@DataBoundConstructor
public BuildStatusFolderIcon() {
// NOP
public BuildStatusFolderIcon(Set<String> jobs) {
this.jobs = jobs;
}

@Override
protected void setOwner(AbstractFolder<?> folder) {
this.owner = folder;
}

private BallColor getCombinedBallColor() {
boolean empty = false;
boolean buildable = false;
boolean running = false;
/**
* @return the jobs to consider for combined build status (null / empty means all jobs).
*/
public Set<String> getJobs() {
return jobs;
}

Result combinedResult = null;
/**
* @return all available jobs in the current folder.
*/
public Set<String> getAvailableJobs() {
return getAllJobs()
.stream()
.map(job -> job.getRelativeDisplayNameFrom(owner))
.collect(Collectors.toCollection(TreeSet::new));
}

@SuppressWarnings("rawtypes")
private Collection<? extends Job> getAllJobs() {
if (owner != null) {
Collection<? extends Job> jobs = owner.getAllJobs();
empty = jobs.isEmpty();
for (Job<?, ?> job : jobs) {
if (job.isBuildable()) {
buildable = true;
Run<?, ?> build = job.getLastBuild();
if (build != null && build.isBuilding()) {
running = true;
build = build.getPreviousBuild();
}
Result result = build != null ? build.getResult() : null;
combinedResult = Result.combine(combinedResult, result);
return owner.getAllJobs();
} else {
return Set.of();
}
}

@SuppressWarnings("rawtypes")
private Collection<? extends Job> getConfiguredJobs() {
Collection<? extends Job> availableJobs = getAllJobs();
Collection<? extends Job> filteredJobs = new HashSet<>();
Set<String> configuredJobs = getJobs();

if (configuredJobs != null) {
// filter jobs that exist and are configured
filteredJobs = availableJobs.stream()
.filter(job -> configuredJobs.contains(job.getRelativeDisplayNameFrom(owner)))
.collect(Collectors.toSet());
}

// if filtered result is empty return all available instead
return filteredJobs.isEmpty() ? availableJobs : filteredJobs;
}

private BallColor getCombinedBallColor() {
var configuredJobs = getConfiguredJobs();

Result combinedResult = null;
boolean buildable = false;
boolean running = false;
boolean empty = configuredJobs.isEmpty();

for (var job : configuredJobs) {
if (job.isBuildable()) {
buildable = true;
Run<?, ?> build = job.getLastBuild();
if (build != null && build.isBuilding()) {
running = true;
build = build.getPreviousBuild();
}
Result result = build != null ? build.getResult() : null;
combinedResult = Result.combine(combinedResult, result);
}
}

BallColor color = combinedResult != null ? combinedResult.color
: empty ? BallColor.NOTBUILT : buildable ? BallColor.NOTBUILT : BallColor.DISABLED;
BallColor color;
if (combinedResult != null) {
color = combinedResult.color;
} else if (empty || buildable) {
color = BallColor.NOTBUILT;
} else {
color = BallColor.DISABLED;
}

return running ? color.anime() : color;
}
Expand Down Expand Up @@ -130,9 +184,5 @@ public String getDisplayName() {
return Messages.BuildStatusFolderIcon_description();
}

@Override
public boolean isApplicable(Class<? extends AbstractFolder> folderType) {
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ protected void setOwner(AbstractFolder<?> folder) {
}

/**
* @return the foldericon
* @return the foldericon.
*/
public String getFoldericon() {
return foldericon;
Expand Down Expand Up @@ -154,11 +154,6 @@ public String getDisplayName() {
return Messages.CustomFolderIcon_description();
}

@Override
public boolean isApplicable(Class<? extends AbstractFolder> folderType) {
return true;
}

/**
* Uploads an icon.
*
Expand Down
5 changes: 0 additions & 5 deletions src/main/java/jenkins/plugins/foldericon/EmojiFolderIcon.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,5 @@ public String getDisplayName() {
return Messages.EmojiFolderIcon_description();
}

@Override
public boolean isApplicable(Class<? extends AbstractFolder> folderType) {
return true;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,5 @@ public String getDisplayName() {
return Messages.FontAwesomeFolderIcon_description();
}

@Override
public boolean isApplicable(Class<? extends AbstractFolder> folderType) {
return true;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,5 @@ public String getDisplayName() {
return Messages.IoniconFolderIcon_description();
}

@Override
public boolean isApplicable(Class<? extends AbstractFolder> folderType) {
return true;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ SOFTWARE.

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Details}" />
<f:entry title="${%Details}" field="jobs" help="${descriptor.getHelpFile('selection')}">
<j:forEach items="${instance.getAvailableJobs()}" var="job">
<f:checkbox json="${job}" checked="${instance.jobs.contains(job)}" title="${job}" />
<br />
</j:forEach>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!--
The MIT License
Copyright (c) 2023 strangelookingnerd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->

<div>
You can select the jobs to be considered for the combined build status.</br>If you select none then all jobs are considered.
</div>

0 comments on commit 6ff2849

Please sign in to comment.