Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-34502] Provide health metric for a named child of the folder #243

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4605dfd
(JENKINS-34502) provide health metric for a named child of the folder
strangelookingnerd Jun 25, 2022
ceecb2e
Merge branch 'master' into JENKINS-34502
strangelookingnerd Oct 4, 2022
d502064
Merge branch 'master' into JENKINS-34502
strangelookingnerd Oct 10, 2022
4a75f33
Merge branch 'master' into JENKINS-34502
strangelookingnerd Oct 27, 2022
f60eba6
Merge branch 'master' into JENKINS-34502
strangelookingnerd Nov 4, 2022
23c4e34
Merge branch 'master' into JENKINS-34502
strangelookingnerd Nov 11, 2022
701bba0
Merge branch 'master' into JENKINS-34502
strangelookingnerd Nov 29, 2022
43a004d
Merge branch 'master' into JENKINS-34502
strangelookingnerd Dec 13, 2022
d29f6ce
Merge branch 'master' into JENKINS-34502
strangelookingnerd Feb 9, 2023
0ac77ee
Merge branch 'master' into JENKINS-34502
strangelookingnerd Feb 21, 2023
5193ed6
Merge branch 'master' into JENKINS-34502
strangelookingnerd Feb 26, 2023
5b1562d
Merge branch 'master' into JENKINS-34502
strangelookingnerd Mar 3, 2023
d23a5d0
Merge branch 'master' into JENKINS-34502
strangelookingnerd May 9, 2023
4ac3c9a
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jun 5, 2023
ceb4767
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jul 17, 2023
3cc83db
Merge branch 'master' into JENKINS-34502
strangelookingnerd Aug 31, 2023
45768b5
Merge branch 'master' into JENKINS-34502
strangelookingnerd Oct 17, 2023
b3f87c6
Merge branch 'master' into JENKINS-34502
car-roll Oct 18, 2023
2b85aec
Merge branch 'master' into JENKINS-34502
car-roll Oct 18, 2023
8b3c285
Merge branch 'master' into JENKINS-34502
strangelookingnerd Nov 23, 2023
080d006
Merge branch 'master' into JENKINS-34502
strangelookingnerd Dec 3, 2023
46b2c9a
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jan 9, 2024
63efeee
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jan 18, 2024
ed5d0ac
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jan 25, 2024
420e3d2
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jan 30, 2024
ec5138e
Merge branch 'master' into JENKINS-34502
strangelookingnerd Feb 3, 2024
271801a
Merge branch 'master' into JENKINS-34502
strangelookingnerd Feb 18, 2024
d08f81f
Merge branch 'master' into JENKINS-34502
strangelookingnerd Apr 17, 2024
1ce960f
Merge branch 'master' into JENKINS-34502
strangelookingnerd May 27, 2024
813333a
Merge branch 'master' into JENKINS-34502
strangelookingnerd Jun 20, 2024
d1dde33
Merge branch 'master' into JENKINS-34502
strangelookingnerd Aug 6, 2024
345481c
Add RequirePOST annotation
strangelookingnerd Aug 6, 2024
c903e97
Merge branch 'master' into JENKINS-34502
strangelookingnerd Sep 11, 2024
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
Expand Up @@ -794,66 +794,60 @@
+ TimeUnit.MINUTES.toMillis(HEALTH_REPORT_CACHE_REFRESH_MIN * 3L / 4L)
+ ENTROPY.nextInt((int)TimeUnit.MINUTES.toMillis(HEALTH_REPORT_CACHE_REFRESH_MIN / 2));
reports = new ArrayList<>();
List<FolderHealthMetric.Reporter> reporters = new ArrayList<>(healthMetrics.size());
boolean recursive = false;
boolean topLevelOnly = true;

for (FolderHealthMetric metric : healthMetrics) {
recursive = recursive || metric.getType().isRecursive();
topLevelOnly = topLevelOnly && metric.getType().isTopLevelItems();
reporters.add(metric.reporter());
FolderHealthMetric.Reporter reporter = metric.reporter();
observeMetric(metric.getType(), reporter);
reports.addAll(reporter.report());

}
for (AbstractFolderProperty<?> p : getProperties()) {
for (FolderHealthMetric metric : p.getHealthMetrics()) {
recursive = recursive || metric.getType().isRecursive();
topLevelOnly = topLevelOnly && metric.getType().isTopLevelItems();
reporters.add(metric.reporter());
FolderHealthMetric.Reporter reporter = metric.reporter();
observeMetric(metric.getType(), reporter);
reports.addAll(p.getHealthReports());

Check warning on line 808 in src/main/java/com/cloudbees/hudson/plugins/folder/AbstractFolder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 806-808 are not covered by tests
}
}
if (recursive) {
Stack<Iterable<? extends Item>> stack = new Stack<>();
stack.push(getItems());
if (topLevelOnly) {
while (!stack.isEmpty()) {
for (Item item : stack.pop()) {
if (item instanceof TopLevelItem) {
for (FolderHealthMetric.Reporter reporter : reporters) {

Collections.sort(reports);
healthReports = reports; // idempotent write
return reports;
}

private void observeMetric(FolderHealthMetric.Type type, FolderHealthMetric.Reporter reporter) {
if (type.isWithChildren()) {

Check warning on line 818 in src/main/java/com/cloudbees/hudson/plugins/folder/AbstractFolder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 818 is only partially covered, one branch is missing
if (type.isRecursive()) {
Stack<Iterable<? extends Item>> stack = new Stack<>();
stack.push(getItems());
if (type.isTopLevelItems()) {

Check warning on line 822 in src/main/java/com/cloudbees/hudson/plugins/folder/AbstractFolder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 819-822 are not covered by tests
while (!stack.isEmpty()) {
for (Item item : stack.pop()) {
if (item instanceof TopLevelItem) {
reporter.observe(item);
if (item instanceof Folder) {
stack.push(((Folder) item).getItems());
}
}
}
}
} else {
while (!stack.isEmpty()) {
for (Item item : stack.pop()) {
reporter.observe(item);
if (item instanceof Folder) {
stack.push(((Folder) item).getItems());
}
}
}
}
} else {
while (!stack.isEmpty()) {
for (Item item : stack.pop()) {
for (FolderHealthMetric.Reporter reporter : reporters) {
reporter.observe(item);
}
if (item instanceof Folder) {
stack.push(((Folder) item).getItems());
}
}
}
}
} else {
for (Item item: getItems()) {
for (FolderHealthMetric.Reporter reporter : reporters) {
for (Item item : getItems()) {
reporter.observe(item);
}
}
} else {
reporter.observe(this);
}
for (FolderHealthMetric.Reporter reporter : reporters) {
reports.addAll(reporter.report());
}
for (AbstractFolderProperty<?> p : getProperties()) {
reports.addAll(p.getHealthReports());
}

Collections.sort(reports);
healthReports = reports; // idempotent write
return reports;
}

public DescribableList<FolderHealthMetric, FolderHealthMetricDescriptor> getHealthMetrics() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,26 @@ public interface Reporter {
}

public enum Type {
IMMEDIATE_TOP_LEVEL_ITEMS(false, true),
RECURSIVE_TOP_LEVEL_ITEMS(true, true),
IMMEDIATE_ALL_ITEMS(false, false),
RECURSIVE_ALL_ITEMS(true, false);


SELF_ONLY(false, false, false),
IMMEDIATE_TOP_LEVEL_ITEMS(true, false, true),
RECURSIVE_TOP_LEVEL_ITEMS(true, true, true),
IMMEDIATE_ALL_ITEMS(true, false, false),
RECURSIVE_ALL_ITEMS(true, true, false);

private final boolean withChildren;
private final boolean recursive;

private final boolean topLevelItems;

Type(boolean recursive, boolean topLevelItems) {
Type(boolean withChildren, boolean recursive, boolean topLevelItems) {
this.withChildren = withChildren;
this.recursive = recursive;
this.topLevelItems = topLevelItems;
}

public boolean isWithChildren() {
return withChildren;
}

public boolean isRecursive() {
return recursive;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* The MIT License
*
* Copyright 2013 CloudBees.
*
* 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.
*/

package com.cloudbees.hudson.plugins.folder.health;

import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import hudson.Extension;
import hudson.model.AutoCompletionCandidates;
import hudson.model.HealthReport;
import hudson.model.Item;
import hudson.model.ItemGroup;

/**
* A health metric for a named child item.
*
* @author strangelookingnerd
*
*/
public class NamedChildHealthMetric extends FolderHealthMetric {

private String childName;

/**
* Ctor.
*
* @param childName
* name of the child
*/
@DataBoundConstructor
public NamedChildHealthMetric(String childName) {
this.childName = childName;
}

/**
* @return the name of the child.
*/
public String getChildName() {
return childName;

Check warning on line 68 in src/main/java/com/cloudbees/hudson/plugins/folder/health/NamedChildHealthMetric.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 68 is not covered by tests
}

@Override
public Type getType() {
return Type.SELF_ONLY;
}

@Override
public Reporter reporter() {
return new ReporterImpl(childName);
}

/**
* Descriptor Implementation.
*
* @author strangelookingnerd
*
*/
@Extension(ordinal = 400)
public static class DescriptorImpl extends FolderHealthMetricDescriptor {

private static final String DEFAULT = "";

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

@Override
public FolderHealthMetric createDefault() {
return new NamedChildHealthMetric(DEFAULT);
}

/**
* Auto-completion for the "child names" field in the configuration.
*
* @param value
* the input
* @param container
* the context
* @return the candidates
*/
@Restricted(DoNotUse.class)
public AutoCompletionCandidates doAutoCompleteChildName(@QueryParameter String value,
Fixed Show fixed Hide fixed
@AncestorInPath ItemGroup<Item> container) {
AutoCompletionCandidates candidates = new AutoCompletionCandidates();
for (Item item : container.getItems()) {
if (StringUtils.startsWith(item.getName(), value)) {
candidates.add(item.getName());
}
}
return candidates;

Check warning on line 120 in src/main/java/com/cloudbees/hudson/plugins/folder/health/NamedChildHealthMetric.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 114-120 are not covered by tests
}
}

private static class ReporterImpl implements Reporter {
private HealthReport report = null;
private String childName;

/**
* Ctor.
*
* @param childName
* name of the child
*/
public ReporterImpl(String childName) {
this.childName = childName;
}

@Override
public void observe(Item item) {
if (item instanceof ItemGroup) {

Check warning on line 140 in src/main/java/com/cloudbees/hudson/plugins/folder/health/NamedChildHealthMetric.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 140 is only partially covered, one branch is missing
Item child = ((ItemGroup<Item>) item).getItem(childName);
if (child != null) {
report = getHealthReport(child);
}
}
}

@Override
public List<HealthReport> report() {
return report != null ? Collections.singletonList(report) : Collections.emptyList();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Folder.HealthWrap=Worst health: {0}: {1}
WorstChildHealthMetric.DisplayName=Child item with worst health
WorstChildHealthMetric.DisplayName=Child item with worst health
NamedChildHealthMetric.DisplayName=Child item with the given name
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@
# THE SOFTWARE.

Folder.HealthWrap=\u6700\u60aa\u306e\u5065\u5168\u6027: {0}: {1}
WorstChildHealthMetric.DisplayName=Child item with worst health
WorstChildHealthMetric.DisplayName=Child item with worst health
NamedChildHealthMetric.DisplayName=Child item with the given name
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
The MIT License
Copyright 2013 CloudBees.
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.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:f="/lib/form">
<f:entry title="${%ChildName}" help="${descriptor.getHelpFile('childName')}">
<f:textbox field="childName" />
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ChildName=Child Name
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Controls the child item within this folder representing to the health of this folder.
</div>
Loading