Today I show you how you can send notifications to Mattermost with PHP and Github Actions. There are some implementations on Github Marketplace but nothing was made with PHP, there was Javascript, Go, or Python. But PHP can be used to create command-line utilities and it’s very easy. Don’t trust me? Come I’ll show you.
Photo by Daria Nepriakhina πΊπ¦ on Unsplash
Creating new project
First of all, create a new folder for your project, mine is action-mattermost-notify. You can do this with the command as follows.
1mkdir action-mattermost-notify
Now initializae new repository
1# cd action-mattermost-notify
2composer init
The composer will ask you for some information such as project name, author name, and email. When you are done you will have a folder structure like this one:
1action-mattermost-notify
2βββ composer.json
3βββ composer.lock
4βββ src
5βββ vendor
Now You need to add some dependencies. (Here are two of them). The first one is the HTTP client and the second one is Console.
1# cd action-mattermost-notify
2composer require symfony/http-client
3composer require symfony/console
After this step, 1st part is done. Go to next step.
Creating Console application
With the Console component is creating a new console application easy. When you finish this part your folder structure will look like follows
1action-mattermost-notify
2βββ app.php # Added this one
3βββ composer.json
4βββ composer.lock
5βββ src
6βΒ Β βββ SendCommand.php # Added this one
7βββ vendor
First create app.php, which is the main file that launches your console application, and put there following content.
1# app.php
2require __DIR__ . '/vendor/autoload.php';
3
4use Symfony\Component\Console\Application;
5
6# Load version information from the composer file
7# You will need to add a version tag to your composer.json
8$version = json_decode(file_get_contents(__DIR__ . '/composer.json'), true);
9
10$app = new Application('Action Mattermost Notify', $version['version']);
11
12$app->run();
Good job! Now try to run it
1php app.php
1Action Mattermost Notify 1.0.0
2
3Usage:
4 command [options] [arguments]
5
6Options:
7 -h, --help Display help for the given command. When no command is given display help for the list command
8 -q, --quiet Do not output any message
9 -V, --version Display this application version
10 --ansi|--no-ansi Force (or disable --no-ansi) ANSI output
11 -n, --no-interaction Do not ask any interactive question
12 -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
13
14Available commands:
15 completion Dump the shell completion script
16 help Display help for a command
17 list List commands
Next, you need to create a new command that will communicate with Mattermost. Go into the src folder and create SendCommand.php
1# cd src
2touch SendCommand.php
…and put there following content
1<?php
2declare(strict_types=1);
3
4# Change namespace to your project's namespace
5namespace Maymeow\ActionMattermostNotify;
6
7use Symfony\Component\Console\Command\Command;
8use Symfony\Component\Console\Input\InputArgument;
9use Symfony\Component\Console\Input\InputInterface;
10use Symfony\Component\Console\Input\InputOption;
11use Symfony\Component\Console\Output\OutputInterface;
12use Symfony\Component\HttpClient\HttpClient;
13
14class SendCommand extends Command
15{
16 protected static $defaultName = 'send';
17
18 /**
19 * Configure method
20 *
21 * @return void
22 */
23 public function configure(): void
24 {
25 $this
26 ->setDescription('Send a message to Mattermost')
27 ->setHelp('This command allows you to send a message to Mattermost');
28
29 $this
30 ->addArgument('message', InputArgument::REQUIRED, 'The message to send')
31 ->addOption('channel', null, InputOption::VALUE_OPTIONAL, 'The channel to send the message to')
32 ->addOption('username', null, InputOption::VALUE_OPTIONAL, 'The username to send the message as')
33 ->addOption('icon', null, InputOption::VALUE_OPTIONAL, 'The icon to send the message with')
34 ->addOption('url', null, InputOption::VALUE_OPTIONAL, 'The URL to send the message with');
35 }
36
37 /**
38 * Execute method
39 *
40 * @param \Symfony\Component\Console\Input\InputInterface $input Input interface
41 * @param \Symfony\Component\Console\Output\OutputInterface $output Output interface
42 * @return int
43 */
44 public function execute(InputInterface $input, OutputInterface $output): int
45 {
46 $message = $input->getArgument('message');
47 $channel = $input->getOption('channel');
48 $username = $input->getOption('username');
49 $icon = $input->getOption('icon');
50 $url = $input->getOption('url');
51
52 $client = HttpClient::create();
53
54 $response = $client->request('POST', $url, [
55 'body' => json_encode([
56 'channel' => $channel,
57 'text' => $message,
58 'username' => $username,
59 'icon_url' => $icon,
60 ]),
61 'headers' => [
62 'Content-Type' => 'application/json',
63 ],
64 ]);
65
66 $output->writeln($response->getContent());
67
68 return Command::SUCCESS;
69 }
70}
Let me show you what are parts of this file doing
1public function configure(): void
The function above, as the name says, is used to configure your command. It tells your application what argument or options this command needs, its name, and description or you can modify the handler (how you call it from command line).
1public function execute(InputInterface $input, OutputInterface $output): int
Function execute is the one where all magic happens. It is used to execute your actions.
The part below is HTTP Client that calls your webhook with the POST method and sends there required information.
1// SendCommand::execute()
2//...
3$client = HttpClient::create();
4$response = $client->request('POST', $url, [
5 'body' => json_encode([
6 'channel' => $channel,
7 'text' => $message,
8 'username' => $username,
9 'icon_url' => $icon,
10 ]),
11 'headers' => [
12 'Content-Type' => 'application/json',
13 ],
14]);
15// ...
Ok, Now register your Command to your application with $app->add(new SendCommand());. Add this to your app.php file. After this step, your file will look like this one
1<?php
2
3require __DIR__ . '/vendor/autoload.php';
4
5use Maymeow\ActionMattermostNotify\SendCommand;
6use Symfony\Component\Console\Application;
7
8$c = json_decode(file_get_contents(__DIR__ . '/composer.json'), true);
9
10$app = new Application('Action Mattermost Notify', $c['version']);
11
12$app->add(new SendCommand());
13
14$app->run();
Try to run your app again php app.php. In your response another action has been added:
1Action Mattermost Notify 1.0.0
2# // ...
3Available commands:
4 completion Dump the shell completion script
5 help Display help for a command
6 list List commands # <--- This one as beed added
To see information about any command append --help behind that command. For example send command
1php app.php send --help
Required are the message and url of your webhook.
You can obtain the webhook URL on your mattermost instance in integrations, then click on Incoming webhook then add new and provide requested information.
Sending message
When you have all you need (created webhook), you can send a meesage to the server as follows
1php app.php send "Hello World from PHP commandline!" --url "https://your-mattermost.url/webhook-id"
Cool isn’t it? But, I like it if I can call the application without php word as follows
1`./action-mattermost-notify send "Hello World from PHP commandline!" --url "https://your-mattermost.url/webhook-id"`
Ok, Let’s do this.
Packing your application to single file
In this step, you will learn how to pack your PHP application into phar. You have 2 options, read the PHP manual and do it your way, or IMO a more elegant way to use phar-composer.
First of all, you need to install it.
1wget https://github.com/clue/phar-composer/releases/download/v1.4.0/phar-composer-1.4.0.phar \
2&& chmod +x phar-composer-1.4.0.phar \
3&& mv phar-composer-1.4.0.phar /usr/local/bin/phar-composer
To check the current version go to the releases page.
Before you can pack your app you need to make small changes in your composer file. Add "bin": ["app.php"], somewhere in composer file. This tells to phar-composer which file needs to call when execute.
Ok build it and make it executable.
1phar-composer build
2chmod +x action-mattermost-notify.phar
After this you can call it like follows
1./action-mattermost-notify.phar
Ok, the console application is finished and now you can create a GitHub action
Creating Action
The folder structure after this part is finished will look like follows
1action-mattermost-notify
2βββ action.yml # Added this one
3βββ app.php
4βββ composer.json
5βββ composer.lock
6βββ Dockerfile # Added this one
7βββ entrypoint.sh # Added this one
8βββ src
9βΒ Β βββ SendCommand.php
10βββ vendor
First of all, you need to automate the steps above like building phar and making it executable. You don’t want to have bin files in your git repository. To do this, we use Docker in this tutorial. Create Dockerfile and put there following content:
1# Dockerfile
2# Folloing image has composer-phar preinstaled in it
3FROM ghcr.io/maymeow/php-ci-cd/php-ci-cd:8.1.6-cs-git-psalm AS build-env
4
5WORKDIR /app
6
7COPY . /app
8
9RUN composer install --no-ansi --no-dev --no-interaction --no-plugins --no-progress --optimize-autoloader --no-scripts
10
11RUN phar-composer build && chmod +x action-mattermost-notify.phar
12
13# Use smallest php image
14FROM php:8.1.6-cli-alpine
15
16COPY --from=build-env /app/action-mattermost-notify.phar /usr/local/bin/action-mattermost-notify
17
18COPY --from=build-env /app/entrypoint.sh /entrypoint.sh
19
20RUN action-mattermost-notify list
21
22ENTRYPOINT ["/entrypoint.sh"]
The example above is a multistep build. In the production image, you will only have phar without source codes.
The second file you need to add is entrypoint.sh which runs when the image starts. Create it with the following content
1#entrypoint.sh
2#!/bin/sh
3
4action-mattermost-notify send "$1" --url "$2" --channel "$3" --username "$5" --icon "$4"
At last, you need to create an action configuration file that tells Github all the required information about the action that you creating. It is called action.yml and has to be in the root directory. Create it with the following content:
1# action.yml
2name: 'Action Name' #change this to your action name
3author: 'Action Author' # Change this to your
4description: 'Action Description' # change this
5branding:
6 icon: 'command'
7 color: 'purple'
8inputs: # following are all inputs that can be used in this action
9 message:
10 description: 'Enter the message to send to Mattermost'
11 required: true
12 url:
13 description: 'The URL to send the message to'
14 required: true
15 channel:
16 description: 'Enter the channel to send the message to'
17 required: false
18 icon:
19 description: 'Enter the icon to use for the message'
20 required: false
21 username:
22 description: 'Enter the username to use for the message'
23 required: false
24runs: # How this action start?
25 using: 'docker'
26 image: 'Dockerfile'
27 args:
28 - ${{ inputs.message }}
29 - ${{ inputs.url }}
30 - ${{ inputs.channel }}
31 - ${{ inputs.icon }}
32 - ${{ inputs.username }}
Good job! Congratulation, You are reading this to the finish. You now have your own Github action and you learned how to
- create a PHP console application
- how to pack it in a single Phar file
- how to create Github Action with PHP
How to run it
At the very end, ill show you how you can use it. There are more options on how to call it.
- Register it in the marketplace (via new release)
- Call it with branch name or commit hash
If you have published it you can call it as follows
1- name: Action Mattermost Notify
2uses: MayMeow/action-mattermost-notify@v1 # Change this to your action
3with:
4 url: ${{ secrets.MATTERMOST_WEBHOOK }}
5 message: "Hello world from ${{ github.repository }}"
Your action has name your-github-username/your-action-repository@version or your-github-username/your-action-repository@branch-name or your-github-username/your-action-repository@commit-hash. The last two options don’t require to have action registered in the marketplace.
In the end
All source code is available on my Github: Action Mattermost notify and Mattermost Action example.
Thank you for reading this post and I hope you enjoy it.
- GitHub: https://github.com/MayMeow
- DEV: https://dev.to/maymeow
- Hashnode: https://hashnode.com/@maymeow
- Ko-fi: https://ko-fi.com/maymeow
Originally published at My Blog