├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── entrypoint.sh ├── notify_irc.py └── requirements.txt /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.4-alpine3.10 2 | 3 | COPY requirements.txt /tmp 4 | RUN pip install -r /tmp/requirements.txt 5 | 6 | COPY entrypoint.sh notify_irc.py / 7 | 8 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Andrew Wason 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Send Notification Message to IRC 2 | 3 | ### Usage 4 | 5 | See [action.yml](./action.yml) For comprehensive list of options. 6 | 7 | Example, send notifications to Libera Chat IRC channel: 8 | 9 | ```yaml 10 | name: "Push Notification" 11 | on: [push, pull_request, create] 12 | 13 | jobs: 14 | test: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: irc push 18 | uses: rectalogic/notify-irc@v1 19 | if: github.event_name == 'push' 20 | with: 21 | channel: "#mychannel" 22 | server: "irc.libera.chat" 23 | nickname: my-github-notifier 24 | message: | 25 | ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }} 26 | ${{ join(github.event.commits.*.message) }} 27 | - name: irc pull request 28 | uses: rectalogic/notify-irc@v1 29 | if: github.event_name == 'pull_request' 30 | with: 31 | channel: "#mychannel" 32 | server: "irc.libera.chat" 33 | nickname: my-github-notifier 34 | message: | 35 | ${{ github.actor }} opened PR ${{ github.event.pull_request.html_url }} 36 | - name: irc tag created 37 | uses: rectalogic/notify-irc@v1 38 | if: github.event_name == 'create' && github.event.ref_type == 'tag' 39 | with: 40 | channel: "#mychannel" 41 | server: "irc.libera.chat" 42 | nickname: my-github-notifier 43 | message: | 44 | ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }} 45 | ``` 46 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Notify IRC' 2 | description: 'Send a notification message to an IRC channel' 3 | author: 'Andrew Wason' 4 | inputs: 5 | server: 6 | description: 'IRC server' 7 | default: 'irc.libera.chat' 8 | required: true 9 | port: 10 | description: 'IRC server port' 11 | default: 6697 12 | required: true 13 | password: 14 | description: 'IRC server password' 15 | required: false 16 | channel: 17 | description: 'IRC channel to message' 18 | required: true 19 | channel_key: 20 | description: 'IRC channel password' 21 | required: false 22 | nickname: 23 | description: 'IRC user nickname' 24 | required: true 25 | sasl_password: 26 | description: 'IRC user SASL password' 27 | required: false 28 | message: 29 | description: 'Message to send' 30 | required: true 31 | notice: 32 | description: 'Use NOTICE instead of PRIVMSG' 33 | default: false 34 | required: false 35 | tls: 36 | description: 'Connect to server using TLS' 37 | default: true 38 | required: false 39 | verbose: 40 | description: 'Enable verbose logging' 41 | default: false 42 | required: false 43 | runs: 44 | using: 'docker' 45 | image: 'Dockerfile' 46 | branding: 47 | icon: 'message-square' 48 | color: 'yellow' 49 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 0 ]; then 4 | exec /notify_irc.py "$@" 5 | fi 6 | 7 | if [ "$INPUT_TLS" == "true" ]; then 8 | ARG_TLS="--tls" 9 | else 10 | ARG_TLS="" 11 | fi 12 | if [ "$INPUT_NOTICE" == "true" ]; then 13 | ARG_NOTICE="--notice" 14 | else 15 | ARG_NOTICE="" 16 | fi 17 | if [ "$INPUT_VERBOSE" == "true" ]; then 18 | ARG_VERBOSE="--verbose" 19 | else 20 | ARG_VERBOSE="" 21 | fi 22 | 23 | exec /notify_irc.py \ 24 | --server "$INPUT_SERVER" \ 25 | --password "$INPUT_PASSWORD" \ 26 | --port "$INPUT_PORT" \ 27 | --nickname "$INPUT_NICKNAME" \ 28 | --sasl-password "$INPUT_SASL_PASSWORD" \ 29 | --channel "$INPUT_CHANNEL" \ 30 | --channel-key "$INPUT_CHANNEL_KEY" \ 31 | --message "$INPUT_MESSAGE" \ 32 | $ARG_TLS $ARG_NOTICE $ARG_VERBOSE 33 | -------------------------------------------------------------------------------- /notify_irc.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import argparse 5 | import logging 6 | 7 | import pydle 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | 12 | class NotifyIRC(pydle.Client): 13 | def __init__(self, channel, channel_key, notification, use_notice=False, **kwargs): 14 | super().__init__(**kwargs) 15 | self.channel = channel if channel.startswith("#") else f"#{channel}" 16 | self.channel_key = channel_key 17 | self.notification = notification 18 | self.use_notice = use_notice 19 | self.future = None 20 | 21 | async def on_connect(self): 22 | await super().on_connect() 23 | if self.use_notice: 24 | await self.notice(self.channel, self.notification) 25 | # Need to issue a command and await the response before we quit, 26 | # otherwise we are disconnected before the notice is processed 27 | self.future = self.eventloop.create_future() 28 | await self.rawmsg("VERSION") 29 | await self.future 30 | await self.quit() 31 | else: 32 | await self.join(self.channel, self.channel_key) 33 | 34 | async def on_join(self, channel, user): 35 | await super().on_join(channel, user) 36 | if user != self.nickname: 37 | return 38 | await self.message(self.channel, self.notification) 39 | await self.part(self.channel) 40 | 41 | async def on_part(self, channel, user, message=None): 42 | await super().on_part(channel, user, message) 43 | await self.quit() 44 | 45 | async def on_raw_351(self, message): 46 | """VERSION response""" 47 | if self.future: 48 | self.future.set_result(None) 49 | 50 | 51 | def get_args(): 52 | parser = argparse.ArgumentParser() 53 | parser.add_argument("--server", default="irc.libera.chat") 54 | parser.add_argument("-p", "--port", default=6667, type=int) 55 | parser.add_argument("--password", default=None, help="Optional server password") 56 | parser.add_argument("--nickname", default="github-notify") 57 | parser.add_argument( 58 | "--sasl-password", help="Nickname password for SASL authentication" 59 | ) 60 | parser.add_argument("--channel", required=True, help="IRC #channel") 61 | parser.add_argument("--channel-key", help="IRC #channel password") 62 | parser.add_argument("--tls", action="store_true") 63 | parser.add_argument( 64 | "--notice", action="store_true", help="Use NOTICE instead of PRIVMSG" 65 | ) 66 | parser.add_argument("--message", required=True) 67 | parser.add_argument("--verbose", action="store_true") 68 | return parser.parse_args() 69 | 70 | 71 | def main(): 72 | args = get_args() 73 | logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARNING) 74 | 75 | client = NotifyIRC( 76 | channel=args.channel, 77 | channel_key=args.channel_key or None, 78 | notification=args.message, 79 | use_notice=args.notice, 80 | nickname=args.nickname, 81 | sasl_username=args.nickname, 82 | sasl_password=args.sasl_password or None, 83 | ) 84 | client.run( 85 | hostname=args.server, 86 | port=args.port, 87 | password=args.password or None, 88 | tls=args.tls, 89 | # https://github.com/Shizmob/pydle/pull/84 90 | # tls_verify=args.tls, 91 | ) 92 | 93 | 94 | if __name__ == "__main__": 95 | main() 96 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pure-sasl==0.6.1 2 | pydle==0.9.2 3 | --------------------------------------------------------------------------------