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

added basic/simple adaptive cards support #358

Merged
merged 4 commits into from
Oct 14, 2024

Conversation

markush81
Copy link
Contributor

Testing done

Add starting point for AdaptiveCard Support because of Microsofts announcement.

Only manually tested in installation where i am working.

The PR is just meant as starting point to fully implement what is needed (unfortunately i have not the time to add tests and all variants, like check encoding of provided message).

Submitter checklist


import java.util.List;

public interface Action {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action is very generic and very popular class name, how about making ConnectorAction or similar to avoid mismatch in class importing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will take CardAction since the new way is not a Connector anymore, but a PowerAutomate Workflow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


void setName(String name);

void setTarget(List<String> target);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setTargets since this takes list as a parameter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then I believe both should be updated to be consistent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@Override
public void setThemeColor(final String cardThemeColor) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty method?

Copy link
Contributor Author

@markush81 markush81 Aug 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, haven't used cardThemeColor (because the AdaptiveCard format doesn't really support color - ok with workarounds - it just a fixed enum https://github.com/microsoft/AdaptiveCards/blob/main/schemas/1.4.0/adaptive-card.json#L1494), but too much depends in the old MessageCard on having this method ... so i left it intentionally empty (meaning: not enough time to do necessary refactoring).


import java.util.List;

public class AdaptiveCardAction implements jenkins.plugins.office365connector.model.Action {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why full package name here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@Override
public void setTarget(final List<String> target) {
target.stream().findFirst().ifPresent(this::setUrl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applies only to first element, why is that ?

Copy link
Contributor Author

@markush81 markush81 Aug 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old PotentialAction works internally with list https://github.com/jenkinsci/office-365-connector-plugin/blob/master/src/main/java/jenkins/plugins/office365connector/model/PotentialAction.java#L34 cause the format expects that https://learn.microsoft.com/en-us/outlook/actionable-messages/message-card-reference#openuri-action.

But the AdaptiveCard action doesn't https://adaptivecards.io/explorer/Action.OpenUrl.html.
So that's why internally url (single) is used.

As far as i can see, the whole code doesn't add more than one anyway. So a bigger refactoring should/could be, work internally with single attribute and only modify the getTarget in MessageCard to return a list to fulfil the MessageCard JSON format.

@markush81 markush81 force-pushed the o365-adaptivecards branch 2 times, most recently from f366899 to e815b95 Compare August 8, 2024 05:28
@markush81
Copy link
Contributor Author

two basic integration tests added to have at least "some" coverage.

@damianszczepanik
Copy link
Member

What I understand from #355 with new approach we need to configure how to convert information from Jenkins into MS Teams even so I am not sure if we need to convert to adaptive card

@markush81
Copy link
Contributor Author

markush81 commented Aug 24, 2024

What I understand from #355 with new approach we need to configure how to convert information from Jenkins into MS Teams even so I am not sure if we need to convert to adaptive card

In can be any Card format which ideally is not deprecated or declared legacy. As far as i understand https://learn.microsoft.com/en-us/outlook/actionable-messages/message-card-reference, the current implemented format is not recommended anymore

Microsoft recommends that new actionable message integrations use the Adaptive Card format, and existing integrations consider updating to Adaptive Card format.

Indeed the same thing says

However, if you are sending actionable messages via an Office connector, or to a Microsoft Teams connector, you must continue to use the message card format.

Which is a) not true (from other applications we were sending Adaptive Cards since more than a year to the mentioned connectors) and b) they retired the connectors.

So IMHO the best way to go forward is, to use AdaptiveCard format.

@marssilva
Copy link

Hello @markush81 , is it possible to set adaptiveCards as default? "Incoming Webhook" already has native support, it would not impact the current connector and would help in the migration to power automate.

https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL%2Ctext1#send-adaptive-cards-using-an-incoming-webhook

@markush81
Copy link
Contributor Author

Hello @markush81 , is it possible to set adaptiveCards as default? "Incoming Webhook" already has native support, it would not impact the current connector and would help in the migration to power automate.

https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL%2Ctext1#send-adaptive-cards-using-an-incoming-webhook

Technically we can, but i am not sure if there is agreement for what the plugin should do in future.

@astrahan87
Copy link

@markush81 Is there any update on the status of this?

@markush81
Copy link
Contributor Author

@markush81 Is there any update on the status of this?

Since i am not maintainer, i am also waiting for review and merge. IMHO i have done the requested changes a while ago.

@astrahan87
Copy link

@damianszczepanik It does look like the requested changes have been made. Is there anything else?

@damianszczepanik
Copy link
Member

One concern I have is to how to configure the hook. Based on the comments from developers I'm not even sure if we need this change as I found conclusion that with powerautomate you need to translate what is received via webhook into MS Teams message.

So concluding it would be best to update README file as well so this is clear how to configure hook with new addaptive cards and also so I'm able to test it before it gets merged.

@markush81
Copy link
Contributor Author

markush81 commented Oct 10, 2024

One concern I have is to how to configure the hook. Based on the comments from developers I'm not even sure if we need this change as I found conclusion that with powerautomate you need to translate what is received via webhook into MS Teams message.

So concluding it would be best to update README file as well so this is clear how to configure hook with new addaptive cards and also so I'm able to test it before it gets merged.

In the retirement article https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/, they mention the migration:

I haven't found any good other description, most create it custom and parse the JSON and so on ... but we never did this, we migrated all our webhooks with exactly this template and didn't need to do anything further than that.

@kikmon
Copy link

kikmon commented Oct 11, 2024

That change would be quite useful since manually converting the json in powerautomate is a bit tedious, and doesn't scale that well when you have many hooks
Having this plugin send adaptive cards will be very helpful.

@damianszczepanik
Copy link
Member

That change would be quite useful since manually converting the json in powerautomate is a bit tedious, and doesn't scale that well when you have many hooks Having this plugin send adaptive cards will be very helpful.

OK, this sounds like question for the answer I didn't get the answer so far!
I will review this one more time, read mentioned docs and merge this.

@marssilva
Copy link

One piece of information, adaptive cards work in the new flow with powerautomate and in the current Incoming Webhook. As a suggestion, it would be interesting to leave the default adaptive cards, aiming at the future that the current standard is discontinued.


public class Webhook extends AbstractDescribableImpl<Webhook> {

public static final Integer DEFAULT_TIMEOUT = 30000;
private static final Logger log = LoggerFactory.getLogger(Webhook.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added but not used

}
}

private String color(final Result result) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should be removed later ?

@SuppressFBWarnings(value = "SS_SHOULD_BE_STATIC")
private final String version = "1.4";
@SerializedName("msTeams")
private final MsTeams msteams = new MsTeams();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you use msTeams then @SerializedName should be useless and name will be more like Java convention


public class MsTeams {

@SuppressFBWarnings(value = "SS_SHOULD_BE_STATIC")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since width is not a final I believe this annotation is not needed here

public class Payload {

@SuppressFBWarnings(value = "SS_SHOULD_BE_STATIC")
private String type = "message";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here about annotation: annotation or static

public class MessageCard implements Card {

private String summary;
private String themeColor = "3479BF";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it valid for adaptive cards?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adaptive Cards and colors are different, there is either a fixed enum which can be used, as done here jenkins.plugins.office365connector.model.adaptivecard.AdaptiveCard#color or do sth. like Semaphore UI does https://github.com/semaphoreui/semaphore/blob/develop/services/tasks/templates/microsoft-teams.tmpl#L44

@@ -24,7 +24,7 @@
import org.junit.Test;
import org.mockito.MockedStatic;

public class ActionableBuilderTest {
public class ActionablePotentialActionBuilderTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no class ActionablePotentialActionBuilder so there is something wrong with class name

@@ -0,0 +1,27 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name of this file does not pass exactly naming convention others

@damianszczepanik
Copy link
Member

@markush81 I did review one more time. I have left a few comments but they are not blocking merging this change to master branch. This pull request is significant and valuable.
I have plan to merge #365 and then publish - take a look if you are OK with that
Also share a few details how did you test adaptive cards with this pull request and also are you planing to maintain this for a while before new version with adaptive cards support gets stable?

@@ -201,8 +213,8 @@
return FormUtils.formValidateUrl(value);
}

public FormValidation doCheckGlobalUrl(@QueryParameter String value) {
if(StringUtils.isNotBlank(value)) {
public FormValidation doCheckGlobalUrl(@QueryParameter String value) {

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing POST/RequirePOST annotation Warning

Potential CSRF vulnerability: If DescriptorImpl#doCheckGlobalUrl connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @POST or @RequirePOST
@@ -201,8 +213,8 @@
return FormUtils.formValidateUrl(value);
}

public FormValidation doCheckGlobalUrl(@QueryParameter String value) {
if(StringUtils.isNotBlank(value)) {
public FormValidation doCheckGlobalUrl(@QueryParameter String value) {

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing permission check Warning

Potential missing permission check in DescriptorImpl#doCheckGlobalUrl
@markush81
Copy link
Contributor Author

@markush81 I did review one more time. I have left a few comments but they are not blocking merging this change to master branch.

Adjust most of the them.

I have plan to merge #365 and then publish - take a look if you are OK with that

I am fine with the plan.

Also share a few details how did you test adaptive cards with this pull request

We have this version with my PR running since i created it, in our installation - so kinda live-testing.
One point of course, we use Pipeline DSL variant only.

and also are you planing to maintain this for a while before new version with adaptive cards support gets stable?

I can't promise anything, but of course will do my best in case after merge issues occur.

@damianszczepanik damianszczepanik merged commit 76e337a into jenkinsci:master Oct 14, 2024
22 checks passed
@kikmon
Copy link

kikmon commented Oct 15, 2024

Thanks a lot to you guys :)

@damianszczepanik
Copy link
Member

@markush81 @kikmon version 5.0.0 has been published

@ViliusS
Copy link

ViliusS commented Oct 15, 2024

I'm a little bit confused how to proceed with an upgrade to 5.0.0.

  • Is there a way to send AdaptiveCard true in a Declarative Pipeline?
  • Should we switch to new Workflow app webhook on Teams side, or to Incoming Webhook connector, given that currently we are using Jenkins 365 Connector Webhook? Or Jenkins 365 Connector should work fine?

@kikmon
Copy link

kikmon commented Oct 16, 2024

As far as I know, this MR added the parameter adaptiveCards in the declarative pipeline too, so you should be good.
365 connectors will stop working next year, so you might as well start creating your workflows now.
That being said, it would be nice to have a documented 'Best Practice' use case with Workflows and adaptive cards.

@movedoa
Copy link

movedoa commented Oct 16, 2024

What do i need to change in a groovy script to send a success/unstable message.
Currently i use:

office365ConnectorSend webhookUrl: 'url',
            message: "${loStatus} - ${oCurNewVersion}",
            color: loColor
      }

As far as i gathered, color is not supported anymore, ss how would i indicate started/success/failure?
Also do i need to add new parameters to make the plugin send an adaptive card?

An updated documentation would be very nice :)

@ViliusS
Copy link

ViliusS commented Oct 16, 2024

OK, I think I figured out the upgrade path:

  1. If you are using Jenkins Connector for Teams with an old webhook URL default settings (adaptiveCards: false) in 5.0.0 will work . You don't need to change anything on Jenkins side.
  2. If you are using Jenkins Connector for Teams with a new improved URL (new URLs will be required by Microsoft as of 2025-02-01) the plugin won't work at all. I guess Jenkins Connector for Teams doesn't support new webhook URLs even though it allows to set them.
  3. If you are using Incoming Webhook Connector for Teams then plugin should work with both adaptiveCards: false and adaptiveCards: true settings. Message formating in Teams channel will be a little bit different, but all essential information will be there.
  4. If you are using Post to a channel when a webhook request is received Power Automate Workflow then you must set adaptiveCards: true. Workflows do not support other message formats.

At least this is how it behaves on my environment and Microsoft 365 tenant.

@rdrgporto
Copy link
Contributor

rdrgporto commented Oct 16, 2024

Hi,

An example with Post to a channel when a webhook request is received Power Automate Workflow would be:

post {
 success {
  office365ConnectorSend webhookUrl: '<webhook-url>', 
    message: 'Test with Webhook Microsoft Teams', 
    adaptiveCards: true
 }
}

Regards

@damianszczepanik
Copy link
Member

Hi,

An example with Post to a channel when a webhook request is received Power Automate Workflow would be:

post {
 success {
  office365ConnectorSend webhookUrl: '<webhook-url>', 
    message: 'Test with Webhook Microsoft Teams', 
    adaptiveCards: true
 }
}

Regards

@rdrgporto would you prepare pull request with updated README file about adaptive cards

@damianszczepanik
Copy link
Member

@markush81 In #355 (comment) @ViliusS has mentioned that the plugin does not support credentials what is benefit of having adaptive cards but is still not supported by the plugin. How did you fix that problem?

@ViliusS
Copy link

ViliusS commented Oct 17, 2024

@damianszczepanik maybe I was not very clear with my comments in another thread. Adaptive Card support in the plugin is working and fine. The issue I was discussing is that someone said that Workflow trigger URL is public, hence insecure. But it was also the case for Incoming Webhook or Jenkins connectors. Nothing has changed regarding security on that part.

BTW, Microsoft actually updated their documentation today: https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/
The timeline for Teams/Oulook Connector deprecation is as follows:

2025-02-01 - All connectors with old webhook URL will stop working. Users must update webhook URLs. So far as I tried, at this point, only Incoming Webhook connector is working with the updated URL. Jenkins connector doesn't work and it doesn't matter which Card format you send. I suspect it needs to be updated somehow to accept new URL format, but I doubt Microsoft will ever do that. Especially considering that that connector only accepts legacy MessageCard messages.
After this day, the only way forward is to use Workflows or general Incoming Webhook connector.
2025 March-April - Microsoft promises to implement MessageCard format support in Workflows.
sometime at the end of 2025 - All Office 365 connectors are discontinued and stops working.
After that, the only working solution is to use Workflows with AdaptiveCard format as recommended, and alternative MessageCard format support if MS keeps their promises.

Thinking about AdaptiveCard support further I would vote to enable it by default now and point plugin users to upgrade instructions, or do it after 2025-02-01 which will probably mark the end of Jenkins connector on MS side anyway.

Also probably plugin naming could be revised again as AdaptiveCards are now implemented by Cisco too. Maybe more implementations will follow. I would vote for something more generalized, like AdaptiveCard sender or Actionable Message sender :)

@markush81
Copy link
Contributor Author

@markush81 In #355 (comment) @ViliusS has mentioned that the plugin does not support credentials what is benefit of having adaptive cards but is still not supported by the plugin. How did you fix that problem?

There is no authentication, but @ViliusS already commented i see.

@markush81
Copy link
Contributor Author

As far as i gathered, color is not supported anymore, ss how would i indicate started/success/failure?
Also do i need to add new parameters to make the plugin send an adaptive card?

Coloring in AdaptiveCards works with a fixed set (or adding background images). So far the plugin determines the color based on build result https://github.com/jenkinsci/office-365-connector-plugin/blob/master/src/main/java/jenkins/plugins/office365connector/model/adaptivecard/AdaptiveCard.java#L40.

@rdrgporto
Copy link
Contributor

Hi,
An example with Post to a channel when a webhook request is received Power Automate Workflow would be:

post {
 success {
  office365ConnectorSend webhookUrl: '<webhook-url>', 
    message: 'Test with Webhook Microsoft Teams', 
    adaptiveCards: true
 }
}

Regards

@rdrgporto would you prepare pull request with updated README file about adaptive cards

Hi @damianszczepanik,

It would be a example like that in README.md? (after Pipeline post section):

Pipeline post section with Adaptive Cards

pipeline {

    agent any

    stages {
        stage('Init') {
            steps {
                echo 'Hello!'
            }
        }
    }

    post {
        failure {
            office365ConnectorSend webhookUrl: "https://prod.westeurope.logic.azure.com:443/workflows...",
              message: 'Something went wrong', 
              status: 'Failure',
              adaptiveCards: true
        }
    }
}

Thanks in advance,

Regards

@damianszczepanik
Copy link
Member

Sounds like a good example of how to use new approach - please create PR with updated README file

@aksh05
Copy link

aksh05 commented Oct 29, 2024

@rdrgporto Are you planning to raise a PR with changes to README about the change? If not, would be happy to help create it. Thanks!

@rdrgporto
Copy link
Contributor

Hi, @damianszczepanik and @aksh05

I have created a Pull Request:

Thanks in advance,

Regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants