Skip to content

Commit

Permalink
Added basic/simple adaptive cards support (#358)
Browse files Browse the repository at this point in the history
* added basic/simple adaptive cards support

* some review comments fixed

* added two integration tests to have some coverage

* final review comments
  • Loading branch information
markush81 authored Oct 14, 2024
1 parent c6d2f59 commit 76e337a
Show file tree
Hide file tree
Showing 38 changed files with 806 additions and 110 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ x64/
build/
[Bb]in/
[Oo]bj/
work

# MSTest test Results
[Tt]est[Rr]esult*/
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>findbugs-annotations</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import hudson.model.Job;
import hudson.model.Result;
import hudson.model.Run;
import jenkins.plugins.office365connector.model.PotentialAction;
import jenkins.plugins.office365connector.model.CardAction;
import jenkins.plugins.office365connector.model.adaptivecard.AdaptiveCardAction;
import jenkins.plugins.office365connector.model.messagecard.PotentialAction;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.metadata.ContributorMetadataAction;
import jenkins.scm.api.metadata.ObjectMetadataAction;
Expand All @@ -34,14 +36,16 @@ public class ActionableBuilder {

private final Run run;
private final FactsBuilder factsBuilder;
private final List<PotentialAction> potentialActions = new ArrayList<>();
private final List<CardAction> potentialActions = new ArrayList<>();
private final boolean isAdaptiveCards;

public ActionableBuilder(Run run, FactsBuilder factsBuilder) {
public ActionableBuilder(Run run, FactsBuilder factsBuilder, boolean isAdaptiveCards) {
this.run = run;
this.factsBuilder = factsBuilder;
this.isAdaptiveCards = isAdaptiveCards;
}

public List<PotentialAction> buildActionable() {
public List<CardAction> buildActionable() {

pullRequestActionable();
buildViewBuild();
Expand All @@ -56,7 +60,7 @@ private void buildViewBuild() {
// hide action button when the build succeed
if (run.getResult() != Result.SUCCESS) {
String viewHeader = Messages.Office365ConnectorWebhookNotifier_ViewHeader(build);
potentialActions.add(new PotentialAction(viewHeader, urlToJob));
potentialActions.add(isAdaptiveCards ? new AdaptiveCardAction(viewHeader,urlToJob) : new PotentialAction(viewHeader, urlToJob));

Check warning on line 63 in src/main/java/jenkins/plugins/office365connector/ActionableBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 63 is only partially covered, one branch is missing
}
}

Expand All @@ -76,7 +80,7 @@ private void pullRequestActionable() {
ObjectMetadataAction oma = job.getAction(ObjectMetadataAction.class);
if (oma != null) {
String urlString = oma.getObjectUrl();
PotentialAction viewPRPotentialAction = new PotentialAction(viewHeader, urlString);
CardAction viewPRPotentialAction = isAdaptiveCards ? new AdaptiveCardAction(viewHeader, urlString) : new PotentialAction(viewHeader, urlString);

Check warning on line 83 in src/main/java/jenkins/plugins/office365connector/ActionableBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 83 is only partially covered, one branch is missing
potentialActions.add(viewPRPotentialAction);
factsBuilder.addFact(titleHeader, oma.getObjectDisplayName());
}
Expand Down
20 changes: 12 additions & 8 deletions src/main/java/jenkins/plugins/office365connector/CardBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import jenkins.plugins.office365connector.model.Card;
import jenkins.plugins.office365connector.model.FactDefinition;
import jenkins.plugins.office365connector.model.Section;
import jenkins.plugins.office365connector.model.adaptivecard.AdaptiveCard;
import jenkins.plugins.office365connector.model.messagecard.MessageCard;
import jenkins.plugins.office365connector.workflow.StepParameters;

/**
Expand All @@ -32,12 +34,14 @@ public class CardBuilder {

private final FactsBuilder factsBuilder;
private final ActionableBuilder potentialActionBuilder;
private final boolean isAdaptiveCards;

public CardBuilder(Run run, TaskListener taskListener) {
public CardBuilder(Run run, TaskListener taskListener, boolean isAdaptiveCards) {
this.run = run;
this.isAdaptiveCards = isAdaptiveCards;

factsBuilder = new FactsBuilder(run, taskListener);
potentialActionBuilder = new ActionableBuilder(run, factsBuilder);
potentialActionBuilder = new ActionableBuilder(run, factsBuilder, isAdaptiveCards);
}

public Card createStartedCard(List<FactDefinition> factDefinitions) {
Expand All @@ -51,8 +55,8 @@ public Card createStartedCard(List<FactDefinition> factDefinitions) {
Section section = buildSection(statusName);

String summary = getDisplayName() + ": Build " + getRunName();
Card card = new Card(summary, section);
card.setPotentialAction(potentialActionBuilder.buildActionable());
Card card = isAdaptiveCards ? new AdaptiveCard(summary, section, getCompletedResult(run)) : new MessageCard(summary, section);

Check warning on line 58 in src/main/java/jenkins/plugins/office365connector/CardBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 58 is only partially covered, one branch is missing
card.setAction(potentialActionBuilder.buildActionable());

return card;
}
Expand Down Expand Up @@ -86,10 +90,10 @@ public Card createCompletedCard(List<FactDefinition> factDefinitions) {

Section section = buildSection(status);

Card card = new Card(summary, section);
Card card = isAdaptiveCards ? new AdaptiveCard(summary, section, getCompletedResult(run)) : new MessageCard(summary, section);
card.setThemeColor(getCardThemeColor(lastResult));
if (run.getResult() != Result.SUCCESS) {
card.setPotentialAction(potentialActionBuilder.buildActionable());
card.setAction(potentialActionBuilder.buildActionable());
}

return card;
Expand Down Expand Up @@ -188,13 +192,13 @@ public Card createBuildMessageCard(StepParameters stepParameters) {
Section section = new Section(activityTitle, stepParameters.getMessage(), factsBuilder.collect());

String summary = getDisplayName() + ": Build " + getRunName();
Card card = new Card(summary, section);
Card card = isAdaptiveCards ? new AdaptiveCard(summary, section, getCompletedResult(run)) : new MessageCard(summary, section);

Check warning on line 195 in src/main/java/jenkins/plugins/office365connector/CardBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 195 is only partially covered, one branch is missing

if (stepParameters.getColor() != null) {
card.setThemeColor(stepParameters.getColor());
}

card.setPotentialAction(potentialActionBuilder.buildActionable());
card.setAction(potentialActionBuilder.buildActionable());

return card;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void sendBuildStartedNotification(boolean isFromPreBuild) {
for (Webhook webhook : webhooks) {
if (decisionMaker.isAtLeastOneRuleMatched(webhook)) {
if (webhook.isStartNotification()) {
CardBuilder cardBuilder = new CardBuilder(run, taskListener);
CardBuilder cardBuilder = new CardBuilder(run, taskListener, webhook.isAdaptiveCards());
Card card = cardBuilder.createStartedCard(webhook.getFactDefinitions());
executeWorker(webhook, card);
}
Expand All @@ -76,7 +76,7 @@ public void sendBuildCompletedNotification() {
for (Webhook webhook : webhooks) {
if (decisionMaker.isAtLeastOneRuleMatched(webhook)) {
if (decisionMaker.isStatusMatched(webhook)) {
CardBuilder cardBuilder = new CardBuilder(run, taskListener);
CardBuilder cardBuilder = new CardBuilder(run, taskListener, webhook.isAdaptiveCards());
Card card = cardBuilder.createCompletedCard(webhook.getFactDefinitions());
executeWorker(webhook, card);
}
Expand All @@ -93,7 +93,9 @@ private static List<Webhook> extractWebhooks(Job job) {
}

public void sendBuildStepNotification(StepParameters stepParameters) {
CardBuilder cardBuilder = new CardBuilder(run, taskListener);
Webhook webhook = new Webhook(stepParameters.getWebhookUrl());

CardBuilder cardBuilder = new CardBuilder(run, taskListener, stepParameters.isAdaptiveCards());
Card card;
// TODO: improve this logic as the user may send any 'status' via pipeline step

Check warning on line 100 in src/main/java/jenkins/plugins/office365connector/Office365ConnectorWebhookNotifier.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: improve this logic as the user may send any 'status' via pipeline step
if (StringUtils.isNotBlank(stepParameters.getMessage())) {
Expand All @@ -104,14 +106,13 @@ public void sendBuildStepNotification(StepParameters stepParameters) {
card = cardBuilder.createCompletedCard(stepParameters.getFactDefinitions());
}

Webhook webhook = new Webhook(stepParameters.getWebhookUrl());
executeWorker(webhook, card);
}

private void executeWorker(Webhook webhook, Card card) {
try {
String url = run.getEnvironment(taskListener).expand(webhook.getUrl());
String data = gson.toJson(card);
String data = gson.toJson(card == null ? null : card.toPaylod());
HttpWorker worker = new HttpWorker(url, data, webhook.getTimeout(), taskListener.getLogger());
worker.submit();
} catch (IOException | InterruptedException | RejectedExecutionException e) {
Expand Down
18 changes: 15 additions & 3 deletions src/main/java/jenkins/plugins/office365connector/Webhook.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

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

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.Util;
Expand Down Expand Up @@ -50,13 +51,15 @@ public class Webhook extends AbstractDescribableImpl<Webhook> {

private int timeout;

private boolean adaptiveCards;

private List<Macro> macros = Collections.emptyList();

private List<FactDefinition> factDefinitions = Collections.emptyList();

@Override
public DescriptorImpl getDescriptor() {
return (DescriptorImpl) super.getDescriptor();
return (DescriptorImpl) super.getDescriptor();
}

@DataBoundConstructor
Expand Down Expand Up @@ -162,6 +165,15 @@ public List<Macro> getMacros() {
return Util.fixNull(macros);
}

@DataBoundSetter
public void setAdaptiveCards(final boolean adaptiveCards) {
this.adaptiveCards = adaptiveCards;
}

public boolean isAdaptiveCards() {
return adaptiveCards;
}

@DataBoundSetter
public void setMacros(List<Macro> macros) {
this.macros = Util.fixNull(macros);
Expand Down Expand Up @@ -201,8 +213,8 @@ public FormValidation doCheckUrl(@QueryParameter String value) {
return FormUtils.formValidateUrl(value);
}

public FormValidation doCheckGlobalUrl(@QueryParameter String value) {
if(StringUtils.isNotBlank(value)) {
public FormValidation doCheckGlobalUrl(@QueryParameter String value) {
if (StringUtils.isNotBlank(value)) {
return FormUtils.formValidateUrl(value);
} else {
return FormValidation.ok();
Expand Down
57 changes: 7 additions & 50 deletions src/main/java/jenkins/plugins/office365connector/model/Card.java
Original file line number Diff line number Diff line change
@@ -1,61 +1,18 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package jenkins.plugins.office365connector.model;

import java.util.Arrays;
import java.util.List;

/**
* @author srhebbar
*/
public class Card {

private String summary;
private String themeColor = "3479BF";

// even plugin needs only single 'section' connector API expects arrays
private List<Section> sections;

private List<PotentialAction> potentialAction;

public Card(String summary, Section section) {
this.summary = summary;
this.sections = Arrays.asList(section);
}
public interface Card {

public String getSummary() {
return summary;
}
public Object toPaylod();

public List<Section> getSections() {
return this.sections;
}
void setAction(List<CardAction> actions);

public void setThemeColor(String themeColor) {
this.themeColor = themeColor;
}
void setThemeColor(String cardThemeColor);

public String getThemeColor() {
return themeColor;
}
String getSummary();

public void setPotentialAction(List<PotentialAction> potentialActions) {
this.potentialAction = potentialActions;
}
List<Section> getSections();

public List<PotentialAction> getPotentialAction() {
return this.potentialAction;
}
String getThemeColor();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package jenkins.plugins.office365connector.model;

import java.util.List;

public interface CardAction {

void setName(String name);

void setTargets(List<String> targets);

String getName();
}
Loading

0 comments on commit 76e337a

Please sign in to comment.