From a60fb45085283237beadc046dba6633e5de3d157 Mon Sep 17 00:00:00 2001 From: PeterHattyar Date: Wed, 28 Feb 2024 14:01:23 +0000 Subject: [PATCH] Slack message implementation These changes add and configure Slack Poster to the application, so it notifies the owners of the affected gems via their team's Slack channels. --- .github/workflows/version_checker.yml | 5 +++- Gemfile | 1 + Gemfile.lock | 3 ++ lib/version_checker.rb | 36 ++++++++++++++++------- spec/version_checker_spec.rb | 42 +++++++++++++++++++++++++-- 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/.github/workflows/version_checker.yml b/.github/workflows/version_checker.yml index 654c685..b700f42 100644 --- a/.github/workflows/version_checker.yml +++ b/.github/workflows/version_checker.yml @@ -3,7 +3,10 @@ name: "Gem Version Checker" on: workflow_dispatch: {} schedule: - - cron: '00 10 * * 1-5' # Runs at 10:00, Monday through Friday. + - cron: '00 13 * * 3' # Runs at 13:00, Every Wednesday. + +env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} jobs: gem-version-checker: diff --git a/Gemfile b/Gemfile index fd21c6a..f7daeea 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,7 @@ source "https://rubygems.org" gem "octokit" gem "rake" +gem "slack-poster" gem "webmock" group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index d3a2979..7e363ef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -101,6 +101,8 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) + slack-poster (2.2.2) + faraday (>= 1.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) @@ -117,6 +119,7 @@ DEPENDENCIES rake rspec rubocop-govuk + slack-poster webmock BUNDLED WITH diff --git a/lib/version_checker.rb b/lib/version_checker.rb index 72dd6f5..53ee98f 100644 --- a/lib/version_checker.rb +++ b/lib/version_checker.rb @@ -4,6 +4,7 @@ require "net/http" require "json" require "octokit" +require "slack/poster" class HttpError < RuntimeError end @@ -11,22 +12,37 @@ class HttpError < RuntimeError class VersionChecker GEMS_API = URI("https://docs.publishing.service.gov.uk/gems.json") + def slack_options(team) + { + icon_emoji: ":gem:", + username: "Gem Release Bot", + channel: team.to_s, + } + end + def print_version_discrepancies all_govuk_gems.group_by { |gem| gem["team"] }.each do |team, gems| - message = gems.filter_map { |gem| - repo_name = gem["app_name"] - rubygems_version = fetch_rubygems_version(repo_name) - if !rubygems_version.nil? && - files_changed_since_tag(repo_name, "v#{rubygems_version}").any? { |path| path_built_into_gem?(path) } - " #{repo_name} has unreleased changes since v#{rubygems_version}" - end - }.join("\n") + message = message_builder(gems) + + puts "team: #{team}\n#{message}" - puts team - puts message + poster = Slack::Poster.new(ENV["SLACK_WEBHOOK"], slack_options(team)) + poster.send_message(message.to_s) unless message.nil? end end + def message_builder(gems) + gems.filter_map { |gem| + repo_name = gem["app_name"] + repo_url = gem["links"]["repo_url"] + rubygems_version = fetch_rubygems_version(repo_name) + if !rubygems_version.nil? && + files_changed_since_tag(repo_name, "v#{rubygems_version}").any? { |path| path_built_into_gem?(path) } + " <#{repo_url}|#{repo_name}> has unreleased changes since v#{rubygems_version}" + end + }.join("\n") + end + def all_govuk_gems res = Net::HTTP.get_response(GEMS_API) if res.is_a?(Net::HTTPSuccess) diff --git a/spec/version_checker_spec.rb b/spec/version_checker_spec.rb index 84e7cb4..67ed1ee 100644 --- a/spec/version_checker_spec.rb +++ b/spec/version_checker_spec.rb @@ -6,6 +6,12 @@ RSpec.describe VersionChecker do subject(:version_checker) { described_class.new } + let(:webhook_url) { "https://slack/webhook" } + + before do + ENV["SLACK_WEBHOOK"] = webhook_url + end + it "fetches version number of a gem from rubygems" do stub_rubygems_call("6.0.1") @@ -13,20 +19,22 @@ end it "detects when there are no files changed since the last release that are built into the gem" do + stub_slack_poster_call_with_no_changes stub_devdocs_call stub_rubygems_call("1.2.3") stub_files_changed_since_tag(["README.md"]) - expect { version_checker.print_version_discrepancies }.to output("#platform-security-reliability-team\n\n").to_stdout + expect { version_checker.print_version_discrepancies }.to output("team: #platform-security-reliability-team\n").to_stdout end it "detects when there are files changed since the last release that are built into the gem" do + stub_slack_poster_call_with_changes stub_devdocs_call stub_rubygems_call("1.2.2") stub_files_changed_since_tag(["lib/foo.rb"]) expect { version_checker.print_version_discrepancies }.to output( - "#platform-security-reliability-team\n example has unreleased changes since v1.2.2\n", + "team: #platform-security-reliability-team\n has unreleased changes since v1.2.2\n", ).to_stdout end @@ -45,8 +53,36 @@ def stub_rubygems_call(version) end def stub_devdocs_call - repo = [{ "app_name": "example", "team": "#platform-security-reliability-team" }] + repo = [{ "app_name": "example", "team": "#platform-security-reliability-team", "links": { "repo_url": "https://example.com" } }] stub_request(:get, "https://docs.publishing.service.gov.uk/gems.json") .to_return(status: 200, body: repo.to_json, headers: {}) end + + def stub_slack_poster_call_with_changes + stub_request(:post, "https://slack/webhook") + .with( + body: { "payload" => "{\"icon_emoji\":\":gem:\",\"username\":\"Gem Release Bot\",\"channel\":\"#platform-security-reliability-team\",\"text\":\" has unreleased changes since v1.2.2\"}" }, + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", + "Content-Type" => "application/x-www-form-urlencoded", + "User-Agent" => "Faraday v2.7.11", + }, + ) + .to_return(status: 200, body: "", headers: {}) + end + + def stub_slack_poster_call_with_no_changes + stub_request(:post, "https://slack/webhook") + .with( + body: { "payload" => "{\"icon_emoji\":\":gem:\",\"username\":\"Gem Release Bot\",\"channel\":\"#platform-security-reliability-team\",\"text\":\"\"}" }, + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", + "Content-Type" => "application/x-www-form-urlencoded", + "User-Agent" => "Faraday v2.7.11", + }, + ) + .to_return(status: 200, body: "", headers: {}) + end end