Skip to content

Mention Committers On Build Failure#418

Open
AmmarOFA wants to merge 40 commits intojenkinsci:masterfrom
AmmarOFA:email-@wrapping-toggle
Open

Mention Committers On Build Failure#418
AmmarOFA wants to merge 40 commits intojenkinsci:masterfrom
AmmarOFA:email-@wrapping-toggle

Conversation

@AmmarOFA
Copy link

@AmmarOFA AmmarOFA commented Dec 16, 2025

Summary

How it Works / Idea

The goal of this feature is to allow Jenkins Office 365 Connector notifications to mention the users responsible for a build (committers or developers) in Microsoft Teams messages.

Workflow:

  1. Collect User Information

    • Jenkins gathers commit authors from the SCM (Git, SVN, etc.) associated with the build.
    • If the commit author corresponds to a Jenkins user, their email is retrieved from Jenkins (hudson.model.User).
  2. Format Mentions

    • User emails are wrapped in <at>user@example.com</at> tags using TeamsMentionUtils.
    • If no email is available, the user's full name is used as a fallback.
  3. Conditional Mentions

    • Mentions are sent only on build failures (controlled via mentionOnFailure).
  4. Send Notification

    • The Office 365 Connector sends the message/card to Teams.
    • Teams (or the Power Automate / Teams workflow connector) parses the <at> tags and converts them into proper mention entities.

Summary Flow:

The changes include:

  1. New Configurable Options:

    • mentionOnFailure – Whether mentions are sent on build failures (default: true).
  2. CardBuilder Updates:

    • Added a new constructor with mentionCommitters and mentionOnFailure parameters.
    • Updated createCompletedCard to conditionally add mentions based on these parameters.
    • Ensured backward compatibility with the existing constructor.
  3. FactsBuilder Updates:

    • addCommitters now accepts a boolean to control mentions.
    • Maintains old behavior with parameterless overloads.
    • Users are de-duplicated, sorted, and mentions applied safely.
  4. Webhook and Jelly Config Updates:

    • Added mentionOnFailure properties to Webhook.
    • Jelly UI updated to allow configuration of this new option.
  5. Utility and Tests:

    • Added TeamsMentionUtils to wrap emails in <at> tags for Teams mentions.
    • Unit tests for TeamsMentionUtils to verify behavior for users with/without emails, and email formatting.

Testing done

  1. Unit Tests:

    • Added TeamsMentionUtilsTest to verify proper handling of user mentions and email formatting.
    • Tests cover:
      • Users with valid email addresses
      • Users without email addresses
      • Null or empty email strings
  2. Manual Verification:

    • Triggered builds with different Webhook configurations:
      • With mentionOnFailure enabled/disabled.
      • Verified mentions appear correctly in Teams messages and only on failures when configured.
    • Ensured backward compatibility:
      • Existing builds without the new parameters continue to work with the default behavior.

Related Issues / PRs

#55
#416

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests that demonstrate the feature works or the issue is fixed


public static String mentionUser(User user) {
if (user == null) {
return "Unknown User";
Copy link
Member

Choose a reason for hiding this comment

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

Unknown User
or
Unknown user ?

if (user == null) {
return "Unknown User";
}
Mailer.UserProperty prop = user.getProperty(Mailer.UserProperty.class);
Copy link
Member

Choose a reason for hiding this comment

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

prop -> userProperty

return "<at>" + email + "</at>";
}

public static String mentionUser(User user) {
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 method does not report your real intention but rather fallback scenario - I believe this is still mentionEmail


boolean isRepeatedFailure = isRepeatedFailure(previousResult, lastNotFailedBuild);

boolean shouldMention = (lastResult == Result.FAILURE || lastResult == Result.UNSTABLE || isRepeatedFailure) && mentionOnFailure;
Copy link
Member

Choose a reason for hiding this comment

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

if the current build is SUCCESS but the previous was FAILURE you are mentioning - was it your intention or you just want to provide more details only on failure?

<f:checkbox/>
</f:entry>

<f:entry title="Only Mention On Failure" field="mentionOnFailure">
Copy link
Member

Choose a reason for hiding this comment

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

Mention only when build has failed

String joinedCommitters = authors.stream()
.map(User::getFullName)
.collect(Collectors.joining(", "));
.map(user -> mentionCommitters ? TeamsMentionUtils.mentionUser(user) : user.getFullName())
Copy link
Member

Choose a reason for hiding this comment

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

it complains here because you haven't extended examples in JSON file - same as for previous PR, please add it

factsBuilder.addRemarks();
factsBuilder.addCommitters();
factsBuilder.addDevelopers();
factsBuilder.addCommitters(mentionCommitters && shouldMention);
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 correct configuration if you set mentionCommiters to true and shouldMention to false?

Copy link
Author

Choose a reason for hiding this comment

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

Yes — committers are always displayed. The boolean only controls whether they’re mentioned. I’ll add clarification / rename to make that intent explicit. If I were to get rid of the mention developers toggle like I talk about here #418 (comment), then I wouldn't need a mentionCommitters toggle either as those would be the only people I'd mention. The only toggle would be shouldMention so that line would turn into

    `factsBuilder.addCommitters(shouldMention);`

for (ChangeLogSet<ChangeLogSet.Entry> set : changeSets) {
for (ChangeLogSet.Entry entry : set) {
User author = entry.getAuthor();
if (author != null) {
Copy link
Member

Choose a reason for hiding this comment

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

this null checking is examined twice: here and above

this.run = run;
this.isAdaptiveCards = isAdaptiveCards;
this.mentionCommitters = mentionCommitters;
this.mentionDevelopers = mentionDevelopers;
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 set commiters AND developers to true you will get committers list duplicated - is that correct?

committer is a subset of developers

Copy link
Author

Choose a reason for hiding this comment

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

The original intent was to allow some flexibility in terms of who you wanted to mention. Some people might want to mention Developers or Committers. Knowing that committers is essentially a blame list for who Jenkins thinks broke the build, it might make more sense to just have committers be mentioned and not developers? As far as I'm aware anyone's name in the developer section will show up in the committer section.

@AmmarOFA
Copy link
Author

Currently on vacation, will come back to this in a week or so


Run previousBuild = run.getPreviousBuild();
Result previousResult = previousBuild != null ? previousBuild.getResult() : Result.SUCCESS;
Result previousResult = previousBuild != null ? previousBuild.getResult() : Result.SUCCESS;
Copy link
Member

Choose a reason for hiding this comment

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

space at the end of the line - please clean up the files before pushing to code review

Copy link
Author

Choose a reason for hiding this comment

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

Will do, done.

.collect(Collectors.joining(", "));
.sorted(Comparator.comparing(User::getFullName))
.map(user -> mentionCommitters ? TeamsMentionUtils.mentionUserOrEmail(user) : user.getFullName())
.filter(StringUtils::isNotBlank) // remove nulls or empty strings
Copy link
Member

Choose a reason for hiding this comment

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

this does not filter out string Unknown user while IMO should

Copy link
Author

Choose a reason for hiding this comment

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

<f:checkbox/>
</f:entry>

<f:entry title="Mention Only When Build Has Failed" field="mentionOnFailure">
Copy link
Member

Choose a reason for hiding this comment

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

or is unstable - at least this is how I understand the code above

Copy link
Author

Choose a reason for hiding this comment

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

done

}

public static String mentionUserOrEmail(User user) {
if (user == null) {
Copy link
Member

Choose a reason for hiding this comment

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

when this condition is met on runtime?

Copy link
Author

@AmmarOFA AmmarOFA Jan 13, 2026

Choose a reason for hiding this comment

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

You're right, double checked that getCulprits() never returns null Users based on Jenkins core behavior. Removed the null check from TeamsMentionUtils.mentionUserOrEmail() since it's only used on the list produced by getCulprits. Test functionality for this null check has been removed as well. If you think re-implementing it differently is of use, please let me know.

<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>display-url-api</artifactId>
</dependency>
<dependency>
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Author

@AmmarOFA AmmarOFA Jan 18, 2026

Choose a reason for hiding this comment

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

I was wondering what that was. I couldn't (and still can't) see the security issue provided by snyk. But Good point. Mailer is not strictly required for this plugin. I can remove the hard dependency and switch to runtime detection so mentions use email when Mailer is present, and fall back to usernames otherwise. Would that work?

Copy link
Author

Choose a reason for hiding this comment

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

Okay, surprised that work haha, I've set mailer to a test dependency now. Fallback behaviour will default if the mailer isn't there, but I needed to test integration. Looks good!

@AmmarOFA AmmarOFA changed the title Mention Committers/Developers On Build Failure Mention Committers On Build Failure Jan 18, 2026
Ammar Zain added 24 commits February 9, 2026 23:24
… so the users with extracted emails are tagged
@AmmarOFA
Copy link
Author

Noticed the build was failing because of a banned import (commons.lang.StringUtils), specified lang3 in TeamsMentionUtils to be consistent with what we use in factsbuilder.java

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.

3 participants