pax_global_header00006660000000000000000000000064125262472220014516gustar00rootroot0000000000000052 comment=005944b0a05be222e1e01dee1a53f8b1f4d1f444 slack-notifier-1.2.1/000077500000000000000000000000001252624722200144315ustar00rootroot00000000000000slack-notifier-1.2.1/.editorconfig000066400000000000000000000003541252624722200171100ustar00rootroot00000000000000; EditorConfig is awesome: http://EditorConfig.org root = true ; top-most EditorConfig file ; Unix-style newlines with a newline ending every file [*] end_of_line = lf indent_style = space indent_size = 2 insert_final_newline = true slack-notifier-1.2.1/.env-example000066400000000000000000000000501252624722200166460ustar00rootroot00000000000000SLACK_WEBHOOK_URL: "https://example.com"slack-notifier-1.2.1/.gitignore000066400000000000000000000001141252624722200164150ustar00rootroot00000000000000.DS_Store Gemfile.lock .rvmrc .ruby-version .ruby-gemset .env *.gem coverageslack-notifier-1.2.1/.rspec000066400000000000000000000000401252624722200155400ustar00rootroot00000000000000--color --format 'documentation'slack-notifier-1.2.1/.travis.yml000066400000000000000000000006421252624722200165440ustar00rootroot00000000000000language: ruby sudo: false cache: bundler bundler_args: "--without development" rvm: - 2.2 - 2.1 - 2.0 - 1.9.3 - jruby-19mode - rbx-2.2.7 matrix: allow_failures: - rvm: jruby-19mode - rvm: rbx-2.2.7 notifications: slack: secure: Ld0tGBmwLG/ADOlLjO6ILq98+u/iq5qkuxAwN1E0SBOooALZZEJSc74jEMpgpnb22tk8QimUmLiCTE+8tWKaGiXTrvK6uvvfP6iiL9850NezHCxA3YMuWPnQQtJpTJ4135MMO8gJXu9vcswb9vW9N3v/A7VJdHbVZyT0vIMGas0= slack-notifier-1.2.1/Gemfile000066400000000000000000000003731252624722200157270ustar00rootroot00000000000000source 'https://rubygems.org' gemspec group :development do if RUBY_VERSION >= '2.0.0' gem 'pry-byebug' else gem 'pry-debugger' end gem 'wwtd' gem 'travis' end group :test do gem 'rake', '~> 10.1' gem 'rspec', '~> 3.0.0' end slack-notifier-1.2.1/LICENSE000066400000000000000000000020671252624722200154430ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Steven Sloan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. slack-notifier-1.2.1/Rakefile000066400000000000000000000001311252624722200160710ustar00rootroot00000000000000require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task :default => :spec slack-notifier-1.2.1/bin/000077500000000000000000000000001252624722200152015ustar00rootroot00000000000000slack-notifier-1.2.1/bin/test000077500000000000000000000007601252624722200161110ustar00rootroot00000000000000#!/usr/bin/env ruby require 'yaml' YAML.load_file('.env').each do |key,var| ENV[key] = var end rubies = YAML.load_file('.travis.yml')['rvm'] rubies.each do |ruby| # cleanup gemfile.locks Dir[ 'spec*/**/*.lock' ].each do |lockfile| puts "removing #{lockfile}" system "rm #{lockfile}" end pid = Process.fork do exec "rvm #{ruby} do ruby spec/integration/ping_integration_test.rb" end trap "INT" do puts "exiting" pid.send(:exit) end Process.wait(pid) endslack-notifier-1.2.1/changelog.md000066400000000000000000000036721252624722200167120ustar00rootroot00000000000000# 1.2.1 - use `#scrub` to (more selectively) strip invalid characters from strings before attempting to format. This allows valid japanese (and more) characters to be used. Thanks to @fukayatsu for reporting. This checks for the presence of the `scrub` method on string, so if on ruby < 2.1 you'll need to include & require the `string-scrub` gem to handle invalid characters. # 1.2.0 - Strip invalid UTF-8 characters from message before attempting to format links. They are replaced with the unicode replacement character '[�](http://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character)'. [@ushu #26] # 1.1.0 - add ability to pass `:http_options` to the initializer or `#ping`. this allows you to set options like `read_timeout` or `open_timeout`. See [issue #17](https://github.com/stevenosloan/slack-notifier/issues/17) for more information. # 1.0.0 - [BREAKING!] To follow changes with slack, client is now initialized with a webhook url instead of team & token. For help upgrading read the [upgrade from 0.6.1 guide](docs/upgrade-from-0.6.1.md) # 0.6.1 - fix bug in link_formatter to allow multiple links in a message # 0.6.0 - add ability to pass in your own http client - [BREAKING!] hook name moves to options array # 0.5.0 - allow defaults to be set on initialization - remove channel formatting [#8] # 0.4.1 - allow default channel's to start with a "@" or "#" [#7] # 0.4.0 - try and correct for a channel name being set without a leading "#" [@dlackty] # 0.3.2 - add Net::HTTP wrapper to include support for ruby 1.9.3 # 0.3.1 - remove requirement for channel, no longer required by slack [@dlackty] # 0.3.0 - add custom hook endpoint parameter [@razielgn] # 0.2.0 - remove HTTParty dependency # 0.1.1 - loosen httparty dependency - refactor codebase & add specs # 0.1.0 - now formats html or markdown links in your message to match slack's format # 0.0.2 - fix a fat finger if a default channel is set # 0.0.1 - initial release slack-notifier-1.2.1/docs/000077500000000000000000000000001252624722200153615ustar00rootroot00000000000000slack-notifier-1.2.1/docs/upgrade-from-0.6.1.md000066400000000000000000000014761252624722200207430ustar00rootroot00000000000000Recently slack changed the way incoming webhooks are handled. Instead of taking a team name and token, they now provide a unique (obfuscated) webhook url. To upgrade the slack-notifier gem, you'll need to find your webhook url. In slack: - go to you're configured integrations (https://team-name.slack.com/services) - select **Incoming Webhooks** - select the webhook that uses the slack-notifier gem - find the webhook url under the heading **Integration Settings** You'll then change the way you initialize your notifier From: ```ruby notifier = Slack::Notifier.new 'team', 'token' ``` To: ```ruby notifier = Slack::Notifier.new 'WEBHOOK_URL' ``` Defaults & attachemnts will continue to work like they have ```ruby notifier = Slack::Notifier.new 'WEBHOOK_URL', icon_emoji: ":ghost:" notifier.ping "I'm feeling spooky" ``` slack-notifier-1.2.1/lib/000077500000000000000000000000001252624722200151775ustar00rootroot00000000000000slack-notifier-1.2.1/lib/slack-notifier.rb000066400000000000000000000022011252624722200204310ustar00rootroot00000000000000require 'net/http' require 'uri' require 'json' require_relative 'slack-notifier/default_http_client' require_relative 'slack-notifier/link_formatter' module Slack class Notifier attr_reader :endpoint, :default_payload def initialize webhook_url, options={} @endpoint = URI.parse webhook_url @default_payload = options end def ping message, options={} message = LinkFormatter.format(message) payload = default_payload.merge(options).merge(text: message) client = payload.delete(:http_client) || http_client http_options = payload.delete(:http_options) params = { payload: payload.to_json } params[:http_options] = http_options if http_options client.post endpoint, params end def http_client default_payload.fetch :http_client, DefaultHTTPClient end def channel default_payload[:channel] end def channel= channel default_payload[:channel] = channel end def username default_payload[:username] end def username= username default_payload[:username] = username end end end slack-notifier-1.2.1/lib/slack-notifier/000077500000000000000000000000001252624722200201115ustar00rootroot00000000000000slack-notifier-1.2.1/lib/slack-notifier/default_http_client.rb000066400000000000000000000020261252624722200244570ustar00rootroot00000000000000module Slack class Notifier class DefaultHTTPClient class << self def post uri, params DefaultHTTPClient.new( uri, params ).call end end attr_reader :uri, :params, :http_options def initialize uri, params @uri = uri @http_options = params.delete(:http_options) || {} @params = params end def call http_obj.request request_obj end private def request_obj req = Net::HTTP::Post.new uri.request_uri req.set_form_data params return req end def http_obj http = Net::HTTP.new uri.host, uri.port http.use_ssl = (uri.scheme == "https") http_options.each do |opt, val| if http.respond_to? "#{opt}=" http.send "#{opt}=", val else warn "Net::HTTP doesn't respond to `#{opt}=`, ignoring that option" end end return http end end end end slack-notifier-1.2.1/lib/slack-notifier/link_formatter.rb000066400000000000000000000024271252624722200234630ustar00rootroot00000000000000module Slack class Notifier class LinkFormatter class << self def format string LinkFormatter.new(string).formatted end end def initialize string @orig = if string.respond_to? :scrub string.scrub else string end end def formatted @orig.gsub( html_pattern ) do |match| link = Regexp.last_match[1] text = Regexp.last_match[2] slack_link link, text end.gsub( markdown_pattern ) do |match| link = Regexp.last_match[2] text = Regexp.last_match[1] slack_link link, text end rescue => e if RUBY_VERSION < '2.1' && e.message.include?('invalid byte sequence') raise e, "#{e.message}. Consider including the 'string-scrub' gem to strip invalid characters" else raise e end end private def slack_link link, text=nil out = "<#{link}" out << "|#{text}" if text && !text.empty? out << ">" return out end def html_pattern / (.+?) <\/a> /x end def markdown_pattern /\[(.*?)\]\((.+?)\)/ end end end end slack-notifier-1.2.1/lib/slack-notifier/version.rb000066400000000000000000000000761252624722200221260ustar00rootroot00000000000000module Slack class Notifier VERSION = "1.2.1" end end slack-notifier-1.2.1/readme.md000066400000000000000000000123321252624722200162110ustar00rootroot00000000000000A simple wrapper to send notifications to [Slack](https://slack.com/) webhooks. [![Build Status](https://travis-ci.org/stevenosloan/slack-notifier.svg?branch=master)](https://travis-ci.org/stevenosloan/slack-notifier) [![Code Climate](https://codeclimate.com/github/stevenosloan/slack-notifier.svg)](https://codeclimate.com/github/stevenosloan/slack-notifier) ## Example ```ruby require 'slack-notifier' notifier = Slack::Notifier.new "WEBHOOK_URL" notifier.ping "Hello World" # => if your webhook is setup, will message "Hello World" # => to the default channel you set in slack ``` #### Setting Defaults On initialization you can set default payloads by passing an options hash. ```ruby notifier = Slack::Notifier.new "WEBHOOK_URL", channel: '#default', username: 'notifier' notifier.ping "Hello default" # => will message "Hello default" # => to the "#default" channel as 'notifier' ``` Once a notifier has been initialized, you can update the default channel and/or user. ```ruby notifier.channel = '#default' notifier.username = 'notifier' notifier.ping "Hello default" # => will message "Hello default" # => to the "#default" channel as 'notifier' ``` These defaults are over-ridable for any individual ping. ```ruby notifier.channel = "#default" notifier.ping "Hello random", channel: "#random" # => will ping the "#random" channel ``` ## Links Slack requires links to be formatted a certain way, so slack-notifier will look through your message and attempt to convert any html or markdown links to slack's format before posting. Here's what it's doing under the covers: ```ruby message = "Hello world, [check](http://example.com) it out" Slack::Notifier::LinkFormatter.format(message) # => "Hello world, it " ``` ## Formatting Slack supports various different formatting options. For example, if you want to alert an entire channel you include `` in your message ```ruby message = " hey check this out" notifier.ping message #ends up posting "@channel hey check this out" in your Slack channel ``` You can see [Slacks message documentation here](https://api.slack.com/docs/formatting) ## Additional parameters Any key passed to the `ping` method is posted to the webhook endpoint. Check out the [Slack webhook documentation](https://my.slack.com/services/new/incoming-webhook) for the available parameters. Setting an icon: ```ruby notifier.ping "feeling spooky", icon_emoji: ":ghost:" # or notifier.ping "feeling chimpy", icon_url: "http://static.mailchimp.com/web/favicon.png" ``` Adding attachments: ```ruby a_ok_note = { fallback: "Everything looks peachy", text: "Everything looks peachy", color: "good" } notifier.ping "with an attachment", attachments: [a_ok_note] ``` ## HTTP options With the default HTTP client, you can send along options to customize it's behavior as `:http_options` params when you ping or initialize the notifier. ```ruby notifier = Slack::Notifier.new 'WEBHOOK_URL', http_options: { open_timeout: 5 } notifier.ping "hello", http_options: { open_timeout: 10 } ``` **Note**: you should only send along options that [`Net::HTTP`](http://ruby-doc.org/stdlib-2.2.0/libdoc/net/http/rdoc/Net/HTTP.html) has as setters, otherwise the option will be ignored and show a warning. ## Custom HTTP Client There is a packaged default client wrapping Net::HTTP, but your HTTP needs might be a little different. In that case, you can pass in your own wrapper to handle sending the notifications. It just needs to respond to `::post` with the arguments of the endpoint URI, and the payload [pretty much the same as Net:HTTP.post_form](http://ruby-doc.org/stdlib-2.1.2/libdoc/net/http/rdoc/Net/HTTP.html#method-c-post_form). A simple example: ```ruby module Client def self.post uri, params={} Net::HTTP.post_form uri, params end end notifier = Slack::Notifier.new 'WEBHOOK_URL', http_client: Client ``` It's also encouraged for any custom HTTP implementations to accept the `:http_options` key in params. **Setting client per ping** You can also set the http_client per-ping if you need to special case certain pings. ```ruby notifier.ping "hello", http_client: CustomClient ``` **Setting a No-Op client** In development (or testing), you may want to watch the behavior of the notifier without posting to slack. This can be handled with a no-op client. ```ruby class NoOpHTTPClient def self.post uri, params={} # bonus, you could log or observe posted params here end end notifier = Slack::Notifier.new 'WEBHOOK_URL', http_client: NoOpHTTPClient ``` Testing ------- ```bash $ rspec ``` There is also an integration test setup to just double check pinging across the supported rubies. To run: 1. Copy the `.env-example` file to `.env` and replace with your details. 2. Make sure `bin/test` is executable 3. then run and watch for the pings in your slack room ```bash $ bin/test ``` Contributing ------------ If there is any thing you'd like to contribute or fix, please: - Fork the repo - Add tests for any new functionality - Make your changes - Verify all new &existing tests pass - Make a pull request License ------- The slack-notifier gem is distributed under the MIT License. slack-notifier-1.2.1/slack-notifier.gemspec000066400000000000000000000012271252624722200207120ustar00rootroot00000000000000require File.expand_path( "../lib/slack-notifier/version", __FILE__ ) Gem::Specification.new do |s| s.name = 'slack-notifier' s.version = Slack::Notifier::VERSION s.platform = Gem::Platform::RUBY s.summary = 'A slim ruby wrapper for posting to slack webhooks' s.description = %q{ A slim ruby wrapper for posting to slack webhooks } s.authors = ["Steven Sloan"] s.email = ["stevenosloan@gmail.com"] s.homepage = "http://github.com/stevenosloan/slack-notifier" s.license = 'MIT' s.files = Dir["{lib}/**/*.rb"] s.test_files = Dir["spec/**/*.rb"] s.require_path = "lib" endslack-notifier-1.2.1/spec/000077500000000000000000000000001252624722200153635ustar00rootroot00000000000000slack-notifier-1.2.1/spec/integration/000077500000000000000000000000001252624722200177065ustar00rootroot00000000000000slack-notifier-1.2.1/spec/integration/ping_integration_test.rb000066400000000000000000000004231252624722200246310ustar00rootroot00000000000000# encoding: utf-8 require_relative '../../lib/slack-notifier' notifier = Slack::Notifier.new ENV['SLACK_WEBHOOK_URL'], username: 'notifier' puts "testing with ruby #{RUBY_VERSION}" notifier.ping "hello/こんにちは from notifier test script on ruby: #{RUBY_VERSION}\225" slack-notifier-1.2.1/spec/lib/000077500000000000000000000000001252624722200161315ustar00rootroot00000000000000slack-notifier-1.2.1/spec/lib/slack-notifier/000077500000000000000000000000001252624722200210435ustar00rootroot00000000000000slack-notifier-1.2.1/spec/lib/slack-notifier/default_http_client_spec.rb000066400000000000000000000022521252624722200264240ustar00rootroot00000000000000require 'spec_helper' describe Slack::Notifier::DefaultHTTPClient do describe "::post" do it "initializes DefaultHTTPClient with the given uri and params then calls" do http_post_double = instance_double("Slack::Notifier::DefaultHTTPClient") expect( described_class ).to receive(:new) .with( 'uri', 'params' ) .and_return( http_post_double ) expect( http_post_double ).to receive(:call) described_class.post 'uri', 'params' end # http_post is really tested in the integration spec, # where the internals are run through end describe "#initialize" do it "allows setting of options for Net::HTTP" do net_http_double = instance_double("Net::HTTP") http_client = described_class.new( URI.parse('http://example.com'), http_options: { open_timeout: 5 }) allow( Net::HTTP ).to receive(:new) .and_return(net_http_double) allow( net_http_double ).to receive(:use_ssl=) allow( net_http_double ).to receive(:request) expect( net_http_double ).to receive(:open_timeout=).with(5) http_client.call end end end slack-notifier-1.2.1/spec/lib/slack-notifier/link_formatter_spec.rb000066400000000000000000000044501252624722200254250ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Slack::Notifier::LinkFormatter do describe "::format" do it "formats html links" do formatted = described_class.format("Hello World, enjoy this.") expect( formatted ).to include("") end it "formats markdown links" do formatted = described_class.format("Hello World, enjoy [this](http://example.com).") expect( formatted ).to include("") end it "formats markdown links with no title" do formatted = described_class.format("Hello World, enjoy [](http://example.com).") expect( formatted ).to include("") end it "handles multiple html links" do formatted = described_class.format("Hello World, enjoy thisthis2.") expect( formatted ).to include("") expect( formatted ).to include("") end it "handles multiple markdown links" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)[this2](http://example2.com).") expect( formatted ).to include("") expect( formatted ).to include("") end it "handles mixed html & markdown links" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)this2.") expect( formatted ).to include("") expect( formatted ).to include("") end if "".respond_to? :scrub context "when on ruby 2.1+ or have string-scrub installed" do it "handles invalid unicode sequences" do expect { described_class.format("This sequence is invalid: \255") }.not_to raise_error end it "replaces invalid unicode sequences with the unicode replacement character" do formatted = described_class.format("\255") expect(formatted).to eq "\uFFFD" end end end it "doesn't replace valid Japanese" do formatted = described_class.format("こんにちは") expect(formatted).to eq "こんにちは" end end end slack-notifier-1.2.1/spec/lib/slack-notifier_spec.rb000066400000000000000000000067531252624722200224150ustar00rootroot00000000000000require 'spec_helper' describe Slack::Notifier do subject { described_class.new 'http://example.com' } describe "#initialize" do it "sets the given hook_url to the endpoint URI" do expect( subject.endpoint ).to eq URI.parse 'http://example.com' end it "sets the default_payload options" do subject = described_class.new 'http://example.com', channel: 'foo' expect( subject.channel ).to eq 'foo' end it "sets a custom http client" do client = double("CustomClient") subject = described_class.new 'http://example.com', http_client: client expect( subject.http_client ).to eq client end end describe "#ping" do before :each do allow( Slack::Notifier::DefaultHTTPClient ).to receive(:post) end it "passes the message through LinkFormatter" do expect( Slack::Notifier::LinkFormatter ).to receive(:format) .with("the message") described_class.new('http://example.com').ping "the message", channel: 'foo' end context "with a default channel set" do before :each do @endpoint_double = instance_double "URI::HTTP" allow( URI ).to receive(:parse) .and_return(@endpoint_double) subject.channel = '#default' end it "does not require a channel to ping" do expect{ subject.ping "the message" }.not_to raise_error end it "uses default channel" do expect( Slack::Notifier::DefaultHTTPClient ).to receive(:post) .with @endpoint_double, payload: '{"channel":"#default","text":"the message"}' subject.ping "the message" end it "allows override channel to be set" do expect( Slack::Notifier::DefaultHTTPClient ).to receive(:post) .with @endpoint_double, payload: '{"channel":"new","text":"the message"}' subject.ping "the message", channel: "new" end end context "with default webhook" do it "posts with the correct endpoint & data" do @endpoint_double = instance_double "URI::HTTP" allow( URI ).to receive(:parse) .with("http://example.com") .and_return(@endpoint_double) expect( Slack::Notifier::DefaultHTTPClient ).to receive(:post) .with @endpoint_double, payload: '{"channel":"channel","text":"the message"}' described_class.new("http://example.com").ping "the message", channel: "channel" end end context "with a custom http_client set" do it "uses it" do endpoint_double = instance_double "URI::HTTP" allow( URI ).to receive(:parse) .with("http://example.com") .and_return(endpoint_double) client = double("CustomClient") expect( client ).to receive(:post) .with endpoint_double, payload: '{"text":"the message"}' described_class.new('http://example.com',http_client: client).ping "the message" end end end describe "#channel=" do it "sets the given channel" do subject.channel = "#foo" expect( subject.channel ).to eq "#foo" end end describe "#username=" do it "sets the given username" do subject.username = "foo" expect( subject.username ).to eq "foo" end end end slack-notifier-1.2.1/spec/spec_helper.rb000066400000000000000000000003701252624722200202010ustar00rootroot00000000000000require 'rspec' require 'slack-notifier' if ENV['DEBUG'] require 'pry' end RSpec.configure do |config| config.mock_with :rspec do |mocks| mocks.verify_doubled_constant_names = true mocks.verify_partial_doubles = true end end