Skip to content

Repository files navigation

MattermostKit

MattermostKit Logo

CIVersionLicensePlatformSwiftDependencies

Swift package for sending messages to Mattermost via Incoming Webhooks with full support for Slack-compatible attachments and Mattermost-specific features.

Also check out SlackKit - A companion package for sending messages to Slack with full Block Kit support.

Features

  • Modern Result Builder API - Declarative DSL for building messages with attachments
  • Type-Safe - Full Codable support with compile-time safety
  • Attachments - Slack-compatible attachment support for rich messages
  • Mattermost-Specific - Support for props.card and message priority
  • Conditional Logic - Native if/else and for-in support in builders
  • Swift 6 - Built with Swift 6, async/await, and strict concurrency

Requirements

  • macOS 12.0+
  • iOS 15.0+
  • tvOS 15.0+
  • watchOS 8.0+
  • Swift 6.0+

Installation

Swift Package Manager

Add MattermostKit to your Package.swift file:

dependencies:[.package(url:"https://github.com/diegotl/MattermostKit.git", from:"1.0.0")]

Or add it directly in Xcode:

  1. File → Add Package Dependencies
  2. Enter the repository URL
  3. Select the version rule

Quick Start

import MattermostKit
// Create a webhook client
letclient=tryMattermostWebhookClient.create(
webhookURLString:"https://mattermost.server.com/hooks/YOUR/WEBHOOK/URL")
// Send a simple message
tryawait client.send(Message(text:"Hello, Mattermost!"))

Result Builder API

Simple Message

letmessage=Message(text:"Deployment completed successfully!")tryawait client.send(message)

Message with Attachments

letmessage=Message(
text:"Deployment complete!",
username:"DeployBot",
iconEmoji:":rocket:"){Attachment(color:"#36a64f", title:"Build #123", text:"Succeeded in 5m 32s"){Field("Branch", value:"main")Field("Commit", value:"abc123")Field("Duration", value:"5m 32s")Field("Status", value:":white_check_mark: Success")}}tryawait client.send(message)

Multiple Attachments

letmessage=Message(
text:"Deployment Summary",
username:"DeployBot",
iconEmoji:":rocket:"){Attachment(color:"#36a64f", title:"Success"){Field("Environment", value:"production")Field("Duration", value:"5m 32s")}Attachment(color:"#36a64f", title:"Build Info"){Field("Branch", value:"main")Field("Commit", value:"abc123")Field("Tests", value:"156 passed")}}

Conditional Attachments

lethasWarnings=truelethasErrors=falseletmessage=Message(username:"CIBot"){Attachment(color:"#36a64f", title:"Build Summary"){Field("Status", value:"Success")}if hasWarnings {Attachment(color:"#ffaa00", title:"Warnings"){Field("Count", value:"3")}}if hasErrors {Attachment(color:"#ff0000", title:"Errors"){Field("Count", value:"1")}}}

Message with Actions

letmessage=Message{Attachment(text:"Deploy to production?"){Field("Environment", value:"production")Field("Version", value:"v2.4.1")}Attachment.actions{Button(text:"Approve", style:"primary", url: approveURL)Button(text:"Reject", style:"danger", url: rejectURL)Button(text:"Defer", style:"default", url: deferURL)}}

Dynamic Fields with Loops

lettestResults=[("TestLogin","passed"),("TestAPI","passed"),("TestUI","failed")]letmessage=Message{Attachment(title:"Test Results"){for(name, result)in testResults {Field(name, value: result, short:true)}}}

Message with Card Props

// Simple card with static text
letmessage=Message(
text:"We won a new deal!",
props:Props(card:""" Salesforce Opportunity Information: **Amount:** $300,020.00 **Close Date:** 2025-01-15 **Sales Rep:** John Doe"""))
// Card with dynamic properties using builder
letmessage=Message(
text:"Deal updated!",
props:Props(card:"Deal Information"){Property("amount", value:300020)Property("stage", value:"Proposal")Property("is_closed", value:false)})
// Conditional properties
letincludeDetails=trueletmessage=Message(
text:"Opportunity created",
props:Props(card:"Sales Info"){Property("opportunity_id", value:"12345")Property("account", value:"Acme Corp")if includeDetails {Property("estimated_value", value:50000)Property("probability", value:0.75)}})

Message with Priority

// Urgent priority with acknowledgment
letmessage=Message(
text:"Critical incident!",
priority:Priority(
priority:.urgent,
requestedAck:true,
persistentNotifications:true))
// Important priority
letmessage=Message(
text:"Important announcement",
priority:Priority(priority:.important))

Confirmation Dialogs for Actions

// Simple confirmation
letconfirm=Confirmation(
title:"Are you sure?",
text:"This will deploy to production",
confirmText:"Deploy",
denyText:"Cancel")
// Using result builder for custom buttons
letconfirm=Confirmation(
title:"Confirm Deployment",
text:"This action cannot be undone"){ConfirmButton(text:"Yes, Deploy", style:"primary")DenyButton(text:"No, Cancel")}letmessage=Message{Attachment.actions{Button(text:"Deploy", style:"primary", url: deployURL, confirm: confirm)Button(text:"Cancel", style:"danger", url: cancelURL)}}

Complex Message with All Features

letmessage=Message(
username:"CI/CD Bot",
iconURL:"https://example.com/ci-icon.png",
text:"Build notification"){Attachment(
color:"#36a64f",
title:"Build #123",
pretext:"Build process completed",
authorName:"Jenkins",
authorLink:"https://jenkins.example.com",
authorIcon:"https://example.com/jenkins-icon.png",
titleLink:"https://jenkins.example.com/job/123",
imageURL:"https://example.com/build-graph.png",
thumbURL:"https://example.com/thumb.png",
footer:"Jenkins CI",
footerIcon:"https://example.com/jenkins.png"){Field("Branch", value:"feature/new-api", short:true)Field("Commit", value:"a1b2c3d", short:true)Field("Duration", value:"5m 32s", short:true)Field("Tests", value:"156 passed", short:true)}}

Confirmation Dialogs for Actions

letconfirm=Confirmation(
title:"Are you sure?",
text:"This will deploy to production",
confirmText:"Deploy",
denyText:"Cancel")letmessage=Message{Attachment.actions{Button(text:"Deploy", style:"primary", url: deployURL, confirm: confirm)Button(text:"Cancel", style:"danger", url: cancelURL)}}

Builder API Reference

Message Builder

Message(
text:"Message text",
username:"Bot Name",
iconEmoji:":robot_face:"){
// Attachments via @AttachmentBuilder
Attachment(title:"Title"){...}}

Attachment Builder

Attachment(
color:"#36a64f",
title:"Title",
text:"Description"){
// Fields via @FieldBuilder
Field("Key", value:"Value")}

Actions Builder

Attachment.actions{
// Actions via @ActionBuilder
Button(text:"Click", url: url)}

Props Builder

Props(card:"Card content"){
// Properties via @PropsBuilder
Property("key", value:"value")Property("number", value:42)}

Confirmation Builder

Confirmation(
title:"Confirm?",
text:"Are you sure?"){
// Components via @ConfirmationBuilder
ConfirmButton(text:"Yes", style:"primary")DenyButton(text:"No")}

Convenience Functions

// Field with short=true by default
Field("Branch", value:"main")
// Button action
Button(text:"Approve", style:"primary", url:"https://example.com")
// Properties (various types)
Property("name", value:"text")Property("count", value:42)Property("enabled", value:true)Property("metadata", value:["key":.string("value")])
// Confirmation components
ConfirmButton(text:"Yes", style:"primary")DenyButton(text:"No")
// Actions-only attachment
Attachment.actions{Button(text:"View", url: viewURL)Button(text:"Dismiss", style:"danger", url: dismissURL)}

Error Handling

do{tryawait client.send(message)}catchMattermostError.invalidURL(let url){print("Invalid URL: \(url)")}catchMattermostError.invalidResponse(let code,let body){print("HTTP \(code): \(body ??"No body")")}catchMattermostError.encodingError(let error){print("Failed to encode message: \(error)")}catchMattermostError.networkError(let error){print("Network error: \(error)")}

API Reference

Message

publicstructMessage:Sendable,Codable{publicvartext:String? // Markdown-formatted message
publicvarchannel:String? // Override default channel
publicvarusername:String? // Override bot username
publicvariconEmoji:String? // e.g., ":rocket:"
publicvariconURL:String? // Override bot icon with image URL
publicvarattachments:[Attachment]? // Message attachments
publicvarprops:Props? // Mattermost metadata
publicvartype:String? // Post type (must begin with "custom_")
publicvarpriority:Priority? // Message priority
}

Attachment

publicstructAttachment:Sendable,Codable{publicvarfallback:String? // Plain-text summary
publicvarcolor:String? // Hex color code
publicvarpretext:String? // Text above attachment
publicvarauthorName:String? // Author name
publicvarauthorLink:String? // Author link
publicvarauthorIcon:String? // Author icon URL
publicvartitle:String? // Attachment title
publicvartitleLink:String? // Title link
publicvartext:String? // Attachment text (Markdown)
publicvarfields:[AttachmentField]? // Attachment fields
publicvarimageURL:String? // Image URL
publicvarthumbURL:String? // Thumbnail URL
publicvarfooter:String? // Footer text
publicvarfooterIcon:String? // Footer icon URL
publicvaractions:[Action]? // Interactive buttons
}

Props (Mattermost-Specific)

publicstructProps:Sendable,Codable{publicvarcard:String? // RHS sidebar content
publicvaradditionalProperties:[String:AnyCodable]?}

Priority (Mattermost-Specific)

publicstructPriority:Sendable,Codable{publicenumLevel:String,Codable{case important // Important message
case urgent // Urgent message
}publicvarpriority:Level // Priority level
publicvarrequestedAck:Bool? // Request acknowledgment
publicvarpersistentNotifications:Bool? // Persistent notifications
}

Differences from Slack

FeatureSlackKitMattermostKit
Block Kit✅ Full support❌ NOT supported
Message Threadingthread_ts❌ Not available
Attachments✅ Slack formatSlack-compatible
Custom Metadata❌ Noprops.card
Message Priority❌ Nopriority

Note: MattermostKit does NOT support Slack's Block Kit. Use Markdown formatting in the text field and attachments for rich messages.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Resources

About

Modern Swift package for Mattermost Incoming Webhooks with attachments, props.card, and message priority support

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages