From 75f615725aab3580db992e795ba64ac20099fe52 Mon Sep 17 00:00:00 2001 From: Andrew Sparkes Date: Fri, 17 Apr 2026 12:05:09 +0100 Subject: [PATCH 1/5] Changes to accommodate mysql 8.4 Re-added PlateTemplate api v2 resource --- .github/workflows/automated_release.yml | 2 +- .github/workflows/build_and_release.yml | 2 +- .github/workflows/cucumber_tests.yml | 2 +- .github/workflows/rake_tests.yml | 2 +- .github/workflows/rspec_feature_tests.yml | 2 +- .github/workflows/rspec_unit_tests.yml | 2 +- .../api/v2/plate_templates_controller.rb | 12 ++++ .../api/v2/plate_template_resource.rb | 41 ++++++++++++ config/routes.rb | 1 + docker-compose.yml | 2 +- spec/requests/api/v2/plate_templates_spec.rb | 65 +++++++++++++++++++ spec/support/user_login.rb | 2 + 12 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 app/controllers/api/v2/plate_templates_controller.rb create mode 100644 app/resources/api/v2/plate_template_resource.rb create mode 100644 spec/requests/api/v2/plate_templates_spec.rb diff --git a/.github/workflows/automated_release.yml b/.github/workflows/automated_release.yml index d77bf6eb35..7d16d3d862 100644 --- a/.github/workflows/automated_release.yml +++ b/.github/workflows/automated_release.yml @@ -16,7 +16,7 @@ jobs: services: mysql: # Use the Mysql docker image https://hub.docker.com/_/mysql - image: mysql:8.0 + image: mysql:8.4 ports: - 3306 # Default port mappings # Monitor the health of the container to mesaure when it is ready diff --git a/.github/workflows/build_and_release.yml b/.github/workflows/build_and_release.yml index 76f207cfd5..0a0dfdeffd 100644 --- a/.github/workflows/build_and_release.yml +++ b/.github/workflows/build_and_release.yml @@ -10,7 +10,7 @@ jobs: services: mysql: # Use the Mysql docker image https://hub.docker.com/_/mysql - image: mysql:8.0 + image: mysql:8.4 ports: - 3306 # Default port mappings # Monitor the health of the container to mesaure when it is ready diff --git a/.github/workflows/cucumber_tests.yml b/.github/workflows/cucumber_tests.yml index 32c34d65d7..337b104112 100644 --- a/.github/workflows/cucumber_tests.yml +++ b/.github/workflows/cucumber_tests.yml @@ -39,7 +39,7 @@ jobs: services: mysql: # Use the Mysql docker image https://hub.docker.com/_/mysql - image: mysql:8.0 + image: mysql:8.4 ports: - 3306 # Default port mappings # Monitor the health of the container to mesaure when it is ready diff --git a/.github/workflows/rake_tests.yml b/.github/workflows/rake_tests.yml index 9dabef0b20..7c5c0abaf8 100644 --- a/.github/workflows/rake_tests.yml +++ b/.github/workflows/rake_tests.yml @@ -36,7 +36,7 @@ jobs: services: mysql: # Use the Mysql docker image https://hub.docker.com/_/mysql - image: mysql:8.0 + image: mysql:8.4 ports: - 3306 # Default port mappings # Monitor the health of the container to mesaure when it is ready diff --git a/.github/workflows/rspec_feature_tests.yml b/.github/workflows/rspec_feature_tests.yml index 184fd8563d..8672c21fa8 100644 --- a/.github/workflows/rspec_feature_tests.yml +++ b/.github/workflows/rspec_feature_tests.yml @@ -39,7 +39,7 @@ jobs: services: mysql: # Use the Mysql docker image https://hub.docker.com/_/mysql - image: mysql:8.0 + image: mysql:8.4 ports: - 3306 # Default port mappings # Monitor the health of the container to mesaure when it is ready diff --git a/.github/workflows/rspec_unit_tests.yml b/.github/workflows/rspec_unit_tests.yml index 58de58a87a..fada0d3c35 100644 --- a/.github/workflows/rspec_unit_tests.yml +++ b/.github/workflows/rspec_unit_tests.yml @@ -39,7 +39,7 @@ jobs: services: mysql: # Use the Mysql docker image https://hub.docker.com/_/mysql - image: mysql:8.0 + image: mysql:8.4 ports: - 3306 # Default port mappings # Monitor the health of the container to mesaure when it is ready diff --git a/app/controllers/api/v2/plate_templates_controller.rb b/app/controllers/api/v2/plate_templates_controller.rb new file mode 100644 index 0000000000..2edd170343 --- /dev/null +++ b/app/controllers/api/v2/plate_templates_controller.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Api + module V2 + # Provides a JSON API controller for PlateTemplate + # See: http://jsonapi-resources.com/ for JSONAPI::Resource documentation + class PlateTemplatesController < JSONAPI::ResourceController + # By default JSONAPI::ResourceController provides most the standard + # behaviour, and in many cases this file may be left empty. + end + end +end diff --git a/app/resources/api/v2/plate_template_resource.rb b/app/resources/api/v2/plate_template_resource.rb new file mode 100644 index 0000000000..09f2b6344b --- /dev/null +++ b/app/resources/api/v2/plate_template_resource.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Api + module V2 + # + # Provides a JSON:API representation of {PlateTemplate}. + # + # A `PlateTemplate` represents a virtual plate used in Cherrypicking to block out empty wells + # or layout pre-assigned samples. + + # @note This resource is accessed via the `/api/v2/plate_templates/` endpoint. + # + # @example GET request to retrieve all plate templates + # GET /api/v2/plate_templates/ + # + # @example GET request to retrieve a specific plate template by ID + # GET /api/v2/plate_templates/123/ + # + # For more information about JSON:API, see the [JSON:API Specifications](https://jsonapi.org/format/) + # or the [JSONAPI::Resources](http://jsonapi-resources.com/) package for Sequencescape's implementation + # of the JSON:API standard. + class PlateTemplateResource < BaseResource + default_includes :uuid_object + + ### + # Attributes + ### + + # @!attribute [r] uuid + # @note This identifier is automatically assigned upon creation and cannot be modified. + # @return [String] The UUID of the plate template. + attribute :uuid, readonly: true + + # @!attribute [r] name + # @note This name is intended for human readability and should clearly indicate the purpose + # of the plate template e.g. 'h12_empty'. It is assigned upon creation in the UI and cannot be modified. + # @return [String] The name of the plate template. + attribute :name, readonly: true + end + end +end diff --git a/config/routes.rb b/config/routes.rb index db4beaa56d..68aa20806c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -63,6 +63,7 @@ jsonapi_resources :plate_conversions, except: %i[update] jsonapi_resources :plate_creations, except: %i[update] jsonapi_resources :plate_purposes, except: %i[update] + jsonapi_resources :plate_templates jsonapi_resources :plates, except: %i[update] post 'plates/:id/register_stock_for_plate', to: 'plates#register_stock_for_plate' diff --git a/docker-compose.yml b/docker-compose.yml index 575351474b..74d7ea667a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ services: retries: 5 mysql_server: - image: mysql:8.0 + image: mysql:8.4 environment: - MYSQL_ALLOW_EMPTY_PASSWORD="yes" healthcheck: diff --git a/spec/requests/api/v2/plate_templates_spec.rb b/spec/requests/api/v2/plate_templates_spec.rb new file mode 100644 index 0000000000..8837350009 --- /dev/null +++ b/spec/requests/api/v2/plate_templates_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'rails_helper' +require './spec/requests/api/v2/shared_examples/api_key_authenticatable' + +describe 'PlateTemplates API', with: :api_v2 do + let(:base_endpoint) { '/api/v2/plate_templates' } + + it_behaves_like 'ApiKeyAuthenticatable' + + context 'with multiple PlateTemplates' do + before { create_list(:plate_template, 5) } + + it 'responds successfully' do + api_get base_endpoint + + # test for the 200 status-code + expect(response).to have_http_status(:success) + end + + it 'returns the list of plate_templates' do + api_get base_endpoint + + # check to make sure the right amount of messages are returned + expect(json['data'].length).to eq(5) + end + end + + context 'with a PlateTemplate' do + let(:resource_model) { create(:plate_template) } + + let(:payload) do + { + 'data' => { + 'id' => resource_model.id, + 'type' => 'plate_templates', + 'attributes' => { + # Set new attributes here + } + } + } + end + + it 'responds successfully' do + api_get "#{base_endpoint}/#{resource_model.id}" + expect(response).to have_http_status(:success) + end + + it 'sends an individual PlateTemplate' do + api_get "#{base_endpoint}/#{resource_model.id}" + expect(json.dig('data', 'type')).to eq('plate_templates') + end + + # Remove if immutable + it 'responds successfully to update' do + api_patch "#{base_endpoint}/#{resource_model.id}", payload + expect(response).to have_http_status(:success) + end + + it 'allows update of a PlateTemplate' do + api_patch "#{base_endpoint}/#{resource_model.id}", payload + expect(json.dig('data', 'type')).to eq('plate_templates') + end + end +end diff --git a/spec/support/user_login.rb b/spec/support/user_login.rb index 603159c35e..768b874137 100644 --- a/spec/support/user_login.rb +++ b/spec/support/user_login.rb @@ -10,6 +10,8 @@ def login_user(user) fill_in 'Username', with: user.login fill_in 'Password', with: 'password' click_button 'Login' + # wait for the login to complete before returning, so ready for whatever is next + find('#message_notice', text: 'Logged in successfully') true end end From bf27602d8138deaa11fdb41fd6a7e5fe3de8574c Mon Sep 17 00:00:00 2001 From: Andrew Sparkes Date: Fri, 17 Apr 2026 12:33:10 +0100 Subject: [PATCH 2/5] linted --- spec/support/user_login.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/user_login.rb b/spec/support/user_login.rb index 768b874137..d10bb2e8d2 100644 --- a/spec/support/user_login.rb +++ b/spec/support/user_login.rb @@ -11,7 +11,7 @@ def login_user(user) fill_in 'Password', with: 'password' click_button 'Login' # wait for the login to complete before returning, so ready for whatever is next - find('#message_notice', text: 'Logged in successfully') + find_by_id('message_notice', text: 'Logged in successfully') true end end From c8bce130fba197fa86d6a8f6cd1e870bb8da4aeb Mon Sep 17 00:00:00 2001 From: Andrew Sparkes Date: Fri, 17 Apr 2026 14:10:23 +0100 Subject: [PATCH 3/5] attempt to fix plate template errors on CI --- app/resources/api/v2/plate_template_resource.rb | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/app/resources/api/v2/plate_template_resource.rb b/app/resources/api/v2/plate_template_resource.rb index 09f2b6344b..93c3998ac3 100644 --- a/app/resources/api/v2/plate_template_resource.rb +++ b/app/resources/api/v2/plate_template_resource.rb @@ -20,22 +20,11 @@ module V2 # or the [JSONAPI::Resources](http://jsonapi-resources.com/) package for Sequencescape's implementation # of the JSON:API standard. class PlateTemplateResource < BaseResource - default_includes :uuid_object - - ### - # Attributes - ### + include Api::V2::SharedBehaviour::Labware - # @!attribute [r] uuid - # @note This identifier is automatically assigned upon creation and cannot be modified. - # @return [String] The UUID of the plate template. - attribute :uuid, readonly: true + model_name 'PlateTemplate' - # @!attribute [r] name - # @note This name is intended for human readability and should clearly indicate the purpose - # of the plate template e.g. 'h12_empty'. It is assigned upon creation in the UI and cannot be modified. - # @return [String] The name of the plate template. - attribute :name, readonly: true + default_includes :uuid_object end end end From 6d78ee8e12d64511141a41a7dbb2606f2a091f08 Mon Sep 17 00:00:00 2001 From: Andrew Sparkes Date: Fri, 17 Apr 2026 14:42:17 +0100 Subject: [PATCH 4/5] fix for destroying plate templates that have wells --- app/controllers/plate_templates_controller.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/controllers/plate_templates_controller.rb b/app/controllers/plate_templates_controller.rb index 4b82ad0e02..bea875c041 100644 --- a/app/controllers/plate_templates_controller.rb +++ b/app/controllers/plate_templates_controller.rb @@ -60,7 +60,16 @@ def update # rubocop:todo Metrics/AbcSize def destroy pattern = PlateTemplate.find(params[:id]) - pattern.destroy + begin + ActiveRecord::Base.transaction do + pattern.wells.destroy_all + pattern.destroy! + end + + flash[:notice] = 'Template deleted' + rescue ActiveRecord::DeleteRestrictionError, ActiveRecord::RecordNotDestroyed + flash[:error] = 'Template cannot be deleted because it has dependent records' + end respond_to { |format| format.html { redirect_to(plate_templates_path) } } end From 023c9b2150d0c6e3cede61f1186b578a81d0746e Mon Sep 17 00:00:00 2001 From: Andrew Sparkes Date: Mon, 20 Apr 2026 12:02:44 +0100 Subject: [PATCH 5/5] linted --- app/controllers/plate_templates_controller.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/controllers/plate_templates_controller.rb b/app/controllers/plate_templates_controller.rb index bea875c041..b0d12ee536 100644 --- a/app/controllers/plate_templates_controller.rb +++ b/app/controllers/plate_templates_controller.rb @@ -58,6 +58,7 @@ def update # rubocop:todo Metrics/AbcSize redirect_to plate_templates_path end + # rubocop:disable Metrics/MethodLength def destroy pattern = PlateTemplate.find(params[:id]) begin @@ -73,4 +74,6 @@ def destroy respond_to { |format| format.html { redirect_to(plate_templates_path) } } end + + # rubocop:enable Metrics/MethodLength end