Skip to content

Commit

Permalink
Add special_route_publisher class and rake tasks
Browse files Browse the repository at this point in the history
- Replace calls to publishing-api with direct calls to the Command
  classes responsible for serving the relevant actions.
- Add test suite for rake tests that tests the larger points (does
  the file load the correct number of routes and publish them,
  does it return error messages for missing paths, etc).
- Add test suite for special_route_publisher to test finer points
  (default locales, does it handle links/additional routes, etc)
- Replace puts with Rails.logger.info, which should show when
  run from the command line but also logs properly and doesn't
  affect tests.
- Remove catch for KeyError - it's not really critical that we
  allow the rake tasks to run with broken data, the data should be
  kept valid.
  • Loading branch information
KludgeKML committed Sep 24, 2024
1 parent fa925ce commit 434b339
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 0 deletions.
107 changes: 107 additions & 0 deletions lib/tasks/special_route_publisher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
module Tasks
class SpecialRoutePublisher
def self.publish_special_routes
new.publish_routes(load_special_routes)
end

def self.publish_special_routes_for_app(app_name)
routes = load_special_routes.filter { |r| r[:rendering_app] == app_name }

if routes.any?
new.publish_routes(routes)
else
Rails.logger.info("No routes for #{app_name} in lib/data/special_routes.yaml")
end
end

def self.publish_one_route(base_path)
route = load_special_routes.find { |r| r[:base_path] == base_path }

if route
new.publish_routes([route])
else
Rails.logger.info("Route needs to be added to /lib/data/special_routes.yaml")
end
end

def self.unpublish_one_route(base_path, alternative_path = nil)
route = load_special_routes.find { |r| r[:base_path] == base_path }

if route && alternative_path
Commands::V2::Unpublish.call({ content_id: route.fetch(:content_id), type: "redirect", alternative_path: })
elsif route
Commands::V2::Unpublish.call({ content_id: route.fetch(:content_id), type: "gone" })
else
Rails.logger.info("Route needs to be added to /lib/data/special_routes.yaml")
end
end

def self.publish_homepage
new.publish_routes(load_homepage)
end

def publish_route(route)
routes = get_routes(route)

routes.each { |r| Rails.logger.info("Publishing #{r[:type]} route #{r[:path]}, routing to #{route.fetch(:rendering_app)}...") }

content_id = route.fetch(:content_id)

# Always request a path reservation before publishing the special route,
# with the flag to override any existing publishing app.
# This allows for routes that were previously published by other apps to
# be added to `special_routes.yaml` and "just work".
# Commands::ReservePath.call(path_item)
Commands::ReservePath.call({
base_path: route.fetch(:base_path),
publishing_app: "publishing-api",
override_existing: true,
})

Commands::V2::PutContent.call({
content_id:,
base_path: route.fetch(:base_path),
document_type: route.fetch(:document_type, "special_route"),
schema_name: route.fetch(:document_type, "special_route"),
title: route.fetch(:title),
description: route.fetch(:description, ""),
locale: route.fetch(:locale, "en"),
details: {},
routes:,
publishing_app: "publishing-api",
rendering_app: route.fetch(:rendering_app),
public_updated_at: Time.zone.now.iso8601,
update_type: route.fetch(:update_type, "major"),
})

if route[:links]
Commands::V2::PatchLinkSet.call({ content_id:, links: route[:links] })
end

Commands::V2::Publish.call({ content_id:, update_type: nil, locale: route.fetch(:locale, "en") })
end

def get_routes(route)
routes = [
{
path: route.fetch(:base_path),
type: route.fetch(:type, "exact"),
},
]

routes + route.fetch(:additional_routes, []).map { |ar| { path: ar[:base_path], type: ar.fetch(:type, "exact") } }
end

def publish_routes(routes)
routes.each { |r| publish_route(r) }
end

def self.load_special_routes
YAML.load_file(Rails.root.join("lib/data/special_routes.yaml"))
end

def self.load_homepage
YAML.load_file(Rails.root.join("lib/data/homepage.yaml"))
end
end
end
24 changes: 24 additions & 0 deletions lib/tasks/special_routes.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
desc "Publish special routes (except the homepage)"
task publish_special_routes: :environment do
Tasks::SpecialRoutePublisher.publish_special_routes
end

desc "Publish all special routes for a single application"
task :publish_special_routes_for_app, [:app_name] => :environment do |_, args|
Tasks::SpecialRoutePublisher.publish_special_routes_for_app(args.app_name)
end

desc "Publish a single special route"
task :publish_one_special_route, [:base_path] => :environment do |_, args|
Tasks::SpecialRoutePublisher.publish_one_route(args.base_path)
end

desc "Unpublish a single special route, with a type of 'gone' or 'redirect'"
task :unpublish_one_special_route, %i[base_path alternative_path] => :environment do |_, args|
Tasks::SpecialRoutePublisher.unpublish_one_route(args.base_path, args.alternative_path)
end

desc "Publish the homepage"
task publish_homepage: :environment do
Tasks::SpecialRoutePublisher.publish_homepage
end
10 changes: 10 additions & 0 deletions spec/fixtures/homepage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- :content_id: "f3bbdec2-0e62-4520-a7fd-6ffd5d36e03a"
:base_path: "/"
:document_type: "homepage"
:title: "GOV.UK homepage"
:rendering_app: "frontend"
:links:
:organisations:
- "af07d5a5-df63-4ddc-9383-6a666845ebe9"
:primary_publishing_organisation:
- "af07d5a5-df63-4ddc-9383-6a666845ebe9"
16 changes: 16 additions & 0 deletions spec/fixtures/special_routes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- :content_id: "c1f08359-21f7-49c1-8811-54bf6690b6a3"
:base_path: "/account/home"
:title: "Account home page"
:rendering_app: "frontend"

- :content_id: "e5098fc2-ad79-4c6f-882b-410831c12f60"
:base_path: "/account/saved-pages/add"
:title: "Save a page"
:rendering_app: "frontend"

- :content_id: "cdcad470-21c6-4e19-b644-9e499de1ad12"
:base_path: "/media"
:title: "Government Uploads"
:description: "Handles redirects for /media/:id/:filename path for asset manager"
:type: "prefix"
:rendering_app: "government-frontend"
66 changes: 66 additions & 0 deletions spec/lib/tasks/special_route_publisher_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
RSpec.describe Tasks::SpecialRoutePublisher do
let(:content_id) { "f3bbdec2-0e62-4520-a7fd-6ffd5d36e03a" }

before do
stub_request(:put, %r{.*content-store.*/content/.*})
end

describe "#publish_route" do
it "sets the rendering app" do
described_class.new.publish_route(content_id:, base_path: "/", title: "Hello", rendering_app: "frontend")

expect(Edition.first.rendering_app).to eq("frontend")
end

context "without a specific locale" do
it "defaults to english" do
described_class.new.publish_route(content_id:, base_path: "/", title: "Hello", rendering_app: "frontend")

expect(Edition.first.locale).to eq("en")
end
end

context "with a specific locale" do
it "uses the specified locale" do
described_class.new.publish_route(content_id:, base_path: "/", title: "Hello", rendering_app: "frontend", locale: "cy")

expect(Edition.first.locale).to eq("cy")
end
end

context "with additional routes" do
let(:additional_routes) { [base_path: "/homepage.json", type: "exact"] }

it "calls the Publishing API with all routes specified for the item" do
described_class.new.publish_route(content_id:, base_path: "/", title: "Hello", rendering_app: "frontend", additional_routes:)

expect(Edition.first.routes).to eq(
[
{ path: "/", type: "exact" },
{ path: "/homepage.json", type: "exact" },
],
)
end
end

context "with links" do
let(:links) do
{
organisations: %w[af07d5a5-df63-4ddc-9383-6a666845ebea],
primary_publishing_organisation: %w[af07d5a5-df63-4ddc-9383-6a666845ebe9],
}
end

it "adds the links" do
described_class.new.publish_route(content_id:, base_path: "/", title: "Hello", rendering_app: "frontend", links:)

link_set = Edition.first.document.link_set
expect(link_set).not_to be_nil
expect(link_set.links.first.link_type).to eq("organisations")
expect(link_set.links.first.target_content_id).to eq("af07d5a5-df63-4ddc-9383-6a666845ebea")
expect(link_set.links.second.link_type).to eq("primary_publishing_organisation")
expect(link_set.links.second.target_content_id).to eq("af07d5a5-df63-4ddc-9383-6a666845ebe9")
end
end
end
end
135 changes: 135 additions & 0 deletions spec/lib/tasks/special_routes_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
RSpec.describe "Rake tasks for publishing special routes" do
context "with special routes data" do
let(:stdout) { double(:stdout, puts: nil) }

before do
stub_request(:put, %r{.*content-store.*/content/.*})
end

let(:replacement_special_routes_file) do
YAML.load_file(Rails.root.join("spec/fixtures/special_routes.yaml"))
end

before do
original_special_routes_path = Rails.root.join("lib/data/special_routes.yaml")
allow(YAML).to receive(:load_file).with(original_special_routes_path).and_return(replacement_special_routes_file)
end

describe "publish_special_routes" do
before do
Rake::Task["publish_special_routes"].reenable
end

it "publishes the special routes" do
Rake::Task["publish_special_routes"].invoke

expect(Document.count).to eq(3)
expect(Edition.count).to eq(3)
end
end

describe "publish_special_routes_for_app" do
before do
Rake::Task["publish_special_routes_for_app"].reenable
end

it "publishes the special routes for one particular app without publishing others" do
Rake::Task["publish_special_routes_for_app"].invoke("government-frontend")

expect(Document.count).to eq(1)
expect(Edition.count).to eq(1)
edition = Edition.where(title: "Government Uploads").first
expect(edition).not_to be_nil
end

it "returns a message if there are no routes for that app" do
expect(Rails.logger).to receive(:info).with(/No routes for finder-frontend in lib\/data\/special_routes.yaml/)

Rake::Task["publish_special_routes_for_app"].invoke("finder-frontend")

expect(Document.count).to eq(0)
end
end

describe "publish_one_special_route" do
before do
Rake::Task["publish_one_special_route"].reenable
end

it "publishes one special route" do
Rake::Task["publish_one_special_route"].invoke("/account/saved-pages/add")

expect(Document.count).to eq(1)
expect(Edition.count).to eq(1)
edition = Edition.where(title: "Save a page").first
expect(edition).not_to be_nil
end

it "returns a message if there are no records for that path" do
expect(Rails.logger).to receive(:info).with(/Route needs to be added to \/lib\/data\/special_routes.yaml/)

Rake::Task["publish_one_special_route"].invoke("/account/saved-pages/remove")

expect(Document.count).to eq(0)
end
end

describe "unpublish_one_special_route" do
before do
Rake::Task["publish_one_special_route"].reenable
Rake::Task["publish_one_special_route"].invoke("/media")
Rake::Task["unpublish_one_special_route"].reenable
end

it "unpublishes one special route" do
expect(Edition.first.state).to eq("published")

Rake::Task["unpublish_one_special_route"].invoke("/media")

expect(Edition.first.state).to eq("unpublished")
end

it "unpublishes one special route with a redirect" do
expect(Edition.first.state).to eq("published")

Rake::Task["unpublish_one_special_route"].invoke("/media", "/media2")

expect(Edition.first.state).to eq("unpublished")
end

it "returns a message if there are no records for that path" do
expect(Edition.first.state).to eq("published")
expect(Rails.logger).to receive(:info).with(/Route needs to be added to \/lib\/data\/special_routes.yaml/)

Rake::Task["unpublish_one_special_route"].invoke("/account/saved-pages/remove")

expect(Edition.first.state).to eq("published")
end
end
end

context "with homepage data" do
before do
stub_request(:put, %r{.*content-store.*/content/.*})
Rake::Task["publish_homepage"].reenable
end

let(:replacement_homepage_file) do
YAML.load_file(Rails.root.join("spec/fixtures/homepage.yaml"))
end

before do
original_homepage_path = Rails.root.join("lib/data/homepage.yaml")
allow(YAML).to receive(:load_file).with(original_homepage_path).and_return(replacement_homepage_file)
end

it "publishes the special routes" do
Rake::Task["publish_homepage"].invoke

expect(Document.count).to eq(1)
expect(Edition.count).to eq(1)
edition = Edition.where(title: "GOV.UK homepage").first
expect(edition).not_to be_nil
end
end
end

0 comments on commit 434b339

Please sign in to comment.