Skip to content

Commit

Permalink
Merge pull request #522 from alphagov/add-gem-alerts
Browse files Browse the repository at this point in the history
Add alerts about unreleased changes to gems
  • Loading branch information
MuriloDalRi authored Apr 11, 2024
2 parents cc86e95 + 23e484a commit daa8baf
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/gem_version_checker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "Gem Version Checker"

on:
workflow_dispatch: {}
schedule:
- cron: '00 13 * * 3' # Runs at 13:00 UTC, Every Wednesday.

env:
SEAL_ORGANISATION: alphagov
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

jobs:
gem-version-checker:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Gem Version Checker
id: gem_version_checker
run: |
./bin/seal_runner.rb gems
File renamed without changes.
36 changes: 36 additions & 0 deletions lib/gem_version_checker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "uri"
require "net/http"
require "json"

class GemVersionChecker
def detect_version_discrepancies(gem_name)
rubygems_version = fetch_rubygems_version(gem_name)
rubygems_version if rubygems_version && change_is_significant?(gem_name, rubygems_version)
end

def fetch_rubygems_version(gem_name)
uri = URI("https://rubygems.org/api/v1/gems/#{gem_name}.json")
res = Net::HTTP.get_response(uri)

JSON.parse(res.body)["version"] if res.is_a?(Net::HTTPSuccess)
end

def files_changed_since_tag(repo, tag)
Dir.mktmpdir do |path|
Dir.chdir(path) do
if system("git clone --recursive --depth 1 --shallow-submodules --no-single-branch https://github.com/alphagov/#{repo}.git > /dev/null 2>&1")
Dir.chdir(repo) { `git diff --name-only #{tag}`.split("\n") }
else
puts "Warning: Failed to clone #{repo}"
[]
end
end
end
end

def change_is_significant?(repo_name, previous_version)
files_changed_since_tag(repo_name, "v#{previous_version}").any? do |path|
path.start_with?("app/", "lib/") || path == "CHANGELOG.md"
end
end
end
30 changes: 30 additions & 0 deletions lib/message_builder.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "pathname"
require_relative "gem_version_checker"
require_relative "github_fetcher"
require_relative "message"

Expand All @@ -18,6 +19,8 @@ def build
build_dependapanda_message
when :ci
build_ci_message
when :gems
build_gems_message
else
build_regular_message
end
Expand Down Expand Up @@ -57,6 +60,33 @@ def build_ci_message
Message.new(ci_message, mood: "robot_face")
end

def build_gems_message
Message.new(gems_message, mood: "gem")
end

def gems_message
@alerts = all_govuk_gems.select { |gem| gem["team"] == team.channel }.map { |gem|
alert = GemVersionChecker.new.detect_version_discrepancies(gem["app_name"])
"<#{gem['links']['repo_url']}|#{gem['app_name']}> has unreleased changes since v#{alert}" if alert
}.compact

template_file = Pathname.new("#{TEMPLATE_DIR}/gem_alerts.text.erb")
ERB.new(template_file.read, trim_mode: "-").result(binding).strip
end

def all_govuk_gems
@all_govuk_gems ||= fetch_gems
end

def fetch_gems
res = Net::HTTP.get_response(URI("https://docs.publishing.service.gov.uk/gems.json"))

JSON.parse(res.body)
rescue StandardError => e
puts "Error fetching gems: #{e.message}"
[]
end

def ci_message
@repos = check_team_repos_ci.reject { |_, v| v }.keys
return nil if @repos.empty?
Expand Down
2 changes: 2 additions & 0 deletions lib/seal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def bark_at(team, mode: nil)
MessageBuilder.new(team, :ci).build if team.ci_checks
when "seal_prs"
MessageBuilder.new(team, :seal).build if team.seal_prs
when "gems"
MessageBuilder.new(team, :gems).build if team.gems
end

return if message.nil? || message.text.nil?
Expand Down
2 changes: 2 additions & 0 deletions lib/slack_poster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def assign_poster_settings
[":#{@season_symbol}angrier_seal:", "#{@season_name}Angry Seal"]
when "robot_face"
[":robot_face:", "Angry CI Robot"]
when "gem"
[":gem:", "Gem Release Robot"]
when "tea"
[":manatea:", "Tea Seal"]
when "charter"
Expand Down
3 changes: 3 additions & 0 deletions lib/team.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ def initialize(
afternoon_seal_quotes: nil,
dependapanda: nil,
ci_checks: nil,
gems: nil,
compact: nil,
exclude_labels: nil,
exclude_titles: nil,
Expand All @@ -22,6 +23,7 @@ def initialize(
@afternoon_seal_quotes = (afternoon_seal_quotes.nil? ? false : afternoon_seal_quotes)
@dependapanda = (dependapanda.nil? ? false : dependapanda)
@ci_checks = (ci_checks.nil? ? false : ci_checks)
@gems = (gems.nil? ? false : gems)
@compact = (compact.nil? ? false : compact)
@quotes_days = quotes_days || []
@exclude_labels = exclude_labels || []
Expand All @@ -40,6 +42,7 @@ def initialize(
afternoon_seal_quotes
dependapanda
ci_checks
gems
compact
exclude_labels
exclude_titles
Expand Down
2 changes: 2 additions & 0 deletions lib/team_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def build_all_teams
raise "#{team_name} is a GOV.UK team and shouldn't list repos in ./config/alphagov.yml"
end
team_config["ci_checks"] = is_govuk_team?(team_name)
team_config["gems"] = is_govuk_team?(team_name)
Team.new(**apply_env(team_config))
end
end
Expand All @@ -60,6 +61,7 @@ def apply_env(config)
afternoon_seal_quotes: env["AFTERNOON_SEAL_QUOTES"] == "true" || config["afternoon_seal_quotes"],
dependapanda: env["DEPENDAPANDA"] == "true" || config["dependapanda"],
ci_checks: env["CI_CHECKS"] == "true" || config["ci_checks"],
gems: env["GEMS"] == "true" || config["gems"],
compact: env["COMPACT"] == "true" || config["compact"],
exclude_labels: env["GITHUB_EXCLUDE_LABELS"]&.split(",") || config["exclude_labels"],
exclude_titles: env["GITHUB_EXCLUDE_TITLES"]&.split(",") || config["exclude_titles"],
Expand Down
36 changes: 36 additions & 0 deletions spec/gem_version_checker_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "./lib/gem_version_checker"

RSpec.describe GemVersionChecker do
subject(:gem_version_checker) { described_class.new }

let(:slack_poster) { instance_double(SlackPoster, send_request: nil) }

before do
allow(SlackPoster).to receive(:new).and_return(slack_poster)
end

it "fetches version number of a gem from rubygems" do
stub_rubygems_call("6.0.1")

expect(gem_version_checker.fetch_rubygems_version("example")).to eq("6.0.1")
end

it "detects when there are files changed since the last release that are built into the gem" do
stub_rubygems_call("1.2.2")
stub_files_changed_since_tag(["lib/foo.rb"])

expect(gem_version_checker.detect_version_discrepancies("example")).to match("1.2.2")
end

def stub_files_changed_since_tag(files)
allow(gem_version_checker).to receive(:files_changed_since_tag) do
files
end
end

def stub_rubygems_call(version)
repo = { "version": version }
stub_request(:get, "https://rubygems.org/api/v1/gems/example.json")
.to_return(status: 200, body: repo.to_json, headers: {})
end
end
3 changes: 3 additions & 0 deletions templates/gem_alerts.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<% @alerts.each do |alert| -%>
<%= alert %>
<% end -%>

0 comments on commit daa8baf

Please sign in to comment.