From 1a1d51b77247e01d3475b01420430a1143347973 Mon Sep 17 00:00:00 2001
From: Adam Lee <32270711+Gubbsy@users.noreply.github.com>
Date: Fri, 4 Aug 2023 12:11:33 +0100
Subject: [PATCH 01/28] Fix/app memory allocation (#1133)
* Bump research memory allocation to 1GB
* Bump mem to 2GB on UATT & PROD, restore research to 256MB
---
manifest-production.yml | 2 +-
manifest-uat.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/manifest-production.yml b/manifest-production.yml
index 4cd9d10e0..4b365b3a0 100644
--- a/manifest-production.yml
+++ b/manifest-production.yml
@@ -13,7 +13,7 @@ applications:
processes:
- type: web
command: bundle exec rake cf:on_first_instance db:migrate && rails s -p $PORT
- memory: 256M
+ memory: 2GB
instances: 2
health-check-type: http
health-check-http-endpoint: /health
diff --git a/manifest-uat.yml b/manifest-uat.yml
index ec8b89ef5..7276a9785 100644
--- a/manifest-uat.yml
+++ b/manifest-uat.yml
@@ -13,7 +13,7 @@ applications:
processes:
- type: web
command: bundle exec rake cf:on_first_instance db:migrate && rails s -p $PORT
- memory: 256M
+ memory: 2GB
instances: 2
health-check-type: http
health-check-http-endpoint: /health
From b5da4f3b16859e648b01095a681face630586c4d Mon Sep 17 00:00:00 2001
From: Jack <91466216+JJD1990@users.noreply.github.com>
Date: Mon, 7 Aug 2023 10:13:33 +0100
Subject: [PATCH 02/28] reordered reconnection report data (#1132)
---
app/helpers/import_helper.rb | 2 +-
.../admin_portal/reconnection_report/show.html.erb | 14 ++++++--------
.../salesforce/import/import_salesforce_api.rb | 2 +-
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb
index 780d3efa7..ccb20792b 100644
--- a/app/helpers/import_helper.rb
+++ b/app/helpers/import_helper.rb
@@ -373,7 +373,7 @@ def populate_temporary_table_and_run_report(projects_for_reconnection)
project.Project_Reference_Number__c)
pop_temp_table_sql << "INSERT INTO reconnection_projects VALUES (" \
- "#{name}, #{title}, #{ref}, #{area});"
+ "#{name}, #{title}, #{area}, #{ref} );"
end
diff --git a/app/views/admin_portal/reconnection_report/show.html.erb b/app/views/admin_portal/reconnection_report/show.html.erb
index 3a622f587..4d5e0c73f 100644
--- a/app/views/admin_portal/reconnection_report/show.html.erb
+++ b/app/views/admin_portal/reconnection_report/show.html.erb
@@ -11,9 +11,9 @@
-
+
@@ -22,17 +22,15 @@
<%# This could be a nested loop, but to be explicit: %>
<%# row[0] - Project Owner%>
- <%# row[2] - Project Reference Number%>
- <%# row[3] - Project Title%>
- <%# row[1] - Project area/country%>
+ <%# row[1] - Project Title%>
+ <%# row[2] - Project area/country%>
+ <%# row[3] - Project Reference Number%>
<%# row[4] - Project Reconnection Date%>
- <%=row[2]%> |
+ <%=row[1]%> |
+ <%=row[2].present? ? row[2]: 'Not specified'%> |
<%=row[3]%> |
- <%=row[1].present? ? row[1]: 'Not specified'%> |
<%=row[4].present? ? row[4].strftime('%d-%m-%Y').to_s : 'Not reconnected' %> |
-
-
<% end %>
diff --git a/lib/apis/salesforce/import/import_salesforce_api.rb b/lib/apis/salesforce/import/import_salesforce_api.rb
index 4d1e2e23f..6bbc464d0 100644
--- a/lib/apis/salesforce/import/import_salesforce_api.rb
+++ b/lib/apis/salesforce/import/import_salesforce_api.rb
@@ -180,7 +180,7 @@ def retrieve_existing_account_info(name, postcode, org_id)
def get_projects_selected_for_reconnection
query = "SELECT Owner.Name, Project_Title__c, " \
- "Project_Reference_Number__c, Region__c " \
+ "Region__c, Project_Reference_Number__c " \
"FROM Case where Export_to_IMS_Portal__c = true "
restforce_response = run_salesforce_query(
From 2fc89d06e4e6d8bc4dd00a7f968956dec078679c Mon Sep 17 00:00:00 2001
From: Paul Trelease
Date: Mon, 7 Aug 2023 14:03:50 +0100
Subject: [PATCH 03/28] Feature/manifest to increase disk for uat prod (#1134)
* increased disk storage values for UAT and prod from 1 to 3GB
---
manifest-production.yml | 1 +
manifest-uat.yml | 1 +
2 files changed, 2 insertions(+)
diff --git a/manifest-production.yml b/manifest-production.yml
index 4b365b3a0..8437d5db4 100644
--- a/manifest-production.yml
+++ b/manifest-production.yml
@@ -14,6 +14,7 @@ applications:
- type: web
command: bundle exec rake cf:on_first_instance db:migrate && rails s -p $PORT
memory: 2GB
+ disk_quota: 3GB
instances: 2
health-check-type: http
health-check-http-endpoint: /health
diff --git a/manifest-uat.yml b/manifest-uat.yml
index 7276a9785..a00ebd841 100644
--- a/manifest-uat.yml
+++ b/manifest-uat.yml
@@ -14,6 +14,7 @@ applications:
- type: web
command: bundle exec rake cf:on_first_instance db:migrate && rails s -p $PORT
memory: 2GB
+ disk_quota: 3GB
instances: 2
health-check-type: http
health-check-http-endpoint: /health
From 63081996f8d078bc61347235c96a0685751afcca Mon Sep 17 00:00:00 2001
From: Jack <91466216+JJD1990@users.noreply.github.com>
Date: Tue, 8 Aug 2023 08:50:37 +0100
Subject: [PATCH 04/28] Fix/org name length 255 (#1135)
* validation for organisation name set to 255, spec written
* error message added to en & cy yml files, validade_length/too_long method added to organisation model.
* better rspec test written for organisation name validation
* deleted redundant validate_length method in organisation.rb
---
app/models/organisation.rb | 1 +
config/locales/cy.yml | 1 +
config/locales/en.yml | 1 +
spec/models/organisation_spec.rb | 17 +++++++++++++++++
4 files changed, 20 insertions(+)
create mode 100644 spec/models/organisation_spec.rb
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index a540db638..eda2024a1 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -46,6 +46,7 @@ class Organisation < ApplicationRecord
validates :custom_org_type, presence: true, if: :validate_custom_org_type?
validate :validate_mission_array, if: :validate_mission?
validates :name, presence: true, if: :validate_name?
+ validates :name, length: { maximum: 255 }
validates :name, presence: true, if: :validate_address?
validates :line1, presence: true, if: :validate_address?
validates :townCity, presence: true, if: :validate_address?
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index ca78fb019..83db170c0 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -204,6 +204,7 @@ cy:
not_a_number: "Mae'n rhaid i rif cwmni fod yn rhif, fel 12345678"
name:
blank: "Rhowch enw eich sefydliad"
+ too_long: "Rhaid i Enw Sefydliad fod yn 225 nod neu lai"
line1:
blank: "Rhowch linell gyntaf cyfeiriad eich sefydliad"
townCity:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 7ac41400b..eec7484d5 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -204,6 +204,7 @@ en-GB:
not_a_number: "Company number must be a number, like 12345678"
name:
blank: "Enter the name of your organisation"
+ too_long: "Organisation name must be 255 characters or fewer"
line1:
blank: "Enter the first line of your organisation's address"
townCity:
diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb
new file mode 100644
index 000000000..5a741cda0
--- /dev/null
+++ b/spec/models/organisation_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+RSpec.describe Organisation, type: :model do
+ let(:valid_organisation_1) { Organisation.new(name: 'A' * 255) }
+ let(:valid_organisation_2) { Organisation.new(name: 'A' * 100) }
+ let(:invalid_organisation) { Organisation.new(name: 'A' * 256) }
+
+ it 'validates length of name to be less than or equal to 255 characters' do
+ expect(invalid_organisation.valid?).to be(false)
+ expect(invalid_organisation.errors[:name]).to include("Organisation name must be 255 characters or fewer")
+ end
+
+ it 'is valid when organisation name is equal to or below 255 characters' do
+ expect(valid_organisation_1.valid?).to be(true)
+ expect(valid_organisation_2.valid?).to be(true)
+ end
+end
\ No newline at end of file
From 0728d2c4c709a161bd141020de3f247852f67fe4 Mon Sep 17 00:00:00 2001
From: Jack <91466216+JJD1990@users.noreply.github.com>
Date: Wed, 9 Aug 2023 09:10:14 +0100
Subject: [PATCH 05/28] Fix/unticked mission (#1136)
* conditionals added to update action in mission_controller which sets mission to empty string if no mission chosen for bugfix
* created ensure_mission_params method in organisation.rb, added not to explain method
* mission_controller_spec added both indirectly and directly testing the ensure_mission_params method
---
.../organisation/mission_controller.rb | 18 ++++++
.../organisation/mission_controller_spec.rb | 62 +++++++++++++++++++
2 files changed, 80 insertions(+)
diff --git a/app/controllers/organisation/mission_controller.rb b/app/controllers/organisation/mission_controller.rb
index d6e4b30e0..8dd83437b 100644
--- a/app/controllers/organisation/mission_controller.rb
+++ b/app/controllers/organisation/mission_controller.rb
@@ -10,6 +10,8 @@ def update
logger.info "Updating mission for organisation ID: #{@organisation.id}"
+ ensure_mission_params
+
@organisation.validate_mission = true
@organisation.update(organisation_params)
@@ -40,4 +42,20 @@ def organisation_params
end
+ # This method ensures that if no mission is chosen by the user
+ # the mission array is set back to empty.
+ def ensure_mission_params
+
+ if params[:organisation]
+
+ params[:organisation][:mission] ||= []
+
+ else
+
+ params[:organisation] = { mission: [] }
+
+ end
+
+ end
+
end
diff --git a/spec/controllers/organisation/mission_controller_spec.rb b/spec/controllers/organisation/mission_controller_spec.rb
index d9cd985a1..7c6775e6d 100644
--- a/spec/controllers/organisation/mission_controller_spec.rb
+++ b/spec/controllers/organisation/mission_controller_spec.rb
@@ -110,6 +110,68 @@
end
+ it "should successfully update if no mission params are passed" do
+
+ put :update, params: {
+ organisation_id: subject.current_user.organisations.first.id,
+ organisation: {
+ mission: []
+ }
+ }
+
+ expect(response).to have_http_status(:redirect)
+ expect(response).to redirect_to(:organisation_summary)
+
+ expect(assigns(:organisation).errors.empty?).to eq(true)
+ expect(assigns(:organisation)
+ .mission).to eq([])
+
+ end
+
+ end
+
+ # These tests specifically test the ensure_mission_params method
+ describe '#ensure_mission_params' do
+
+ before do
+ controller.class.send(:public, :ensure_mission_params) # This makes the method available for testing as it is a private method
+ end
+
+ context 'when :organisation is present' do
+ context 'when :mission is already set' do
+ it 'does not change the mission' do
+ params = {
+ organisation: {
+ mission: ["female_led"],
+ }
+ }
+ allow(controller).to receive(:params).and_return(params)
+
+ controller.ensure_mission_params
+
+ expect(params[:organisation][:mission]).to eq(['female_led'])
+
+ end
+
+ end
+
+ end
+
+ context 'when :mission is not set' do
+ it 'sets mission to an empty array' do
+ params = {
+ organisation: {}
+ }
+ allow(controller).to receive(:params).and_return(params)
+
+ controller.ensure_mission_params
+
+ expect(params[:organisation][:mission]).to eq([])
+
+ end
+
+ end
+
end
end
From 9561121f7dc281b5e37d141809cc192ff26155c9 Mon Sep 17 00:00:00 2001
From: Eithel Anderson <48526057+etelish@users.noreply.github.com>
Date: Wed, 9 Aug 2023 14:44:11 +0100
Subject: [PATCH 06/28] added project title conditional to get main contact
apps method (#1137)
* added project title conditional to get main contact apps method
* added in a method to migrate and move application medium over 100k
---
app/helpers/admin_portal_helper.rb | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/app/helpers/admin_portal_helper.rb b/app/helpers/admin_portal_helper.rb
index fb49f2a36..11800eda7 100644
--- a/app/helpers/admin_portal_helper.rb
+++ b/app/helpers/admin_portal_helper.rb
@@ -43,6 +43,7 @@ module AdminPortalHelper
PEF = 4
EOI = 5
UNKNOWN = 6
+ MIGRATED_MEDIUM_OVER_100k = 7
# Creates an array of hashes for the applications and
# pre-applications belonging to a main applicant.
@@ -74,6 +75,16 @@ def get_main_contact_apps(org_id, user_id)
type = MEDIUM
end
+ if fa.migrated_medium_over_100k?
+ type = MIGRATED_MEDIUM_OVER_100k
+
+ salesforce_api_client= SalesforceApiClient.new
+
+ title = salesforce_api_client
+ .get_project_title(fa.salesforce_case_id)
+ .Project_Title__c
+ end
+
if fa.project.present?
title = fa.project.project_title
type = SMALL
@@ -163,6 +174,8 @@ def move_app_to_new_user(chosen_app_hash, new_contact_id, new_org_id)
move_3_to_10k(chosen_app_hash, new_contact_id, new_org_id)
when MEDIUM
move_10_to_250k(chosen_app_hash, new_contact_id, new_org_id)
+ when MIGRATED_MEDIUM_OVER_100k
+ move_migrated_medium_over_100k(chosen_app_hash, new_org_id)
when LARGE
move_large(chosen_app_hash, new_org_id)
when PEF
@@ -354,6 +367,16 @@ def move_large(chosen_app_hash, new_org_id)
end
+ # uses exactly the same as move_large for migrating medium over 100k
+ # @param [Hash] chosen_app_hash App that we are moving: example
+ # {:id=>"", :ref_no=>"", :type=>1, :title=>"", salesforce_id => ""}
+ # @param [String] new_org_id FFE GUID for new organisation
+ def move_migrated_medium_over_100k(chosen_app_hash, new_org_id)
+
+ move_large(chosen_app_hash, new_org_id)
+
+ end
+
# Moves a pre_application to a new user
# Amends pre_applications rows
# Writes audit row of changes
From 485fe9730fc6af5351d78965ea25de38f4eec7e8 Mon Sep 17 00:00:00 2001
From: Paul Trelease
Date: Thu, 10 Aug 2023 15:00:09 +0100
Subject: [PATCH 07/28] Enabled session timeout (#1138)
---
app/models/user.rb | 3 ++-
config/initializers/devise.rb | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/app/models/user.rb b/app/models/user.rb
index 698034762..7aca2fb87 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -8,7 +8,8 @@ class User < ApplicationRecord
:recoverable,
:rememberable,
:validatable,
- :confirmable
+ :confirmable,
+ :timeoutable
enum role: [:user, :admin]
after_initialize :set_default_role, :if => :new_record?
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 54103ffa1..7bcbb6883 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -175,8 +175,8 @@
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
- # time the user will be asked for credentials again. Default is 30 minutes.
- # config.timeout_in = 30.minutes
+ # time the user will be asked for credentials again.
+ config.timeout_in = 60.minutes
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
From add0a9c80fff568fcdab2d74b1389a06b80932f9 Mon Sep 17 00:00:00 2001
From: Paul Trelease
Date: Fri, 11 Aug 2023 11:42:41 +0100
Subject: [PATCH 08/28] Feature/amend longer session (#1140)
* increased timeout criteria to 20 hours
---
config/initializers/devise.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 7bcbb6883..87f400fa0 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -176,7 +176,9 @@
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again.
- config.timeout_in = 60.minutes
+ # Gone for WCAG 20 hour exception to meet level A criteria.
+ # https://www.w3.org/WAI/WCAG21/Understanding/timing-adjustable.html
+ config.timeout_in = 20.hours
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
From 27f53a02ca6bb277d149bef868073aef7051a50c Mon Sep 17 00:00:00 2001
From: Eithel Anderson <48526057+etelish@users.noreply.github.com>
Date: Fri, 11 Aug 2023 12:28:35 +0100
Subject: [PATCH 09/28] replaced email input field with label and override
update_resource method to prevent users email being updated (#1139)
---
app/controllers/user/registrations_controller.rb | 9 +++++++++
app/views/user/registrations/edit.html.erb | 7 +++----
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/app/controllers/user/registrations_controller.rb b/app/controllers/user/registrations_controller.rb
index 96ed1650f..a6cd284e9 100644
--- a/app/controllers/user/registrations_controller.rb
+++ b/app/controllers/user/registrations_controller.rb
@@ -33,5 +33,14 @@ def create_person(resource)
NotifyMailer.confirmation_instructions_copy(resource).deliver_later
end
+
+ # Override the Devise::RegistrationsController update_resource method
+ # Ensures the email is not provided as a param to prevent it being updated
+ def update_resource(resource, params)
+
+ params.delete(:email)
+
+ super
+ end
end
diff --git a/app/views/user/registrations/edit.html.erb b/app/views/user/registrations/edit.html.erb
index cfa83dd9a..1b67bdf41 100644
--- a/app/views/user/registrations/edit.html.erb
+++ b/app/views/user/registrations/edit.html.erb
@@ -45,10 +45,9 @@
<%=
- f.text_field :email,
- autofocus: true,
- autocomplete: "email",
- class: "govuk-input govuk-input--width-20"
+ f.label :email,
+ @user.email,
+ class: "govuk-label govuk-!-margin-top-2 govuk-!-font-weight-bold"
%>
From 5734e941dcbe59212b1a7809a35e8f36edfb6bf3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 21 Aug 2023 09:52:07 +0100
Subject: [PATCH 10/28] Bump semver from 5.7.1 to 5.7.2 (#1120)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)
---
updated-dependencies:
- dependency-name: semver
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
yarn.lock | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index ba5efb06b..86fa6394e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7612,19 +7612,19 @@ selfsigned@^1.10.8:
node-forge "^0.10.0"
"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.2, semver@^7.3.5:
- version "7.5.3"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
- integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
From a244c9b47db07697c32533676bc8b279fcd38e9a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 22 Aug 2023 11:07:28 +0100
Subject: [PATCH 11/28] Bump puma from 4.3.12 to 5.6.7 (#1141)
Bumps [puma](https://github.com/puma/puma) from 4.3.12 to 5.6.7.
- [Release notes](https://github.com/puma/puma/releases)
- [Changelog](https://github.com/puma/puma/blob/master/History.md)
- [Commits](https://github.com/puma/puma/compare/v4.3.12...v5.6.7)
---
updated-dependencies:
- dependency-name: puma
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
Gemfile | 2 +-
Gemfile.lock | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Gemfile b/Gemfile
index 190c3f2e3..e3336b943 100644
--- a/Gemfile
+++ b/Gemfile
@@ -17,7 +17,7 @@ gem 'lograge', '~> 0.11.2'
gem 'mail-notify', '~> 1.1.0 '
gem 'nilify_blanks', '~> 1.3'
gem 'pg', '~> 1.1'
-gem 'puma', '~> 4.3'
+gem 'puma', '~> 5.6'
gem "rails", "~> 7.0.0"
gem 'rails-i18n', '~> 7.0.5'
gem 'redis', '~> 4.1.3'
diff --git a/Gemfile.lock b/Gemfile.lock
index 0c71c1029..5f82a41c5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -257,7 +257,7 @@ GEM
method_source (~> 1.0)
psych (3.3.4)
public_suffix (5.0.1)
- puma (4.3.12)
+ puma (5.6.7)
nio4r (~> 2.0)
racc (1.7.1)
rack (2.2.7)
@@ -473,7 +473,7 @@ DEPENDENCIES
pg (~> 1.1)
pry (~> 0.14.1)
psych (< 4)
- puma (~> 4.3)
+ puma (~> 5.6)
rails (~> 7.0.0)
rails-controller-testing (~> 1.0.4)
rails-i18n (~> 7.0.5)
From 42fda8232bb04a737a3ca39f60cbde8bae4055fa Mon Sep 17 00:00:00 2001
From: Jack <91466216+JJD1990@users.noreply.github.com>
Date: Thu, 24 Aug 2023 09:39:37 +0100
Subject: [PATCH 12/28] Fix/cc no not sure (#1142)
* method created in the project model to format the cash contribution secured value
* dash taken away from not sure in format secured for salesforce method, dasherize is needed for other values to work
* added cc build and further expect to spec for x_not_sure fix
* context added to spec to test project with no cc, better formatted method description
* formatting comments and line at eof
---
app/models/project.rb | 23 ++-
spec/models/project_spec.rb | 318 ++++++++++++++++++++----------------
2 files changed, 195 insertions(+), 146 deletions(-)
diff --git a/app/models/project.rb b/app/models/project.rb
index ce0f20a1d..28c2b24a3 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -417,7 +417,7 @@ def to_salesforce_json
json.cashContributions self.cash_contributions do |cash_contribution|
json.description cash_contribution.description
json.amount cash_contribution.amount
- json.secured cash_contribution.secured&.dasherize
+ json.secured format_secured_for_salesforce(cash_contribution)
json.id cash_contribution.id
end
json.set!('organisationSalesforceAccountId',
@@ -470,4 +470,23 @@ def get_organisation_type_for_salesforce_json
end
-end
+ # Formats the secured value of a cash contribution for Salesforce.
+ #
+ # Given a cash contribution with a particular secured value, this method
+ # will either return the "not sure" string or a dasherized version of the
+ # value, depending on the original value.
+ #
+ # @param [object] cash contribution object
+ # @param [string] :secured for the answer/value of the 'is your cash
+ # contribution secured?' question
+ #
+ # @return [string] - A formatted string value. Either 'not sure' or
+ # a dasherized value
+ def format_secured_for_salesforce(cash_contribution)
+ if cash_contribution.secured == 'x_not_sure'
+ 'not sure'
+ else
+ cash_contribution.secured&.dasherize
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 2107d6c14..cb338d65c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1,40 +1,38 @@
require "rails_helper"
RSpec.describe Project, type: :model do
-
describe "Project model" do
- it "should serialise Salesforce JSON successfully" do
-
- @project = build(
- :project,
- id: "2c660111-ab15-4221-98e0-cf0e02748a9b",
- project_title: "Test Project", start_date: "1/1/2025",
- end_date: "1/10/2025", line1: "10 Downing Street",
- line2: "Westminster", townCity: "London", county: "LONDON",
- postcode: "SW1A 2AA", description: "A description of my project...",
- difference: "The difference my project will make to...",
- matter: "My project matters because...",
- best_placed_description: "My organisation is best placed to...",
- heritage_description: "The heritage of my project...",
- involvement_description: "My project will involve a wider range of " \
- "people...",
- outcome_2: true, outcome_3: false, outcome_4: true, outcome_5: false,
- outcome_6: true, outcome_7: false, outcome_8: true, outcome_9: false,
- outcome_2_description: "Description of outcome 2",
- outcome_3_description: "",
- outcome_4_description: "Description of outcome 4",
- outcome_5_description: "",
- outcome_6_description: "Description of outcome 6",
- outcome_7_description: "",
- outcome_8_description: "Description of outcome 8",
- outcome_9_description: "", permission_type: 2,
- permission_description: "permission description",
- partnership_details: "partnership details",
- declaration_reasons_description: "something"
- )
+ before do
+ @project = build(
+ :project,
+ id: "2c660111-ab15-4221-98e0-cf0e02748a9b",
+ project_title: "Test Project", start_date: "1/1/2025",
+ end_date: "1/10/2025", line1: "10 Downing Street",
+ line2: "Westminster", townCity: "London", county: "LONDON",
+ postcode: "SW1A 2AA", description: "A description of my project...",
+ difference: "The difference my project will make to...",
+ matter: "My project matters because...",
+ best_placed_description: "My organisation is best placed to...",
+ heritage_description: "The heritage of my project...",
+ involvement_description: "My project will involve a wider range of " \
+ "people...",
+ outcome_2: true, outcome_3: false, outcome_4: true, outcome_5: false,
+ outcome_6: true, outcome_7: false, outcome_8: true, outcome_9: false,
+ outcome_2_description: "Description of outcome 2",
+ outcome_3_description: "",
+ outcome_4_description: "Description of outcome 4",
+ outcome_5_description: "",
+ outcome_6_description: "Description of outcome 6",
+ outcome_7_description: "",
+ outcome_8_description: "Description of outcome 8",
+ outcome_9_description: "", permission_type: 2,
+ permission_description: "permission description",
+ partnership_details: "partnership details",
+ declaration_reasons_description: "something"
+ )
- organisation = build(
+ organisation = build(
:organisation,
name: "Test Organisation",
org_type: 5,
@@ -50,120 +48,152 @@
@project.user.organisations.append(organisation)
- project_salesforce_json = JSON.parse(@project.to_salesforce_json)
-
- # Assert metadata parameters
- expect(project_salesforce_json['meta']['applicationId'])
- .to eq("2c660111-ab15-4221-98e0-cf0e02748a9b")
- expect(project_salesforce_json['meta']['username'])
- .to eq(@project.user.email)
-
- # Assert main contact parameters
- expect(project_salesforce_json['application']['mainContactName'])
- .to eq("Joe Bloggs")
- expect(project_salesforce_json['application']['mainContactDateOfBirth'])
- .to eq("1980-01-01")
- expect(project_salesforce_json['application']['mainContactPhone'])
- .to eq("07123456789")
- expect(project_salesforce_json['application']['mainContactEmail'])
- .to eq(@project.user.email)
- expect(project_salesforce_json['application']['mainContactAddress']['line1'])
- .to eq("10 Downing Street, Westminster")
- expect(project_salesforce_json['application']['mainContactAddress']['townCity'])
- .to eq("London")
- expect(project_salesforce_json['application']['mainContactAddress']['county'])
- .to eq("LONDON")
- expect(project_salesforce_json['application']['mainContactAddress']['postcode'])
- .to eq("SW1A 2AA")
-
- # Assert organisation parameters
- expect(project_salesforce_json['application']['organisationName'])
- .to eq("Test Organisation")
- expect(project_salesforce_json['application']['organisationType'])
- .to eq("faith-based-or-church-organisation")
- expect(project_salesforce_json['application']['organisationMission'])
- .to eq(%w(young-people-led disability-led))
- expect(project_salesforce_json['application']['charityNumber'])
- .to eq("12345")
- expect(project_salesforce_json['application']['companyNumber'])
- .to eq("54321")
- expect(project_salesforce_json['application']['organisationAddress']['line1'])
- .to eq("10 Downing Street, Westminster")
- expect(project_salesforce_json['application']['organisationAddress']['townCity'])
- .to eq("London")
- expect(project_salesforce_json['application']['organisationAddress']['county'])
- .to eq("LONDON")
- expect(project_salesforce_json['application']['organisationAddress']['postcode'])
- .to eq("SW1A 2AA")
-
- # Assert project parameters
- expect(project_salesforce_json['application']['projectName'])
- .to eq("Test Project")
- expect(project_salesforce_json['application']['projectDateRange']['startDate'])
- .to eq("2025-01-01")
- expect(project_salesforce_json['application']['projectDateRange']['endDate'])
- .to eq("2025-10-01")
- expect(project_salesforce_json['application']['projectAddress']['line1'])
- .to eq("10 Downing Street, Westminster")
- expect(project_salesforce_json['application']['projectAddress']['townCity'])
- .to eq("London")
- expect(project_salesforce_json['application']['projectAddress']['county'])
- .to eq("LONDON")
- expect(project_salesforce_json['application']['projectAddress']['projectPostcode'])
- .to eq("SW1A 2AA")
- expect(project_salesforce_json['application']['yourIdeaProject'])
- .to eq("A description of my project...")
- expect(project_salesforce_json['application']['projectDifference'])
- .to eq("The difference my project will make to...")
- expect(project_salesforce_json['application']['projectOrgBestPlace'])
- .to eq("My organisation is best placed to...")
- expect(project_salesforce_json['application']['projectAvailable'])
- .to eq("The heritage of my project...")
- expect(project_salesforce_json['application']['projectOutcome1'])
- .to eq("My project will involve a wider range of people...")
- expect(project_salesforce_json['application']['projectOutcome2'])
- .to eq("Description of outcome 2")
- expect(project_salesforce_json['application']['projectOutcome3'])
- .to eq("")
- expect(project_salesforce_json['application']['projectOutcome4'])
- .to eq("Description of outcome 4")
- expect(project_salesforce_json['application']['projectOutcome5'])
- .to eq("")
- expect(project_salesforce_json['application']['projectOutcome6'])
- .to eq("Description of outcome 6")
- expect(project_salesforce_json['application']['projectOutcome7'])
- .to eq("")
- expect(project_salesforce_json['application']['projectOutcome8'])
- .to eq("Description of outcome 8")
- expect(project_salesforce_json['application']['projectOutcome9'])
- .to eq("")
- expect(project_salesforce_json['application']['projectOutcome2Checked'])
- .to eq(true)
- expect(project_salesforce_json['application']['projectOutcome3Checked'])
- .to eq(false)
- expect(project_salesforce_json['application']['projectOutcome4Checked'])
- .to eq(true)
- expect(project_salesforce_json['application']['projectOutcome5Checked'])
- .to eq(false)
- expect(project_salesforce_json['application']['projectOutcome6Checked'])
- .to eq(true)
- expect(project_salesforce_json['application']['projectOutcome7Checked'])
- .to eq(false)
- expect(project_salesforce_json['application']['projectOutcome8Checked'])
- .to eq(true)
- expect(project_salesforce_json['application']['projectOutcome9Checked'])
- .to eq(false)
- expect(project_salesforce_json['application']['projectNeedsPermission'])
- .to eq("not-sure")
- expect(project_salesforce_json['application']['projectNeedsPermissionDetails'])
- .to eq("permission description")
- expect(project_salesforce_json['application']['partnershipDetails'])
- .to eq("partnership details")
- expect(project_salesforce_json['application']['informationNotPubliclyAvailableRequest'])
- .to eq("something")
+ end
+
+ context "with a cash contribution" do
+
+ before do
+ @cash_contribution = build(
+ :cash_contribution,
+ description: "Test Contribution",
+ amount: 1000,
+ secured: 'x_not_sure'
+ )
+
+ @project.cash_contributions << @cash_contribution
+
+ @project_salesforce_json = JSON.parse(@project.to_salesforce_json)
+
+ end
+ it "should serialize Salesforce JSON successfully" do
+ # Assert metadata parameters
+ expect(@project_salesforce_json['meta']['applicationId'])
+ .to eq("2c660111-ab15-4221-98e0-cf0e02748a9b")
+ expect(@project_salesforce_json['meta']['username'])
+ .to eq(@project.user.email)
+
+ # Assert main contact parameters
+ expect(@project_salesforce_json['application']['mainContactName'])
+ .to eq("Joe Bloggs")
+ expect(@project_salesforce_json['application']['mainContactDateOfBirth'])
+ .to eq("1980-01-01")
+ expect(@project_salesforce_json['application']['mainContactPhone'])
+ .to eq("07123456789")
+ expect(@project_salesforce_json['application']['mainContactEmail'])
+ .to eq(@project.user.email)
+ expect(@project_salesforce_json['application']['mainContactAddress']['line1'])
+ .to eq("10 Downing Street, Westminster")
+ expect(@project_salesforce_json['application']['mainContactAddress']['townCity'])
+ .to eq("London")
+ expect(@project_salesforce_json['application']['mainContactAddress']['county'])
+ .to eq("LONDON")
+ expect(@project_salesforce_json['application']['mainContactAddress']['postcode'])
+ .to eq("SW1A 2AA")
+
+ # Assert organisation parameters
+ expect(@project_salesforce_json['application']['organisationName'])
+ .to eq("Test Organisation")
+ expect(@project_salesforce_json['application']['organisationType'])
+ .to eq("faith-based-or-church-organisation")
+ expect(@project_salesforce_json['application']['organisationMission'])
+ .to eq(%w(young-people-led disability-led))
+ expect(@project_salesforce_json['application']['charityNumber'])
+ .to eq("12345")
+ expect(@project_salesforce_json['application']['companyNumber'])
+ .to eq("54321")
+ expect(@project_salesforce_json['application']['organisationAddress']['line1'])
+ .to eq("10 Downing Street, Westminster")
+ expect(@project_salesforce_json['application']['organisationAddress']['townCity'])
+ .to eq("London")
+ expect(@project_salesforce_json['application']['organisationAddress']['county'])
+ .to eq("LONDON")
+ expect(@project_salesforce_json['application']['organisationAddress']['postcode'])
+ .to eq("SW1A 2AA")
+
+ # Assert project parameters
+ expect(@project_salesforce_json['application']['projectName'])
+ .to eq("Test Project")
+ expect(@project_salesforce_json['application']['projectDateRange']['startDate'])
+ .to eq("2025-01-01")
+ expect(@project_salesforce_json['application']['projectDateRange']['endDate'])
+ .to eq("2025-10-01")
+ expect(@project_salesforce_json['application']['projectAddress']['line1'])
+ .to eq("10 Downing Street, Westminster")
+ expect(@project_salesforce_json['application']['projectAddress']['townCity'])
+ .to eq("London")
+ expect(@project_salesforce_json['application']['projectAddress']['county'])
+ .to eq("LONDON")
+ expect(@project_salesforce_json['application']['projectAddress']['projectPostcode'])
+ .to eq("SW1A 2AA")
+ expect(@project_salesforce_json['application']['yourIdeaProject'])
+ .to eq("A description of my project...")
+ expect(@project_salesforce_json['application']['projectDifference'])
+ .to eq("The difference my project will make to...")
+ expect(@project_salesforce_json['application']['projectOrgBestPlace'])
+ .to eq("My organisation is best placed to...")
+ expect(@project_salesforce_json['application']['projectAvailable'])
+ .to eq("The heritage of my project...")
+ expect(@project_salesforce_json['application']['projectOutcome1'])
+ .to eq("My project will involve a wider range of people...")
+ expect(@project_salesforce_json['application']['projectOutcome2'])
+ .to eq("Description of outcome 2")
+ expect(@project_salesforce_json['application']['projectOutcome3'])
+ .to eq("")
+ expect(@project_salesforce_json['application']['projectOutcome4'])
+ .to eq("Description of outcome 4")
+ expect(@project_salesforce_json['application']['projectOutcome5'])
+ .to eq("")
+ expect(@project_salesforce_json['application']['projectOutcome6'])
+ .to eq("Description of outcome 6")
+ expect(@project_salesforce_json['application']['projectOutcome7'])
+ .to eq("")
+ expect(@project_salesforce_json['application']['projectOutcome8'])
+ .to eq("Description of outcome 8")
+ expect(@project_salesforce_json['application']['projectOutcome9'])
+ .to eq("")
+ expect(@project_salesforce_json['application']['projectOutcome2Checked'])
+ .to eq(true)
+ expect(@project_salesforce_json['application']['projectOutcome3Checked'])
+ .to eq(false)
+ expect(@project_salesforce_json['application']['projectOutcome4Checked'])
+ .to eq(true)
+ expect(@project_salesforce_json['application']['projectOutcome5Checked'])
+ .to eq(false)
+ expect(@project_salesforce_json['application']['projectOutcome6Checked'])
+ .to eq(true)
+ expect(@project_salesforce_json['application']['projectOutcome7Checked'])
+ .to eq(false)
+ expect(@project_salesforce_json['application']['projectOutcome8Checked'])
+ .to eq(true)
+ expect(@project_salesforce_json['application']['projectOutcome9Checked'])
+ .to eq(false)
+ expect(@project_salesforce_json['application']['projectNeedsPermission'])
+ .to eq("not-sure")
+ expect(@project_salesforce_json['application']['projectNeedsPermissionDetails'])
+ .to eq("permission description")
+ expect(@project_salesforce_json['application']['partnershipDetails'])
+ .to eq("partnership details")
+ expect(@project_salesforce_json['application']['informationNotPubliclyAvailableRequest'])
+ .to eq("something")
+ expect(@project_salesforce_json['application']['cashContributions'][0]['description'])
+ .to eq("Test Contribution")
+ expect(@project_salesforce_json['application']['cashContributions'][0]['amount'])
+ .to eq(1000)
+ expect(@project_salesforce_json['application']['cashContributions'][0]['secured'])
+ .to eq('not sure')
+ end
end
- end
+ context "without a cash contribution" do
+ before do
+ @project_salesforce_json = JSON.parse(@project.to_salesforce_json)
+ end
-end
+ it "should serialise a project without cash contributions Salesforce JSON successfully" do
+ expect(@project_salesforce_json['application']['cashContributions']).to eq([])
+ end
+ end
+
+ end
+end
\ No newline at end of file
From 6ef4cc86d5f97123d207510b1021a9831ddc0d41 Mon Sep 17 00:00:00 2001
From: Jack <91466216+JJD1990@users.noreply.github.com>
Date: Wed, 20 Sep 2023 11:51:48 +0100
Subject: [PATCH 13/28] inital regex alteration to enforce domains in email
validation (#1146)
* inital regex alteration to enforce domains in email validation
* add tests for legal sig regex and registration
* tests written for email validation, legal sig model and user model
* comments added to explain regex in devise.rb and legalsig model
* deleted end of file extra lines
* misunderstanding, added EOF lines back in!
* eof line to user_spec
* took out debugging comments in user_spec
---------
Co-authored-by: eithel
---
app/models/legal_signatory.rb | 4 +-
config/initializers/devise.rb | 7 +-
.../second_signatory_controller_spec.rb | 26 ++++++
.../users/registrations_controller_spec.rb | 1 +
spec/models/legal_signatory_spec.rb | 86 +++++++++++++++++++
spec/models/user_spec.rb | 25 +++++-
6 files changed, 145 insertions(+), 4 deletions(-)
create mode 100644 spec/models/legal_signatory_spec.rb
diff --git a/app/models/legal_signatory.rb b/app/models/legal_signatory.rb
index 663808aab..b2b368574 100644
--- a/app/models/legal_signatory.rb
+++ b/app/models/legal_signatory.rb
@@ -14,8 +14,10 @@ class LegalSignatory < ApplicationRecord
validates :name, length: { minimum: 1, maximum: 80 }
+ # the custom regex below ensures that a domain
+ # is present and also allows tags.
validates :email_address,
- format: { with: URI::MailTo::EMAIL_REGEXP }
+ format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
def validate_role?
validate_role == true
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 87f400fa0..62660d6a6 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -171,7 +171,12 @@
# Email regex used to validate email formats. It simply asserts that
# one (and only one) @ exists in the given string. This is mainly
# to give user feedback and not to assert the e-mail validity.
- config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
+ # original email_regexp /\A[^@\s]+@[^@\s]+\z/
+
+ # a custom regex has now been added below, this ensures that a domain
+ # is present and also allows tags.
+ config.email_regexp =/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
+
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
diff --git a/spec/controllers/funding_application/legal_agreements/second_signatory_controller_spec.rb b/spec/controllers/funding_application/legal_agreements/second_signatory_controller_spec.rb
index 840ab04ad..c4bbb46ef 100644
--- a/spec/controllers/funding_application/legal_agreements/second_signatory_controller_spec.rb
+++ b/spec/controllers/funding_application/legal_agreements/second_signatory_controller_spec.rb
@@ -157,6 +157,32 @@
end
+ it "should raise email error based on invalid email validation " \
+ "when email without a domain is passed" do
+
+ put :update,
+ params: {
+ application_id: @funding_application.id,
+ legal_signatory:{
+ name: "John Smith",
+ email_address: "john@smith",
+ role: "Trustee"
+ }
+ }
+
+ expect(response).to have_http_status(:success)
+ expect(response).to render_template(:show)
+
+ expect(assigns(:funding_application).errors.empty?).to eq(false)
+
+ expect(assigns(:funding_application).errors.count)
+ .to eq(1)
+
+ expect(assigns(:funding_application).errors[:"legal_signatories.email_address"][0])
+ .to eq("Enter a valid email address")
+
+ end
+
it "should raise email error based matching email address of " \
"legal signatory 1 and legal signatory 2" do
diff --git a/spec/controllers/users/registrations_controller_spec.rb b/spec/controllers/users/registrations_controller_spec.rb
index 42751beed..9d2c42108 100644
--- a/spec/controllers/users/registrations_controller_spec.rb
+++ b/spec/controllers/users/registrations_controller_spec.rb
@@ -30,4 +30,5 @@
subject.create_person(resource)
end
end
+
end
diff --git a/spec/models/legal_signatory_spec.rb b/spec/models/legal_signatory_spec.rb
new file mode 100644
index 000000000..e02272938
--- /dev/null
+++ b/spec/models/legal_signatory_spec.rb
@@ -0,0 +1,86 @@
+require "rails_helper"
+
+RSpec.describe LegalSignatory, type: :model do
+ subject { build(:legal_signatory) }
+
+ context "Validations" do
+ it "validates the length of role" do
+ subject.role = 'a' * 81
+ expect(subject.valid?).to be_falsey
+ expect(subject.errors[:role]).to include("The role of the legal signatory must be fewer than 80 characters")
+
+ subject.role = ''
+ expect(subject.valid?).to be_falsey
+ expect(subject.errors[:role]).to include("Enter the role of a legal signatory")
+
+ subject.role = 'Valid Role'
+ expect(subject.valid?).to be_truthy
+ end
+
+ it "validates the length of name" do
+ subject.name = 'a' * 81
+ expect(subject.valid?).to be_falsey
+ expect(subject.errors[:name]).to include("The name of the legal signatory must be fewer than 80 characters")
+
+ subject.name = ''
+ expect(subject.valid?).to be_falsey
+ expect(subject.errors[:name]).to include("Enter the name of a legal signatory")
+
+ subject.name = 'Valid Name'
+ expect(subject.valid?).to be_truthy
+ end
+ end
+
+ describe "Legal model" do
+
+ let (:resource) {
+ create(
+ :legal_signatory,
+ id: 1,
+ email_address: 'a@f.com',
+ role: 'role'
+ )
+ }
+
+ context "when email is invalid" do
+ let(:invalid_emails) { ['invalid', 'invalid@', 'invalid@.com', '@invalid.com', 'invalid@invalid'] }
+
+ it "should be invalid" do
+ invalid_emails.each do |email|
+ resource.email_address = email
+ expect(resource.valid?).to eq(false)
+ end
+ end
+ end
+
+ context "when email is valid" do
+ let(:valid_emails) { ['valid@example.com', 'valid.name@example.com', 'valid.name+tag@example.co.uk', 'valid-name@example.co.uk'] }
+
+ it "should be valid" do
+ valid_emails.each do |email|
+ resource.email_address = email
+ unless resource.valid?
+ puts "Validation failed for email #{email}"
+ puts resource.errors.full_messages
+ end
+ expect(resource.valid?).to eq(true)
+ end
+ end
+ end
+
+ describe "Conditionally validating email_address" do
+ it "should validate email_address when validate_email_address is set to true" do
+ subject.validate_email_address = true
+ expect(subject.validate_email_address?).to eq(true)
+ end
+ end
+
+ describe "Conditionally validating phone number" do
+ it "should validate phone number when validate_phone_number is set to true" do
+ subject.validate_phone_number = true
+ expect(subject.validate_phone_number?).to eq(true)
+ end
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 002e853f8..44d277813 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -92,9 +92,30 @@
expect(resource.send_english_mails?).to eq(true)
expect(resource.send_welsh_mails?).to eq(false)
expect(resource.send_bilingual_mails?).to eq(false)
+ end
- end
- end
+ context "when email is invalid" do
+ let(:invalid_emails) { ['invalid', 'invalid@', 'invalid@.com', '@invalid.com', 'invalid@invalid'] }
+
+ it "should be invalid" do
+ invalid_emails.each do |email|
+ resource.email = email
+ expect(resource.valid?).to eq(false)
+ end
+ end
+ end
+ context "when email is valid" do
+ let(:valid_emails) { ['valid@example.com', 'valid.name@example.com', 'valid.name+tag@example.co.uk', 'valid-name@example.co.uk'] }
+
+ it "should be valid" do
+ valid_emails.each do |email|
+ resource.email = email
+ expect(resource.valid?).to eq(true)
+ end
+ end
+ end
+
+ end
end
From 82020dcd2e68034673b28d31ee707ab88da77b1a Mon Sep 17 00:00:00 2001
From: Jack <91466216+JJD1990@users.noreply.github.com>
Date: Mon, 25 Sep 2023 12:31:47 +0100
Subject: [PATCH 14/28] Feature/create ogranisation model spec (#1148)
* feat/create org spec
* context for empty address fields with error tests added
* add org type tests
* rearranged tests in oragnisation spec, added invalid org type test
* taken contexts out, used factory organisations
* test org mission validation
* refactored spec, configured org factory to allow test suite to run properly, added further organisation tests
* all organisation tests added to file, need to refactor further
* refactored organisation factory and references
* organisation_spec refactored
* association tests added to organisation spec
* comment added about shoulda gem
* added EOF lines
---------
Co-authored-by: eithel
---
spec/factories/organisations.rb | 68 ++++-
spec/models/organisation_spec.rb | 426 ++++++++++++++++++++++++++++++-
2 files changed, 481 insertions(+), 13 deletions(-)
diff --git a/spec/factories/organisations.rb b/spec/factories/organisations.rb
index 6e52c882b..e9a3722d4 100644
--- a/spec/factories/organisations.rb
+++ b/spec/factories/organisations.rb
@@ -1,7 +1,69 @@
FactoryBot.define do
- factory :organisation do |f|
-
+ # This blank :organisation is used throughout the test suite
+ # best not to change it without knowing where its used.
+ factory :organisation do
end
-end
+ # Everything below and including this organisation model is
+ # used within the organisation_spec.rb.
+ trait :organisation_model do
+ id { SecureRandom.uuid }
+ created_at { Time.current }
+ updated_at { Time.current }
+ line1 { "123 Main Street" }
+ line2 { "Flat 3" }
+ line3 { "Third Floor" }
+ townCity { "Plymouth" }
+ county { "Devon" }
+ postcode { "PL1 3TT" }
+ org_type { 0 }
+ company_number { "COMP12345" }
+ charity_number { "CHAR12345" }
+ charity_number_ni { 7890 }
+ mission { ["black_or_minority_ethnic_led"] }
+ salesforce_account_id { "sf-123456789" }
+ custom_org_type { "CustomType" }
+ main_purpose_and_activities { "Main purpose and activities text" }
+ spend_in_last_financial_year { 1000.00 }
+ unrestricted_funds { 500.00 }
+ board_members_or_trustees { 5 }
+ vat_registered { true }
+ vat_number { "GB123456789" }
+ social_media_info { "Follow us on Twitter @test_org" }
+ end
+
+ # A trait to allow testing of blank attributes
+ #that must be present.
+ trait :blank_organisation do
+ after(:build) do |org|
+ org.validate_name = true
+ org.validate_address = true
+ org.validate_org_type = true
+ end
+
+ org_type { nil }
+ custom_org_type { nil }
+ name { nil }
+ line1 { nil }
+ townCity { nil }
+ county { nil }
+ postcode { nil }
+ main_purpose_and_activities { nil }
+ end
+
+ trait :valid_organisation do
+ name { 'A' * 255 }
+ end
+
+ trait :invalid_organisation do
+ name { 'A' * 256 }
+ end
+
+ trait :invalid_mission do
+ mission { ["invalid_value1", "invalid_value2", "black_or_minority_ethnic_led" ] }
+ validate_mission {true}
+ end
+
+ end
+
\ No newline at end of file
diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb
index 5a741cda0..f386fc110 100644
--- a/spec/models/organisation_spec.rb
+++ b/spec/models/organisation_spec.rb
@@ -1,17 +1,423 @@
require 'rails_helper'
RSpec.describe Organisation, type: :model do
- let(:valid_organisation_1) { Organisation.new(name: 'A' * 255) }
- let(:valid_organisation_2) { Organisation.new(name: 'A' * 100) }
- let(:invalid_organisation) { Organisation.new(name: 'A' * 256) }
+ subject {build(:organisation)}
+ let(:valid_organisation) { build(:organisation, :organisation_model, :valid_organisation) }
+ let(:invalid_mission_organisation) { build(:organisation, :organisation_model, :invalid_organisation, :invalid_mission) }
+ let(:blank_organisation) { build(:organisation, :organisation_model, :blank_organisation) }
+ let(:not_vat_registered_org) { build(:organisation, :organisation_model, vat_registered: false, validate_vat_registered: true) }
+ let(:invalid_vat_registered_org) { build(:organisation, :organisation_model, vat_registered: nil, validate_vat_registered: true) }
+ let(:custom_org_type_blank) { build(:organisation, :organisation_model, custom_org_type: nil, validate_custom_org_type: true) }
- it 'validates length of name to be less than or equal to 255 characters' do
- expect(invalid_organisation.valid?).to be(false)
- expect(invalid_organisation.errors[:name]).to include("Organisation name must be 255 characters or fewer")
+ # Set the state of the organisations to ensure any error
+ # messages are there to be seen in the tests.
+ before do
+ blank_organisation.valid?
end
- it 'is valid when organisation name is equal to or below 255 characters' do
- expect(valid_organisation_1.valid?).to be(true)
- expect(valid_organisation_2.valid?).to be(true)
+ # create a hash of attributes/fields that should have presence
+ # of errors.
+ describe "Validation of mandatory fields" do
+ fields_with_presence_errors = {
+ name: 'Enter the name of your organisation',
+ line1: "Enter the first line of your organisation's address",
+ townCity: "Enter the town or city where your organisation is located",
+ county: "Enter the county where your organisation is located",
+ postcode: "Enter the postcode where your organisation is located",
+ org_type: "Select the type of organisation that will be running your project"
+ }
+
+ # Loop through each field to check they have an error
+ # and that the error matches what it should be.
+ fields_with_presence_errors.each do |field, message|
+ it "is invalid without a #{field}" do
+ blank_organisation[field] = nil
+ expect(blank_organisation.valid?).to be(false)
+ expect(blank_organisation.errors[field]).to include(message)
+ end
+ end
+ end
+
+ # create a hash of attributes/fields that should have length limits
+ # with their error message.
+ describe "Validation of length for relevant fields" do
+ length_fields = {
+ name: [255, "Organisation name must be 255 characters or fewer"],
+ company_number: [20, "Company number must be 20 characters or fewer"],
+ charity_number: [20, "Charity number must be 20 characters or fewer. For example 1234567 in England and Wales, SC000123 in Scotland, or 10000-0 in Northern Ireland"],
+ vat_number: [[9, 12], "Enter the VAT number of your organisation in the correct format"]
+ }
+
+ # Loop through each field to check they have an error
+ # and that the error matches what it should be.
+ length_fields.each do |field, details|
+ max_length, message = details
+
+ it "validates length of #{field} to be within valid constraints" do
+ expect(valid_organisation.valid?).to be(true)
+
+ if max_length.is_a?(Array)
+ # For VAT number, we have a range.
+ min_len, max_len = max_length
+ too_long = build(:organisation, field => 'A' * (max_len + 1))
+ too_short = build(:organisation, field => 'A' * (min_len - 1))
+
+ if field == :vat_number
+ too_long.validate_vat_number = true
+ too_short.validate_vat_number = true
+ end
+
+ expect(too_long.valid?).to be(false)
+ expect(too_short.valid?).to be(false)
+ expect(too_long.errors[field]).to include(message)
+ expect(too_short.errors[field]).to include(message)
+
+ else
+ too_long = build(:organisation, field => 'A' * (max_length + 1))
+
+ if field == :company_number
+ too_long.validate_company_number = true
+ elsif field == :charity_number
+ too_long.validate_charity_number = true
+ end
+
+ expect(too_long.valid?).to be(false)
+ expect(too_long.errors[field]).to include(message)
+ end
+ end
+ end
+ end
+
+ # org_type tests
+ describe "validation or org_type" do
+ it 'has a valid org type' do
+ expect(valid_organisation.valid?).to be(true)
+ expect(blank_organisation.errors[:org_type]).to include("Select the type of organisation that will be running your project")
+ end
+
+ it 'validates the presence of org_type when org_type is blank' do
+ expect(blank_organisation.valid?).to be(false)
+ expect(blank_organisation.errors[:org_type]).to include("Select the type of organisation that will be running your project")
+ end
+
+ it 'validates the org_type with the correct enum' do
+ valid_org_type = build(:organisation, org_type: 3)
+ expect(valid_org_type.org_type).to eq("community_interest_company")
+ end
+
+ it 'should allow organization types within the range 0 to 11' do
+ (0..11).each do |org_type|
+ valid_org = build(:organisation, org_type: org_type)
+ expect(valid_org.valid?).to be(true), "Expected organization type #{org_type} to be valid, but got errors: #{valid_org.errors[:org_type].join(', ')}"
+ end
+ end
+
+ # We are testing an enum, so should recieve an ArgumentError.
+ it 'should raise an ArgumentError for invalid organization types' do
+ invalid_org_types = [-1, 12, 200, "invalid"]
+ invalid_org_types.each do |org_type|
+ expect { subject.org_type = org_type }.to raise_error(ArgumentError), "Expected an ArgumentError to be raised for org_type #{org_type.inspect}, but it wasn't."
+ end
+ end
+ end
+
+ # testing custom_org_type
+ describe "Validation of custom_org_type" do
+ it 'passes validation if custom_org_type is present when validate_custom_org_type is true' do
+ expect(valid_organisation.valid?).to be(true)
+ end
+
+ it 'fails validation if custom_org_type is blank when validate_custom_org_type is true' do
+ blank_organisation.validate_custom_org_type = true
+ expect(blank_organisation.valid?).to be(false)
+ expect(blank_organisation.errors[:custom_org_type]).to include("Specify your organisation type")
+ end
+
+ it 'passes validation regardless of custom_org_type value when validate_custom_org_type is false' do
+ custom_org_type_blank.validate_custom_org_type = false
+ expect(custom_org_type_blank.valid?).to be(true)
+ end
+ end
+
+ # mission tests - here we test the validate_mission_array method
+ describe "Validation of mission and mission_array" do
+ it 'validates the mission with the correct value ' do
+ expect(valid_organisation.mission).to eq(["black_or_minority_ethnic_led"])
+ expect(invalid_mission_organisation.valid?).to be(false)
+ end
+
+ it 'adds no error when mission contains only valid values' do
+ valid_organisation.mission = ["black_or_minority_ethnic_led", "female_led"]
+ valid_organisation.valid?
+ expect(valid_organisation.errors[:mission]).to be_empty
+ end
+
+ it "adds an error when mission contains an invalid value" do
+ invalid_mission_organisation.valid?
+ expect(invalid_mission_organisation.errors[:mission]).to include("invalid_value1 is not a valid selection")
+ end
+
+ it "adds multiple errors when mission contains multiple invalid values" do
+ invalid_mission_organisation = Organisation.new(
+ mission: ["invalid_value1", "invalid_value2"],
+ validate_mission: true
+ )
+ invalid_mission_organisation.valid?
+ expect(invalid_mission_organisation.errors[:mission]).to include("invalid_value1 is not a valid selection", "invalid_value2 is not a valid selection")
+ end
+
+ it 'adds no errors when mission is nil' do
+ expect(blank_organisation.errors[:mission]).to be_empty
+ end
+
+ it 'adds no errors when mission is an empty array' do
+ blank_organisation.mission = []
+ blank_organisation.valid?
+ expect(blank_organisation.errors[:mission]).to be_empty
+ end
+ end
+
+ # More complex tests to assert the validate_length methods work
+ # via a loop
+ describe "Test the validate_length methods" do
+ [
+ [:main_purpose_and_activities, 'activerecord.errors.models.organisation.attributes.main_purpose_and_activities.too_long'],
+ [:social_media_info, 'activerecord.errors.models.organisation.attributes.social_media_info.too_long']
+ ].each do |attribute, translation_key|
+ it "validates the length of #{attribute}, must be 500 characters or fewer" do
+ subject.send("validate_#{attribute}=", true)
+ subject.send("#{attribute}=", "A " * 501)
+ subject.valid?
+
+ expect(subject.errors[attribute]).to include(
+ I18n.t(
+ translation_key,
+ word_count: 500
+ )
+ )
+ end
+ end
+ end
+
+ # tests for board_members_or_trustees, main_purpose_and_activities
+ # spend_in_last_financial_year and unrestricted_funds
+ # Iterate through each set of test data for different attributes.
+ # Each set of test data consists of an attribute and an array of test cases.
+ describe "More complex validations for attributes" do
+ [
+ {
+ attribute: :board_members_or_trustees, # The attribute to be tested
+ cases: [
+ # Array of test cases, each containing a value to test and the expected error message.
+ { value: -1, error: "Enter an amount greater than -1" },
+ { value: "Twenty One", error: "Number of board members or trustees must be a number" },
+ { value: 2147483648, error: "Enter an amount less than 2147483648" },
+ { value: nil, error: nil }
+ ]
+ },
+ {
+ attribute: :main_purpose_and_activities,
+ cases: [
+ { value: nil, error: "Enter your organisation's main purpose or activities" },
+ { value: "Some Activities", error: nil }
+ ]
+ },
+ {
+ attribute: :spend_in_last_financial_year,
+ cases: [
+ { value: 0, error: "Enter an amount greater than 0" },
+ { value: "Ninety Pound", error: "Must be a number, like 500" },
+ { value: nil, error: nil },
+ { value: 900000, error: nil }
+ ]
+ },
+ {
+ attribute: :unrestricted_funds,
+ cases: [
+ { value: 0, error: "Enter an amount greater than 0" },
+ { value: "Ninety Thousand Pounds", error: "Level of unrestricted funds must be a number" },
+ { value: nil, error: nil },
+ { value: 900000, error: nil }
+ ]
+ }
+ ].each do |test_data|
+ attribute = test_data[:attribute]
+ cases = test_data[:cases]
+
+ # Testing when the corresponding validate flag for the attribute is true
+ context "when validate_#{attribute} is true" do
+ before { subject.send("validate_#{attribute}=", true) }
+
+ # Iterate through each case and apply the test
+ cases.each do |test_case|
+ it "handles value: #{test_case[:value]}" do
+ subject.send("#{attribute}=", test_case[:value])
+
+ # Validate the subject and compare with the expected outcome
+ expect(subject.valid?).to eq(test_case[:error].nil?)
+
+ # Check for error messages if any are expected
+ if test_case[:error]
+ expect(subject.errors[attribute]).to include(test_case[:error])
+ else
+ expect(subject.errors[attribute]).to be_empty
+ end
+ end
+ end
+ end
+
+ describe "Conditional Validation of Attributes" do
+ # Testing when the corresponding validate flag for the attribute is false
+ context "when validate_#{attribute} is false" do
+ before { subject.send("validate_#{attribute}=", false) }
+
+ cases.each do |test_case|
+ it "skips validation for value: #{test_case[:value]}" do
+ subject.send("#{attribute}=", test_case[:value])
+ expect(subject.valid?).to be(true)
+ expect(subject.errors[attribute]).to be_empty
+ end
+ end
+ end
+ end
+ end
+
+ end
+
+ # Tests inclusion of vat_registered
+ describe "VAT Registered Validations" do
+ it 'fails validation if vat_registered is neither true or false when validate_vat_registered is true' do
+ expect(invalid_vat_registered_org.valid?).to be(false)
+ expect(invalid_vat_registered_org.errors[:vat_registered]).to include("Select an option to tell us whether your organisation is VAT registered")
+ end
+
+ it 'passes validation if vat_registered is true when validate_vat_registered is true' do
+ expect(valid_organisation.valid?).to be(true)
+ end
+
+ it 'passes validation if vat_registered is false when validate_vat_registered is true' do
+ expect(not_vat_registered_org.valid?).to be(true)
+ end
+
+ it 'passes validation regardless of vat_registered value when validate_vat_registered is false' do
+ invalid_vat_registered_org.validate_vat_registered = false
+ expect(invalid_vat_registered_org.valid?).to be(true)
+ end
+ end
+
+ # Tests that the validate_xyz? methods work
+ describe "Conditionally validating fields" do
+ fields_to_validate = [
+ :name,
+ :org_type,
+ :custom_org_type,
+ :address,
+ :mission,
+ :main_purpose_and_activities,
+ :board_members_or_trustees,
+ :vat_registered,
+ :vat_number,
+ :company_number,
+ :charity_number,
+ :social_media_info,
+ :spend_in_last_financial_year,
+ :unrestricted_funds
+ ]
+
+ fields_to_validate.each do |field|
+ it "should validate #{field} when validate_#{field} is set to true" do
+ subject.public_send("validate_#{field}=", true)
+ expect(subject.public_send("validate_#{field}?")).to eq(true)
+ end
+ end
end
-end
\ No newline at end of file
+
+ # Tests for Organisation associations
+ # We could use the 'shoulda' gem which tests associations
+ describe 'Associations' do
+
+ it 'can exist without pre_applications' do
+ expect(valid_organisation.pre_applications).to be_empty
+ end
+
+ it 'can have many pre_applications' do
+ pre_application1 = create(:pre_application, organisation: valid_organisation)
+ pre_application2 = create(:pre_application, organisation: valid_organisation)
+
+ expect(valid_organisation.pre_applications).to include(pre_application1, pre_application2)
+ end
+
+ it 'can exist without a funding_applications' do
+ expect(valid_organisation.funding_applications).to be_empty
+ end
+
+ it 'can have many funding_applications' do
+ funding_application1 = create(:funding_application, organisation: valid_organisation)
+ funding_application2 = create(:funding_application, organisation: valid_organisation)
+
+ expect(valid_organisation.funding_applications).to include(funding_application1, funding_application2)
+ end
+
+ it 'can exist without organisations_org_types' do
+ expect(valid_organisation.organisations_org_types).to be_empty
+ end
+
+ it 'can have many organisations_org_types' do
+ organisation = Organisation.create!()
+
+ org_type_1 = OrgType.create!(id: SecureRandom.uuid, created_at: DateTime.now, updated_at: DateTime.now)
+ org_type_2 = OrgType.create!(id: SecureRandom.uuid, created_at: DateTime.now, updated_at: DateTime.now)
+
+ organisations_org_type_1 = OrganisationsOrgType.create!(id: SecureRandom.uuid, organisation: organisation, org_type: org_type_1, created_at: DateTime.now, updated_at: DateTime.now)
+ organisations_org_type_2 = OrganisationsOrgType.create!(id: SecureRandom.uuid, organisation: organisation, org_type: org_type_2, created_at: DateTime.now, updated_at: DateTime.now)
+
+ expect(organisation.organisations_org_types).to include(organisations_org_type_1, organisations_org_type_2)
+ end
+
+ it 'can have many org_types through organisations_org_types' do
+ organisation = Organisation.create!()
+
+ org_type1 = OrgType.create!()
+ org_type2 = OrgType.create!()
+
+ OrganisationsOrgType.create!(organisation: organisation, org_type: org_type1)
+ OrganisationsOrgType.create!(organisation: organisation, org_type: org_type2)
+
+ expect(organisation.org_types).to include(org_type1, org_type2)
+ end
+
+ it 'can exist without org_types through organisations_org_types' do
+ expect(valid_organisation.org_types).to be_empty
+ end
+
+ it 'can exist without users_organisations' do
+ expect(valid_organisation.users_organisations).to be_empty
+ end
+
+ it 'can have many users_organisations' do
+ user1 = create(:user)
+ user2 = create(:user)
+
+ user_org1 = create(:users_organisation, organisation: valid_organisation, user: user1)
+ user_org2 = create(:users_organisation, organisation: valid_organisation, user: user2)
+
+ expect(valid_organisation.users_organisations).to include(user_org1, user_org2)
+ end
+
+
+ it 'can exist without users through users_organisations' do
+ expect(valid_organisation.users).to be_empty
+ end
+
+ it 'can have many users through users_organisations' do
+ user1 = create(:user)
+ user2 = create(:user)
+
+ create(:users_organisation, organisation: valid_organisation, user: user1)
+ create(:users_organisation, organisation: valid_organisation, user: user2)
+
+ expect(valid_organisation.users).to include(user1, user2)
+ end
+ end
+
+end
From 313be4efefec2f06c0904ffc7229a7842a450203 Mon Sep 17 00:00:00 2001
From: Vasili Kachalko
Date: Tue, 26 Sep 2023 12:31:03 +0200
Subject: [PATCH 15/28] modify dockerfile to use phusion passenger image
initial changes
---
Dockerfile | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
dockerfile | 50 --------------------------------
2 files changed, 84 insertions(+), 50 deletions(-)
create mode 100644 Dockerfile
delete mode 100644 dockerfile
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..388470ce1
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,84 @@
+# syntax=docker/dockerfile:1
+
+FROM phusion/passenger-ruby31:latest
+
+ENV HOME /home/app/deploy
+
+CMD ["/sbin/my_init"]
+
+# Install common dependencies
+RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
+ --mount=type=tmpfs,target=/var/log \
+ apt-get update -qq \
+ && apt-get dist-upgrade -y \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
+ curl \
+ gnupg2 \
+ less \
+ tzdata \
+ time \
+ locales \
+ && update-locale LANG=C.UTF-8 LC_ALL=C.UTF-8
+
+# Install NodeJS and Yarn
+ARG NODE_MAJOR=16
+RUN yes | apt remove nodejs
+RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
+ --mount=type=tmpfs,target=/var/log \
+ apt-get update && \
+ apt-get install -y curl software-properties-common && \
+ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
+ echo "deb https://deb.nodesource.com/node_${NODE_MAJOR}.x $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/nodesource.list && \
+ apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends nodejs
+
+ARG YARN_VERSION=latest
+RUN npm install -g yarn@$YARN_VERSION
+
+# Configure bundler
+ENV RAILS_ENV=production \
+ NODE_ENV=production \
+ BUNDLE_JOBS=4 \
+ BUNDLE_RETRY=3 \
+ BUNDLE_APP_CONFIG=/home/app/.bundle \
+ BUNDLE_PATH=/home/app/.bundle \
+ GEM_HOME=/home/app/.bundle \
+ PATH="$HOME/bin:${PATH}" \
+ LANG=C.UTF-8 \
+ LC_ALL=C.UTF-8
+
+# Upgrade RubyGems and install the latest Bundler version
+ARG BUNDLER_VERSION=2.3.11
+RUN echo "gem: --no-rdoc --no-ri >> \"$HOME/.gemrc\""
+RUN gem update --system && \
+ gem install bundler:$BUNDLER_VERSION
+
+# Create a directory for the app code
+RUN mkdir -p $HOME
+WORKDIR $HOME
+
+# Install Ruby gems
+COPY --chown=app:app Gemfile Gemfile.lock ./
+RUN bundle lock --add-platform aarch64-linux
+
+RUN mkdir $BUNDLE_PATH \
+ && bundle config --local path "${BUNDLE_PATH}" \
+ && bundle config --local without 'development test' \
+ && bundle config --local clean 'true' \
+ && bundle config --local no-cache 'true' \
+ && bundle install --jobs=${BUNDLE_JOBS} \
+ && rm -rf $BUNDLE_PATH/ruby/3.1.0/cache/* \
+ && rm -rf $HOME/.bundle/cache/*
+
+# Install JS packages
+COPY --chown=app:app package.json yarn.lock ./
+RUN yarn install --check-files
+
+RUN mkdir -p $HOME/tmp/pids
+
+COPY --chown=app:app . .
+
+# Precompile assets
+RUN SECRET_KEY_BASE=dummyvalue bundle exec rake assets:precompile
diff --git a/dockerfile b/dockerfile
deleted file mode 100644
index 9b063bfa5..000000000
--- a/dockerfile
+++ /dev/null
@@ -1,50 +0,0 @@
-ARG RUBY_VERSION=3.1.1
-
-FROM ruby:$RUBY_VERSION
-
-# Set Docker's working directory
-WORKDIR /docker/app
-
-# Install fundamentals, git, npm, node and yarn
-# This builds with a node v16.20.2 binary, so dev env needs to match that. (Github link https://github.com/nodesource/distributions )
-RUN apt-get update -qq && apt-get install -y build-essential apt-utils libpq-dev git \
- -y curl gnupg2 && \
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
- apt-get install -y nodejs && \
- npm install -g yarn
-
-# Copy these 2 files to working directory, check the
-# dependencies and node versions sync, and generate node_modules.
-COPY package.json ./
-COPY yarn.lock ./
-RUN yarn install --check-files
-
-# Install same bundler as developing with
-RUN gem install bundler -v 2.3.11
-
-# Copy generated lock to Docker's working directory and install
-COPY Gemfile Gemfile.lock ./
-RUN bundle install
-
-ADD . /docker/app
-
-# The username must have a matching user on the database.
-# The username must be set by a build argument
-# Group will have same name as username. Home directory for user created.
-ARG RAILS_RUNNING_USER
-RUN useradd --user-group --system --create-home -u 1001 --no-log-init $RAILS_RUNNING_USER
-
-# New user owns /docker/app
-RUN chown -R $RAILS_RUNNING_USER:$RAILS_RUNNING_USER /docker/app
-# /docker/app can be read, written and executed from by new user
-RUN chmod 700 /docker/app
-
-# Switch to user created above
-USER $RAILS_RUNNING_USER
-
-# Exposes port for other containers and docker desktop
-EXPOSE 3000
-
-# run rails server -b 0.0.0.0 -p 3000
-ENTRYPOINT sh ./web-entrypoint.sh
-
From bc375a11e08dce937e07f14b0b3db2f9a455f895 Mon Sep 17 00:00:00 2001
From: Vasili Kachalko
Date: Tue, 26 Sep 2023 15:33:52 +0200
Subject: [PATCH 16/28] allow to monitor both running processes
---
Dockerfile | 13 ++++++++++---
docker/puma.sh | 3 +++
docker/workers.sh | 3 +++
web-entrypoint.sh | 15 ---------------
4 files changed, 16 insertions(+), 18 deletions(-)
create mode 100644 docker/puma.sh
create mode 100644 docker/workers.sh
delete mode 100644 web-entrypoint.sh
diff --git a/Dockerfile b/Dockerfile
index 388470ce1..62664b833 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,8 +4,6 @@ FROM phusion/passenger-ruby31:latest
ENV HOME /home/app/deploy
-CMD ["/sbin/my_init"]
-
# Install common dependencies
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
@@ -81,4 +79,13 @@ RUN mkdir -p $HOME/tmp/pids
COPY --chown=app:app . .
# Precompile assets
-RUN SECRET_KEY_BASE=dummyvalue bundle exec rake assets:precompile
+
+RUN SKIP_SALESFORCE_INIT=true SKIP_FLIPPER_INIT=true SECRET_KEY_BASE=dummyvalue bundle exec rake assets:precompile
+
+RUN mkdir -p /etc/my_init.d
+COPY docker/puma.sh /etc/my_init.d/puma.sh
+COPY docker/workers.sh /etc/my_init.d/workers.sh
+
+
+CMD ["/sbin/my_init"]
+EXPOSE 3000
diff --git a/docker/puma.sh b/docker/puma.sh
new file mode 100644
index 000000000..bfc8f2149
--- /dev/null
+++ b/docker/puma.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cd /home/app/deploy && exec bundle exec rails server -b 0.0.0.0 -p 3000 >>/var/log/puma.log 2>&1
diff --git a/docker/workers.sh b/docker/workers.sh
new file mode 100644
index 000000000..4aea5d71f
--- /dev/null
+++ b/docker/workers.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cd /home/app/deploy && exec bundle exec rake jobs:work >>/var/log/workers.log 2>&1
diff --git a/web-entrypoint.sh b/web-entrypoint.sh
deleted file mode 100644
index 1bfad2659..000000000
--- a/web-entrypoint.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-# Database migration
-
-echo 'prepping database'
-
-bin/rails db:migrate
-
-# Runs rails server
-
-echo 'running server'
-
-bundle exec rake assets:precompile
-
-bundle exec rails server -b 0.0.0.0 -p 3000 & rake jobs:work
\ No newline at end of file
From 09dbb01d4a6da9095f8fc7246406c87eb6ae5374 Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Tue, 26 Sep 2023 17:37:32 +0100
Subject: [PATCH 17/28] Create .tool-versions
Makes managing ruby with asdf easier.
Setting to 3.1.4 as that is the latest secure 3.1 patch version and what CI is using.
---
.tool-versions | 1 +
1 file changed, 1 insertion(+)
create mode 100644 .tool-versions
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 000000000..306ab3370
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1 @@
+ruby 3.1.4
From 0cc33d6df3a41efed249192ff68496062e9490b2 Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Tue, 26 Sep 2023 17:45:26 +0100
Subject: [PATCH 18/28] Remove CF utils gem and fix asset compilation in docker
remove cf specific gem, fix build errors for assets compilation
- update redis url for all envs
- use ENV[""] instead of fetch without default values
- skip flipper and salesforce initialization during assets compilation
- Fix the gemfile.lock
---
Dockerfile | 1 +
Gemfile | 1 -
Gemfile.lock | 5 ++--
config/database.yml | 6 ++---
config/environments/civmiguat.rb | 36 ++++++++++++++--------------
config/environments/production.rb | 40 +++++++++++++++----------------
config/environments/research.rb | 37 ++++++++++++++--------------
config/environments/staging.rb | 36 ++++++++++++++--------------
config/environments/training.rb | 34 +++++++++++++-------------
config/environments/uat.rb | 36 ++++++++++++++--------------
config/initializers/constants.rb | 14 +++++------
config/initializers/flipper.rb | 6 ++---
web-entrypoint.sh | 13 ++++++++++
13 files changed, 139 insertions(+), 126 deletions(-)
create mode 100644 web-entrypoint.sh
diff --git a/Dockerfile b/Dockerfile
index 62664b833..a03ceceef 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -47,6 +47,7 @@ ENV RAILS_ENV=production \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8
+
# Upgrade RubyGems and install the latest Bundler version
ARG BUNDLER_VERSION=2.3.11
RUN echo "gem: --no-rdoc --no-ri >> \"$HOME/.gemrc\""
diff --git a/Gemfile b/Gemfile
index c58d3dacb..e5b6af5f5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -64,7 +64,6 @@ end
group :production, :uat, :staging, :training, :civmiguat, :research do
gem 'aws-sdk-s3', require: false
gem 'remote_syslog_logger', '~> 1.0', '>= 1.0.4'
- gem 'cf-app-utils'
gem 'delayed_job_active_record', '~> 4.1'
gem 'sentry-raven', '~> 3.1.2'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 25a017dc0..c32616723 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -110,7 +110,6 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
- cf-app-utils (0.6)
childprocess (3.0.0)
coderay (1.1.3)
coercible (1.0.0)
@@ -242,6 +241,8 @@ GEM
activerecord (>= 4.0.0)
activesupport (>= 4.0.0)
nio4r (2.5.9)
+ nokogiri (1.15.2-arm64-darwin)
+ racc (~> 1.4)
nokogiri (1.15.2-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.15.2-x86_64-linux)
@@ -448,6 +449,7 @@ GEM
zeitwerk (2.6.8)
PLATFORMS
+ arm64-darwin-23
x86_64-darwin-20
x86_64-linux
@@ -459,7 +461,6 @@ DEPENDENCIES
bundler (~> 2.3, >= 2.3.11)
byebug
capybara (>= 2.15)
- cf-app-utils
database_cleaner-active_record (~> 1.8)
delayed_job_active_record (~> 4.1)
delayed_job_web (~> 1.4)
diff --git a/config/database.yml b/config/database.yml
index e87e770ba..86023cc30 100644
--- a/config/database.yml
+++ b/config/database.yml
@@ -10,8 +10,8 @@ default: &default
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
host: <%= ENV.fetch("RAILS_PG_HOST") {"host.docker.internal"} %>
- username: <%= ENV.fetch("RAILS_PG_USERNAME")%>
- password: <%= ENV.fetch("RAILS_PG_PASSWORD")%>
+ username: <%= ENV.fetch("RAILS_PG_USERNAME") { "postgres" } %>
+ password: <%= ENV.fetch("RAILS_PG_PASSWORD") { "postgres" } %>
development:
<<: *default
@@ -30,4 +30,4 @@ production:
<<: *default
training:
- <<: *default
\ No newline at end of file
+ <<: *default
diff --git a/config/environments/civmiguat.rb b/config/environments/civmiguat.rb
index fa719dd90..202390398 100644
--- a/config/environments/civmiguat.rb
+++ b/config/environments/civmiguat.rb
@@ -52,7 +52,7 @@
# Use a different cache store in production.
config.cache_store = :redis_cache_store, {
- url: CF::App::Credentials.find_by_service_label('redis')['uri'],
+ url: "rediss://:#{ENV["REDIS_PASSWORD"]}@#{ENV["REDIS_URL"]}:#{ENV["REDIS_PORT"]}",
connect_timeout: 30,
read_timeout: 0.2,
write_timeout: 0.2,
@@ -119,31 +119,31 @@
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# Send emails via notify
- config.action_mailer.default_url_options = { host: "https://#{JSON.parse(ENV['VCAP_APPLICATION'])['application_uris'][0]}" }
+ config.action_mailer.default_url_options = { host: "https://#{ENV["HOST_URI"]}" }
config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = {
api_key: ENV.fetch("NOTIFY_API_KEY")
}
- config.x.ideal_postcodes.api_key = ENV.fetch("IDEAL_POSTCODES_API_KEY")
- config.x.salesforce.username = ENV.fetch("SALESFORCE_USERNAME")
- config.x.salesforce.password = ENV.fetch("SALESFORCE_PASSWORD")
- config.x.salesforce.security_token = ENV.fetch("SALESFORCE_SECURITY_TOKEN")
- config.x.salesforce.client_id = ENV.fetch("SALESFORCE_CLIENT_ID")
- config.x.salesforce.client_secret = ENV.fetch("SALESFORCE_CLIENT_SECRET")
+ config.x.ideal_postcodes.api_key = ENV["IDEAL_POSTCODES_API_KEY"]
+ config.x.salesforce.username = ENV["SALESFORCE_USERNAME"]
+ config.x.salesforce.password = ENV["SALESFORCE_PASSWORD"]
+ config.x.salesforce.security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
+ config.x.salesforce.client_id = ENV["SALESFORCE_CLIENT_ID"]
+ config.x.salesforce.client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
config.x.salesforce.host = "test.salesforce.com"
-
- config.x.payment_encryption_key = ENV.fetch("PAYMENT_ENCRYPTION_KEY")
- config.x.payment_encryption_salt = ENV.fetch("PAYMENT_ENCRYPTION_SALT")
-
- config.x.support_email_address = ENV.fetch("SUPPORT_EMAIL_ADDRESS")
- config.x.reply_email_guid = ENV.fetch("REPLY_EMAIL_GUID")
- config.x.no_reply_email_address = ENV.fetch("NO_REPLY_EMAIL_ADDRESS")
-
+
+ config.x.payment_encryption_key = ENV["PAYMENT_ENCRYPTION_KEY"]
+ config.x.payment_encryption_salt = ENV["PAYMENT_ENCRYPTION_SALT"]
+
+ config.x.support_email_address = ENV["SUPPORT_EMAIL_ADDRESS"]
+ config.x.reply_email_guid = ENV["REPLY_EMAIL_GUID"]
+ config.x.no_reply_email_address = ENV["NO_REPLY_EMAIL_ADDRESS"]
+
config.lograge.enabled = true
config.assets.quiet = true
- config.x.consumer.username = ENV.fetch("CONSUMER_USERNAME")
- config.x.consumer.password = ENV.fetch("CONSUMER_PASSWORD")
+ config.x.consumer.username = ENV["CONSUMER_USERNAME"]
+ config.x.consumer.password = ENV["CONSUMER_PASSWORD"]
end
\ No newline at end of file
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 6aa83ad04..08b0896ce 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -41,7 +41,7 @@
# config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options).
- # config.active_storage.service = :local # Rails 7 Upgrade Recommendation, we have disabled.
+ # config.active_storage.service = :local # Rails 7 Upgrade Recommendation, we have disabled.
# Mount Action Cable outside main process or domain.
# config.action_cable.mount_path = nil
@@ -62,7 +62,7 @@
# Use a different cache store in production.
config.cache_store = :redis_cache_store, {
- url: CF::App::Credentials.find_by_service_label('redis')['uri'],
+ url: "rediss://:#{ENV["REDIS_PASSWORD"]}@#{ENV["REDIS_URL"]}:#{ENV["REDIS_PORT"]}",
connect_timeout: 30,
read_timeout: 0.2,
write_timeout: 0.2,
@@ -132,33 +132,33 @@
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# Send emails via notify
- config.action_mailer.default_url_options = { host: "https://#{JSON.parse(ENV['VCAP_APPLICATION'])['application_uris'][0]}" }
+ config.action_mailer.default_url_options = { host: "https://#{ENV["HOST_URI"]}" }
config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = {
- api_key: ENV.fetch("NOTIFY_API_KEY")
+ api_key: ENV["NOTIFY_API_KEY"]
}
- config.x.ideal_postcodes.api_key = ENV.fetch("IDEAL_POSTCODES_API_KEY")
- config.x.salesforce.username = ENV.fetch("SALESFORCE_USERNAME")
- config.x.salesforce.password = ENV.fetch("SALESFORCE_PASSWORD")
- config.x.salesforce.security_token = ENV.fetch("SALESFORCE_SECURITY_TOKEN")
- config.x.salesforce.client_id = ENV.fetch("SALESFORCE_CLIENT_ID")
- config.x.salesforce.client_secret = ENV.fetch("SALESFORCE_CLIENT_SECRET")
+ config.x.ideal_postcodes.api_key = ENV["IDEAL_POSTCODES_API_KEY"]
+ config.x.salesforce.username = ENV["SALESFORCE_USERNAME"]
+ config.x.salesforce.password = ENV["SALESFORCE_PASSWORD"]
+ config.x.salesforce.security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
+ config.x.salesforce.client_id = ENV["SALESFORCE_CLIENT_ID"]
+ config.x.salesforce.client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
config.x.salesforce.host = "login.salesforce.com"
- config.x.devise_pepper = ENV.fetch("DEVISE_PEPPER")
+ config.x.devise_pepper = ENV["DEVISE_PEPPER"]
config.lograge.enabled = true
config.assets.quiet = true
- config.x.payment_encryption_key = ENV.fetch("PAYMENT_ENCRYPTION_KEY")
- config.x.payment_encryption_salt = ENV.fetch("PAYMENT_ENCRYPTION_SALT")
+ config.x.payment_encryption_key = ENV["PAYMENT_ENCRYPTION_KEY"]
+ config.x.payment_encryption_salt = ENV["PAYMENT_ENCRYPTION_SALT"]
- config.x.support_email_address = ENV.fetch("SUPPORT_EMAIL_ADDRESS")
- config.x.reply_email_guid = ENV.fetch("REPLY_EMAIL_GUID")
- config.x.no_reply_email_address = ENV.fetch("NO_REPLY_EMAIL_ADDRESS")
+ config.x.support_email_address = ENV["SUPPORT_EMAIL_ADDRESS"]
+ config.x.reply_email_guid = ENV["REPLY_EMAIL_GUID"]
+ config.x.no_reply_email_address = ENV["NO_REPLY_EMAIL_ADDRESS"]
- config.x.delayed_job_web.username = ENV.fetch("DELAYED_JOB_WEB_USERNAME")
- config.x.delayed_job_web.password = ENV.fetch("DELAYED_JOB_WEB_PASSWORD")
- config.x.consumer.username = ENV.fetch("CONSUMER_USERNAME")
- config.x.consumer.password = ENV.fetch("CONSUMER_PASSWORD")
+ config.x.delayed_job_web.username = ENV["DELAYED_JOB_WEB_USERNAME"]
+ config.x.delayed_job_web.password = ENV["DELAYED_JOB_WEB_PASSWORD"]
+ config.x.consumer.username = ENV["CONSUMER_USERNAME"]
+ config.x.consumer.password = ENV["CONSUMER_PASSWORD"]
end
diff --git a/config/environments/research.rb b/config/environments/research.rb
index 161732091..afc078e3d 100644
--- a/config/environments/research.rb
+++ b/config/environments/research.rb
@@ -54,7 +54,7 @@
# Use a different cache store in production.
config.cache_store = :redis_cache_store, {
- url: CF::App::Credentials.find_by_service_label('redis')['uri'],
+ url: "rediss://:#{ENV["REDIS_PASSWORD"]}@#{ENV["REDIS_URL"]}:#{ENV["REDIS_PORT"]}",
connect_timeout: 30,
read_timeout: 0.2,
write_timeout: 0.2,
@@ -121,31 +121,30 @@
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# Send emails via notify
- config.action_mailer.default_url_options = { host: "https://#{JSON.parse(ENV['VCAP_APPLICATION'])['application_uris'][0]}" }
+ config.action_mailer.default_url_options = { host: "https://#{ENV["HOST_URI"]}" }
config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = {
api_key: ENV.fetch("NOTIFY_API_KEY")
}
- config.x.ideal_postcodes.api_key = ENV.fetch("IDEAL_POSTCODES_API_KEY")
- config.x.salesforce.username = ENV.fetch("SALESFORCE_USERNAME")
- config.x.salesforce.password = ENV.fetch("SALESFORCE_PASSWORD")
- config.x.salesforce.security_token = ENV.fetch("SALESFORCE_SECURITY_TOKEN")
- config.x.salesforce.client_id = ENV.fetch("SALESFORCE_CLIENT_ID")
- config.x.salesforce.client_secret = ENV.fetch("SALESFORCE_CLIENT_SECRET")
+ config.x.ideal_postcodes.api_key = ENV["IDEAL_POSTCODES_API_KEY"]
+ config.x.salesforce.username = ENV["SALESFORCE_USERNAME"]
+ config.x.salesforce.password = ENV["SALESFORCE_PASSWORD"]
+ config.x.salesforce.security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
+ config.x.salesforce.client_id = ENV["SALESFORCE_CLIENT_ID"]
+ config.x.salesforce.client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
config.x.salesforce.host = "test.salesforce.com"
-
- config.x.payment_encryption_key = ENV.fetch("PAYMENT_ENCRYPTION_KEY")
- config.x.payment_encryption_salt = ENV.fetch("PAYMENT_ENCRYPTION_SALT")
-
- config.x.support_email_address = ENV.fetch("SUPPORT_EMAIL_ADDRESS")
- config.x.reply_email_guid = ENV.fetch("REPLY_EMAIL_GUID")
- config.x.no_reply_email_address = ENV.fetch("NO_REPLY_EMAIL_ADDRESS")
-
+
+ config.x.payment_encryption_key = ENV["PAYMENT_ENCRYPTION_KEY"]
+ config.x.payment_encryption_salt = ENV["PAYMENT_ENCRYPTION_SALT"]
+
+ config.x.support_email_address = ENV["SUPPORT_EMAIL_ADDRESS"]
+ config.x.reply_email_guid = ENV["REPLY_EMAIL_GUID"]
+ config.x.no_reply_email_address = ENV["NO_REPLY_EMAIL_ADDRESS"]
+
config.lograge.enabled = true
config.assets.quiet = true
- config.x.consumer.username = ENV.fetch("CONSUMER_USERNAME")
- config.x.consumer.password = ENV.fetch("CONSUMER_PASSWORD")
-
+ config.x.consumer.username = ENV["CONSUMER_USERNAME"]
+ config.x.consumer.password = ENV["CONSUMER_PASSWORD"]
end
\ No newline at end of file
diff --git a/config/environments/staging.rb b/config/environments/staging.rb
index 3bcf79347..db1ed853f 100644
--- a/config/environments/staging.rb
+++ b/config/environments/staging.rb
@@ -54,7 +54,7 @@
# Use a different cache store in production.
config.cache_store = :redis_cache_store, {
- url: CF::App::Credentials.find_by_service_label('redis')['uri'],
+ url: "rediss://:#{ENV["REDIS_PASSWORD"]}@#{ENV["REDIS_URL"]}:#{ENV["REDIS_PORT"]}",
connect_timeout: 30,
read_timeout: 0.2,
write_timeout: 0.2,
@@ -121,30 +121,30 @@
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# Send emails via notify
- config.action_mailer.default_url_options = { host: "https://#{JSON.parse(ENV['VCAP_APPLICATION'])['application_uris'][0]}" }
+ config.action_mailer.default_url_options = { host: "https://#{ENV["HOST_URI"]}" }
config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = {
api_key: ENV.fetch("NOTIFY_API_KEY")
}
- config.x.ideal_postcodes.api_key = ENV.fetch("IDEAL_POSTCODES_API_KEY")
- config.x.salesforce.username = ENV.fetch("SALESFORCE_USERNAME")
- config.x.salesforce.password = ENV.fetch("SALESFORCE_PASSWORD")
- config.x.salesforce.security_token = ENV.fetch("SALESFORCE_SECURITY_TOKEN")
- config.x.salesforce.client_id = ENV.fetch("SALESFORCE_CLIENT_ID")
- config.x.salesforce.client_secret = ENV.fetch("SALESFORCE_CLIENT_SECRET")
+ config.x.ideal_postcodes.api_key = ENV["IDEAL_POSTCODES_API_KEY"]
+ config.x.salesforce.username = ENV["SALESFORCE_USERNAME"]
+ config.x.salesforce.password = ENV["SALESFORCE_PASSWORD"]
+ config.x.salesforce.security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
+ config.x.salesforce.client_id = ENV["SALESFORCE_CLIENT_ID"]
+ config.x.salesforce.client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
config.x.salesforce.host = "test.salesforce.com"
-
- config.x.payment_encryption_key = ENV.fetch("PAYMENT_ENCRYPTION_KEY")
- config.x.payment_encryption_salt = ENV.fetch("PAYMENT_ENCRYPTION_SALT")
-
- config.x.support_email_address = ENV.fetch("SUPPORT_EMAIL_ADDRESS")
- config.x.reply_email_guid = ENV.fetch("REPLY_EMAIL_GUID")
- config.x.no_reply_email_address = ENV.fetch("NO_REPLY_EMAIL_ADDRESS")
-
+
+ config.x.payment_encryption_key = ENV["PAYMENT_ENCRYPTION_KEY"]
+ config.x.payment_encryption_salt = ENV["PAYMENT_ENCRYPTION_SALT"]
+
+ config.x.support_email_address = ENV["SUPPORT_EMAIL_ADDRESS"]
+ config.x.reply_email_guid = ENV["REPLY_EMAIL_GUID"]
+ config.x.no_reply_email_address = ENV["NO_REPLY_EMAIL_ADDRESS"]
+
config.lograge.enabled = true
config.assets.quiet = true
- config.x.consumer.username = ENV.fetch("CONSUMER_USERNAME")
- config.x.consumer.password = ENV.fetch("CONSUMER_PASSWORD")
+ config.x.consumer.username = ENV["CONSUMER_USERNAME"]
+ config.x.consumer.password = ENV["CONSUMER_PASSWORD"]
end
diff --git a/config/environments/training.rb b/config/environments/training.rb
index 50d94d1bd..910eeca73 100644
--- a/config/environments/training.rb
+++ b/config/environments/training.rb
@@ -130,31 +130,31 @@
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# Send emails via notify
- config.action_mailer.default_url_options = { host: "https://#{ENV.fetch("HOST_URI")}" }
+ config.action_mailer.default_url_options = { host: "https://#{ENV["HOST_URI"]}" }
config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = {
api_key: ENV.fetch("NOTIFY_API_KEY")
}
- config.x.ideal_postcodes.api_key = ENV.fetch("IDEAL_POSTCODES_API_KEY")
- config.x.salesforce.username = ENV.fetch("SALESFORCE_USERNAME")
- config.x.salesforce.password = ENV.fetch("SALESFORCE_PASSWORD")
- config.x.salesforce.security_token = ENV.fetch("SALESFORCE_SECURITY_TOKEN")
- config.x.salesforce.client_id = ENV.fetch("SALESFORCE_CLIENT_ID")
- config.x.salesforce.client_secret = ENV.fetch("SALESFORCE_CLIENT_SECRET")
+ config.x.ideal_postcodes.api_key = ENV["IDEAL_POSTCODES_API_KEY"]
+ config.x.salesforce.username = ENV["SALESFORCE_USERNAME"]
+ config.x.salesforce.password = ENV["SALESFORCE_PASSWORD"]
+ config.x.salesforce.security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
+ config.x.salesforce.client_id = ENV["SALESFORCE_CLIENT_ID"]
+ config.x.salesforce.client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
config.x.salesforce.host = "test.salesforce.com"
-
- config.x.payment_encryption_key = ENV.fetch("PAYMENT_ENCRYPTION_KEY")
- config.x.payment_encryption_salt = ENV.fetch("PAYMENT_ENCRYPTION_SALT")
-
- config.x.support_email_address = ENV.fetch("SUPPORT_EMAIL_ADDRESS")
- config.x.reply_email_guid = ENV.fetch("REPLY_EMAIL_GUID")
- config.x.no_reply_email_address = ENV.fetch("NO_REPLY_EMAIL_ADDRESS")
-
+
+ config.x.payment_encryption_key = ENV["PAYMENT_ENCRYPTION_KEY"]
+ config.x.payment_encryption_salt = ENV["PAYMENT_ENCRYPTION_SALT"]
+
+ config.x.support_email_address = ENV["SUPPORT_EMAIL_ADDRESS"]
+ config.x.reply_email_guid = ENV["REPLY_EMAIL_GUID"]
+ config.x.no_reply_email_address = ENV["NO_REPLY_EMAIL_ADDRESS"]
+
config.lograge.enabled = true
config.assets.quiet = true
- config.x.consumer.username = ENV.fetch("CONSUMER_USERNAME")
- config.x.consumer.password = ENV.fetch("CONSUMER_PASSWORD")
+ config.x.consumer.username = ENV["CONSUMER_USERNAME"]
+ config.x.consumer.password = ENV["CONSUMER_PASSWORD"]
end
\ No newline at end of file
diff --git a/config/environments/uat.rb b/config/environments/uat.rb
index 2d2928a1e..f49683ac0 100644
--- a/config/environments/uat.rb
+++ b/config/environments/uat.rb
@@ -54,7 +54,7 @@
# Use a different cache store in production.
config.cache_store = :redis_cache_store, {
- url: CF::App::Credentials.find_by_service_label('redis')['uri'],
+ url: "rediss://:#{ENV["REDIS_PASSWORD"]}@#{ENV["REDIS_URL"]}:#{ENV["REDIS_PORT"]}",
connect_timeout: 30,
read_timeout: 0.2,
write_timeout: 0.2,
@@ -121,31 +121,31 @@
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# Send emails via notify
- config.action_mailer.default_url_options = { host: "https://#{JSON.parse(ENV['VCAP_APPLICATION'])['application_uris'][0]}" }
+ config.action_mailer.default_url_options = { host: "https://#{ENV["HOST_URI"]}" }
config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = {
api_key: ENV.fetch("NOTIFY_API_KEY")
}
- config.x.ideal_postcodes.api_key = ENV.fetch("IDEAL_POSTCODES_API_KEY")
- config.x.salesforce.username = ENV.fetch("SALESFORCE_USERNAME")
- config.x.salesforce.password = ENV.fetch("SALESFORCE_PASSWORD")
- config.x.salesforce.security_token = ENV.fetch("SALESFORCE_SECURITY_TOKEN")
- config.x.salesforce.client_id = ENV.fetch("SALESFORCE_CLIENT_ID")
- config.x.salesforce.client_secret = ENV.fetch("SALESFORCE_CLIENT_SECRET")
+ config.x.ideal_postcodes.api_key = ENV["IDEAL_POSTCODES_API_KEY"]
+ config.x.salesforce.username = ENV["SALESFORCE_USERNAME"]
+ config.x.salesforce.password = ENV["SALESFORCE_PASSWORD"]
+ config.x.salesforce.security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
+ config.x.salesforce.client_id = ENV["SALESFORCE_CLIENT_ID"]
+ config.x.salesforce.client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
config.x.salesforce.host = "test.salesforce.com"
-
- config.x.payment_encryption_key = ENV.fetch("PAYMENT_ENCRYPTION_KEY")
- config.x.payment_encryption_salt = ENV.fetch("PAYMENT_ENCRYPTION_SALT")
-
- config.x.support_email_address = ENV.fetch("SUPPORT_EMAIL_ADDRESS")
- config.x.reply_email_guid = ENV.fetch("REPLY_EMAIL_GUID")
- config.x.no_reply_email_address = ENV.fetch("NO_REPLY_EMAIL_ADDRESS")
-
+
+ config.x.payment_encryption_key = ENV["PAYMENT_ENCRYPTION_KEY"]
+ config.x.payment_encryption_salt = ENV["PAYMENT_ENCRYPTION_SALT"]
+
+ config.x.support_email_address = ENV["SUPPORT_EMAIL_ADDRESS"]
+ config.x.reply_email_guid = ENV["REPLY_EMAIL_GUID"]
+ config.x.no_reply_email_address = ENV["NO_REPLY_EMAIL_ADDRESS"]
+
config.lograge.enabled = true
config.assets.quiet = true
- config.x.consumer.username = ENV.fetch("CONSUMER_USERNAME")
- config.x.consumer.password = ENV.fetch("CONSUMER_PASSWORD")
+ config.x.consumer.username = ENV["CONSUMER_USERNAME"]
+ config.x.consumer.password = ENV["CONSUMER_PASSWORD"]
end
\ No newline at end of file
diff --git a/config/initializers/constants.rb b/config/initializers/constants.rb
index 0e9936f35..33f95f29e 100644
--- a/config/initializers/constants.rb
+++ b/config/initializers/constants.rb
@@ -1,9 +1,9 @@
Rails.application.reloader.to_prepare do
- Rails.env.test? ? \
-
- SALESFORCE_URL_BASE = "" : \
-
- SALESFORCE_URL_BASE = SalesforceApi::SalesforceApiClient.new.get_salesforce_url
-
-end
\ No newline at end of file
+ SALESFORCE_URL_BASE =
+ if Rails.env.test? || ENV["SKIP_SALESFORCE_INIT"] == "true"
+ ""
+ else
+ SalesforceApi::SalesforceApiClient.new.get_salesforce_url
+ end
+end
diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb
index 76704b32e..ee74c1b77 100644
--- a/config/initializers/flipper.rb
+++ b/config/initializers/flipper.rb
@@ -1,10 +1,10 @@
-if ActiveRecord::Base.connection.table_exists? :flipper_features
+if ENV["SKIP_FLIPPER_INIT"] != "true" && ActiveRecord::Base.connection.table_exists?(:flipper_features)
Flipper.configure do |config|
config.default do
adapter = Flipper::Adapters::ActiveRecord.new
Flipper.new(adapter)
end
- # Flipper gates toggle app features on and off. Adding the flippers
+ # Flipper gates toggle app features on and off. Adding the flippers
# here creates a row in flipper_features.
# To control toggles - see README
Flipper[:registration_enabled].add
@@ -27,4 +27,4 @@
Flipper[:import_existing_account_enabled].add
Flipper[:disable_ffe].add
end
-end
\ No newline at end of file
+end
diff --git a/web-entrypoint.sh b/web-entrypoint.sh
new file mode 100644
index 000000000..1f1b81f9c
--- /dev/null
+++ b/web-entrypoint.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Database migration
+
+echo 'prepping database'
+
+bin/rails db:migrate
+
+# Runs rails server
+
+echo 'running server'
+
+bundle exec rails server -b 0.0.0.0 -p 3000 & rake jobs:work
From 686cc23df037f9c4e46d569d105fc3001756879e Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Tue, 26 Sep 2023 17:51:48 +0100
Subject: [PATCH 19/28] Update storage.yml
Add back in the config for the other envs
---
config/storage.yml | 76 +++++++++++++++++++++-------------------------
1 file changed, 35 insertions(+), 41 deletions(-)
diff --git a/config/storage.yml b/config/storage.yml
index f8d95046a..d36cc59db 100644
--- a/config/storage.yml
+++ b/config/storage.yml
@@ -6,54 +6,48 @@ local:
service: Disk
root: <%= Rails.root.join("storage") %>
+research:
+ service: S3
+ access_key_id: <%= Rails.env.research? ? ENV['AWS_ACCESS_KEY'] : "" %>
+ secret_access_key: <%= Rails.env.research? ? ENV['AWS_SECRET_KEY'] : "" %>
+ region: <%= Rails.env.research? ? ENV['AWS_REGION'] : "" %>
+ bucket: <%= Rails.env.research? ? ENV['AWS_BUCKET'] : "" %>
-# research:
-# service: S3
-# access_key_id: <%= Rails.env.research? ? ENV.fetch('AWS_ACCESS_KEY') : "" %>
-# secret_access_key: <%= Rails.env.research? ? ENV.fetch('AWS_SECRET_KEY') : "" %>
-# region: <%= Rails.env.research? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['aws_region'] : "" %>
-# bucket: <%= Rails.env.research? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['bucket_name'] : "" %>
-
-# # Rails tries to read this on all environments and expects a string value
-# staging:
-# service: S3
-# access_key_id: <%= Rails.env.staging? ? ENV.fetch('AWS_ACCESS_KEY') : "" %>
-# secret_access_key: <%= Rails.env.staging? ? ENV.fetch('AWS_SECRET_KEY') : "" %>
-# region: <%= Rails.env.staging? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['aws_region'] : "" %>
-# bucket: <%= Rails.env.staging? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['bucket_name'] : "" %>
+staging:
+ service: S3
+ access_key_id: <%= Rails.env.staging? ? ENV['AWS_ACCESS_KEY'] : "" %>
+ secret_access_key: <%= Rails.env.staging? ? ENV['AWS_SECRET_KEY'] : "" %>
+ region: <%= Rails.env.staging? ? ENV['AWS_REGION'] : "" %>
+ bucket: <%= Rails.env.staging? ? ENV['AWS_BUCKET'] : "" %>
-# Rails tries to read this on all environments and expects a string value
training:
service: S3
- access_key_id: <%= Rails.env.training? ? ENV.fetch('AWS_ACCESS_KEY') : "" %>
- secret_access_key: <%= Rails.env.training? ? ENV.fetch('AWS_SECRET_KEY') : "" %>
- region: <%= Rails.env.training? ? ENV.fetch('AWS_REGION') : "" %>
- bucket: <%= Rails.env.training? ? ENV.fetch('AWS_BUCKET') : "" %>
-
-# Rails tries to read this on all environments and expects a string value
-# uat:
-# service: S3
-# access_key_id: <%= Rails.env.uat? ? ENV.fetch('AWS_ACCESS_KEY') : "" %>
-# secret_access_key: <%= Rails.env.uat? ? ENV.fetch('AWS_SECRET_KEY') : "" %>
-# region: <%= Rails.env.uat? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['aws_region'] : "" %>
-# bucket: <%= Rails.env.uat? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['bucket_name'] : "" %>
+ access_key_id: <%= Rails.env.training? ? ENV['AWS_ACCESS_KEY'] : "" %>
+ secret_access_key: <%= Rails.env.training? ? ENV['AWS_SECRET_KEY'] : "" %>
+ region: <%= Rails.env.training? ? ENV['AWS_REGION'] : "" %>
+ bucket: <%= Rails.env.training? ? ENV['AWS_BUCKET'] : "" %>
-# # Rails tries to read this on all environments and expects a string value
-# civmiguat:
-# service: S3
-# access_key_id: <%= Rails.env.civmiguat? ? ENV.fetch('AWS_ACCESS_KEY') : "" %>
-# secret_access_key: <%= Rails.env.civmiguat? ? ENV.fetch('AWS_SECRET_KEY') : "" %>
-# region: <%= Rails.env.civmiguat? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['aws_region'] : "" %>
-# bucket: <%= Rails.env.civmiguat? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['bucket_name'] : "" %>
+uat:
+ service: S3
+ access_key_id: <%= Rails.env.uat? ? ENV['AWS_ACCESS_KEY'] : "" %>
+ secret_access_key: <%= Rails.env.uat? ? ENV['AWS_SECRET_KEY'] : "" %>
+ region: <%= Rails.env.uat? ? ENV['AWS_REGION'] : "" %>
+ bucket: <%= Rails.env.uat? ? ENV['AWS_BUCKET'] : "" %>
-# # Rails tries to read this on all environments and expects a string value
-# production:
-# service: S3
-# access_key_id: <%= Rails.env.production? ? ENV.fetch('AWS_ACCESS_KEY') : "" %>
-# secret_access_key: <%= Rails.env.production? ? ENV.fetch('AWS_SECRET_KEY') : "" %>
-# region: <%= Rails.env.production? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['aws_region'] : "" %>
-# bucket: <%= Rails.env.production? ? CF::App::Credentials.find_by_service_label('aws-s3-bucket')['bucket_name'] : "" %>
+civmiguat:
+ service: S3
+ access_key_id: <%= Rails.env.civmiguat? ? ENV['AWS_ACCESS_KEY'] : "" %>
+ secret_access_key: <%= Rails.env.civmiguat? ? ENV['AWS_SECRET_KEY'] : "" %>
+ region: <%= Rails.env.civmiguat? ? ENV['AWS_REGION'] : "" %>
+ bucket: <%= Rails.env.civmiguat? ? ENV['AWS_BUCKET'] : "" %>
+production:
+ service: S3
+ access_key_id: <%= Rails.env.production? ? ENV['AWS_ACCESS_KEY'] : "" %>
+ secret_access_key: <%= Rails.env.production? ? ENV['AWS_SECRET_KEY'] : "" %>
+ region: <%= Rails.env.production? ? ENV['AWS_REGION'] : "" %>
+ bucket: <%= Rails.env.production? ? ENV['AWS_BUCKET'] : "" %>
+
# Remember not to checkin your GCS keyfile to a repository
# google:
# service: GCS
From 9028a94f611d15503c66592a9edec352911e96b7 Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Tue, 26 Sep 2023 18:06:10 +0100
Subject: [PATCH 20/28] Delete web-entrypoint.sh
We are running processes under the docker folder
---
web-entrypoint.sh | 13 -------------
1 file changed, 13 deletions(-)
delete mode 100644 web-entrypoint.sh
diff --git a/web-entrypoint.sh b/web-entrypoint.sh
deleted file mode 100644
index 1f1b81f9c..000000000
--- a/web-entrypoint.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# Database migration
-
-echo 'prepping database'
-
-bin/rails db:migrate
-
-# Runs rails server
-
-echo 'running server'
-
-bundle exec rails server -b 0.0.0.0 -p 3000 & rake jobs:work
From f1e0eabc845a7fe23f40e7b630fa9bca9c06a29e Mon Sep 17 00:00:00 2001
From: Lubos Hricak
Date: Wed, 27 Sep 2023 00:57:12 -0300
Subject: [PATCH 21/28] Fix DB host fallback preventing tests to run
---
config/database.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/database.yml b/config/database.yml
index 86023cc30..c674f6f00 100644
--- a/config/database.yml
+++ b/config/database.yml
@@ -9,7 +9,7 @@ default: &default
database: <%= ENV.fetch("RAILS_DATABASE") {"funding_frontend"} %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
- host: <%= ENV.fetch("RAILS_PG_HOST") {"host.docker.internal"} %>
+ host: <%= ENV.fetch("RAILS_PG_HOST") { "localhost" } %>
username: <%= ENV.fetch("RAILS_PG_USERNAME") { "postgres" } %>
password: <%= ENV.fetch("RAILS_PG_PASSWORD") { "postgres" } %>
From cd0bdb31088455ba00e2b71281e4e1fc9d562610 Mon Sep 17 00:00:00 2001
From: Lubos Hricak
Date: Wed, 27 Sep 2023 01:01:14 -0300
Subject: [PATCH 22/28] Add workflow to deploy application to Azure container
---
.github/workflows/azure-deploy-production.yml | 130 ++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 .github/workflows/azure-deploy-production.yml
diff --git a/.github/workflows/azure-deploy-production.yml b/.github/workflows/azure-deploy-production.yml
new file mode 100644
index 000000000..954a10c7d
--- /dev/null
+++ b/.github/workflows/azure-deploy-production.yml
@@ -0,0 +1,130 @@
+name: Build, test & deploy to Azure Web App
+
+env:
+ AZURE_WEBAPP_NAME: funding-frontend # Name set within Azure Web App
+ REGISTRY: ghcr.io
+
+on:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ packages: write
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ services:
+ db:
+ image: postgres:11-alpine
+ ports: ['5432:5432']
+ env:
+ POSTGRES_DB: funding_frontend_test
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 15s
+ --health-retries 5
+ redis:
+ image: redis
+ ports: ['6379:6379']
+ options: --entrypoint redis-server
+
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ with:
+ path: vendor/bundle
+ key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-gems-
+
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
+ - uses: actions/cache@v2
+ id: yarn-cache
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Setup Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.1.1
+ - uses: actions/setup-node@v2-beta
+ with:
+ node-version: '16'
+ - run: npm install -g yarn
+ - uses: nanasess/setup-chromedriver@master
+
+ - name: Build and run tests
+ env:
+ DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/funding_frontend_test'
+ BUNDLER_VERSION: 2.3.11
+ DOCKER_TLS_CERTDIR: ''
+ run: |
+ sudo apt update
+ sudo apt-get -yqq install postgresql postgresql-client libpq-dev xvfb unzip libcurl4 libcurl3-gnutls libcurl4-openssl-dev
+ gem install bundler
+ gem update --system && gem update bundler
+ yarn install
+ bundle install --jobs 4 --retry 3
+ RAILS_ENV=test bundle exec rake db:setup
+ RAILS_ENV=test RAILS_DISABLE_TEST_LOG=true bundle exec rspec
+
+ buildx:
+ runs-on: ubuntu-latest
+ needs: [test]
+ if: github.ref == 'refs/heads/master'
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ github.token }}
+
+ - name: Lowercase the repository name and username
+ run: echo "REPOSITORY=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
+
+ - name: Build the container image and push it to the registry
+ uses: docker/build-push-action@v2
+ with:
+ push: true
+ tags: ${{ env.REGISTRY }}/${{ env.REPOSITORY }}:${{ github.sha }}
+ file: ./Dockerfile
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: [buildx]
+
+ permissions:
+ contents: none
+
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+
+ steps:
+ - name: Lowercase the repository name and username
+ run: echo "REPOSITORY=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: ${{ env.AZURE_WEBAPP_NAME }}
+ publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
+ images: '${{ env.REGISTRY }}/${{ env.REPOSITORY }}:${{ github.sha }}'
From d3e0010205e123b2b63fa65cfbbe260d2c69012f Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Wed, 27 Sep 2023 12:39:27 +0100
Subject: [PATCH 23/28] Switch Docker image to use Foreman and Ruby base image
We are having issues debugging the Passenger image.
Switching to another image and using a Procfile to manage the two processes.
---
.dockerignore | 56 +++++--------
.node-version | 1 +
Dockerfile | 185 +++++++++++++++++++++---------------------
Procfile | 2 +
bin/docker-entrypoint | 7 ++
config/puma.rb | 8 +-
docker/puma.sh | 3 -
docker/workers.sh | 3 -
8 files changed, 130 insertions(+), 135 deletions(-)
create mode 100644 .node-version
create mode 100644 Procfile
create mode 100755 bin/docker-entrypoint
delete mode 100644 docker/puma.sh
delete mode 100644 docker/workers.sh
diff --git a/.dockerignore b/.dockerignore
index e5c04a3a8..ca0f731c0 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,14 +1,18 @@
-# Replicates gitignore - but keeps .env for local development
-#
-# If you find yourself ignoring temporary files generated by your text editor
-# or operating system, you probably want to add a global ignore instead:
-# git config --global core.excludesfile '~/.gitignore_global'
+# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
+
+# Ignore git directory.
+/.git/
# Ignore bundler config.
/.bundle
-/db/*.sqlite3
-/db/*.sqlite3-journal
+# Ignore all default key files.
+/config/master.key
+/config/credentials/*.key
+
+# Ignore all environment files.
+/.env*
+!/.env.example
# Ignore all logfiles and tempfiles.
/log/*
@@ -16,34 +20,18 @@
!/log/.keep
!/tmp/.keep
-# Ignore uploaded files in development.
+# Ignore pidfiles, but keep the directory.
+/tmp/pids/*
+!/tmp/pids/.keep
+
+# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
+/tmp/storage/*
+!/tmp/storage/.keep
+# Ignore assets.
+/node_modules/
+/app/assets/builds/*
+!/app/assets/builds/.keep
/public/assets
-.byebug_history
-
-# Ignore master key for decrypting credentials and more.
-/config/master.key
-
-/public/packs
-/public/packs-test
-/node_modules
-/node_modules/.cache/
-/yarn-error.log
-yarn-debug.log*
-.yarn-integrity
-
-# Credentials - env is copied if present
-# but env is never present in source control.
-# so docker can only copy when running locally
-.env
-.dockersenv
-
-# Ignore Mac specific files
-.DS_Store
-
-/package-lock.json
-
-# Salesforce logs
-lib/apis/salesforce/log
diff --git a/.node-version b/.node-version
new file mode 100644
index 000000000..cb406c60c
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+16.20.2
diff --git a/Dockerfile b/Dockerfile
index a03ceceef..8a23ae7ee 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,92 +1,95 @@
-# syntax=docker/dockerfile:1
-
-FROM phusion/passenger-ruby31:latest
-
-ENV HOME /home/app/deploy
-
-# Install common dependencies
-RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
- --mount=type=cache,target=/var/lib/apt,sharing=locked \
- --mount=type=tmpfs,target=/var/log \
- apt-get update -qq \
- && apt-get dist-upgrade -y \
- && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
- curl \
- gnupg2 \
- less \
- tzdata \
- time \
- locales \
- && update-locale LANG=C.UTF-8 LC_ALL=C.UTF-8
-
-# Install NodeJS and Yarn
-ARG NODE_MAJOR=16
-RUN yes | apt remove nodejs
-RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
- --mount=type=cache,target=/var/lib/apt,sharing=locked \
- --mount=type=tmpfs,target=/var/log \
- apt-get update && \
- apt-get install -y curl software-properties-common && \
- curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
- echo "deb https://deb.nodesource.com/node_${NODE_MAJOR}.x $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/nodesource.list && \
- apt-get update && \
- DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends nodejs
-
-ARG YARN_VERSION=latest
-RUN npm install -g yarn@$YARN_VERSION
-
-# Configure bundler
-ENV RAILS_ENV=production \
- NODE_ENV=production \
- BUNDLE_JOBS=4 \
- BUNDLE_RETRY=3 \
- BUNDLE_APP_CONFIG=/home/app/.bundle \
- BUNDLE_PATH=/home/app/.bundle \
- GEM_HOME=/home/app/.bundle \
- PATH="$HOME/bin:${PATH}" \
- LANG=C.UTF-8 \
- LC_ALL=C.UTF-8
-
-
-# Upgrade RubyGems and install the latest Bundler version
-ARG BUNDLER_VERSION=2.3.11
-RUN echo "gem: --no-rdoc --no-ri >> \"$HOME/.gemrc\""
-RUN gem update --system && \
- gem install bundler:$BUNDLER_VERSION
-
-# Create a directory for the app code
-RUN mkdir -p $HOME
-WORKDIR $HOME
-
-# Install Ruby gems
-COPY --chown=app:app Gemfile Gemfile.lock ./
-RUN bundle lock --add-platform aarch64-linux
-
-RUN mkdir $BUNDLE_PATH \
- && bundle config --local path "${BUNDLE_PATH}" \
- && bundle config --local without 'development test' \
- && bundle config --local clean 'true' \
- && bundle config --local no-cache 'true' \
- && bundle install --jobs=${BUNDLE_JOBS} \
- && rm -rf $BUNDLE_PATH/ruby/3.1.0/cache/* \
- && rm -rf $HOME/.bundle/cache/*
-
-# Install JS packages
-COPY --chown=app:app package.json yarn.lock ./
-RUN yarn install --check-files
-
-RUN mkdir -p $HOME/tmp/pids
-
-COPY --chown=app:app . .
-
-# Precompile assets
-
-RUN SKIP_SALESFORCE_INIT=true SKIP_FLIPPER_INIT=true SECRET_KEY_BASE=dummyvalue bundle exec rake assets:precompile
-
-RUN mkdir -p /etc/my_init.d
-COPY docker/puma.sh /etc/my_init.d/puma.sh
-COPY docker/workers.sh /etc/my_init.d/workers.sh
-
-
-CMD ["/sbin/my_init"]
+# syntax = docker/dockerfile:1
+
+# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
+ARG RUBY_VERSION=3.1.4
+FROM ruby:$RUBY_VERSION-slim as base
+
+# Rails app lives here
+WORKDIR /rails
+
+# Set production environment
+ENV RAILS_ENV="production" \
+ BUNDLE_WITHOUT="development:test" \
+ BUNDLE_DEPLOYMENT="1"
+
+# Update gems and bundler
+RUN gem update --system --no-document && \
+ gem install -N bundler &&\
+ gem install -N foreman
+
+# Throw-away build stages to reduce size of final image
+FROM base as prebuild
+
+# Install packages needed to build gems and node modules
+RUN apt-get update -qq && \
+ apt-get install --no-install-recommends -y build-essential curl libpq-dev node-gyp pkg-config python-is-python3
+
+
+FROM prebuild as node
+
+# Install JavaScript dependencies
+ARG NODE_VERSION=16.20.2
+ARG YARN_VERSION=1.22.19
+ENV PATH=/usr/local/node/bin:$PATH
+RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
+ /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
+ npm install -g yarn@$YARN_VERSION && \
+ rm -rf /tmp/node-build-master
+
+# Install node modules
+COPY --link package.json yarn.lock ./
+RUN yarn install --frozen-lockfile
+
+
+FROM prebuild as build
+
+# Install application gems
+COPY --link Gemfile Gemfile.lock ./
+RUN bundle install && \
+ bundle exec bootsnap precompile --gemfile && \
+ rm -rf ~/.bundle/ $BUNDLE_PATH/ruby/*/cache $BUNDLE_PATH/ruby/*/bundler/gems/*/.git
+
+# Copy node modules
+COPY --from=node /rails/node_modules /rails/node_modules
+COPY --from=node /usr/local/node /usr/local/node
+ENV PATH=/usr/local/node/bin:$PATH
+
+# Copy application code
+COPY --link . .
+
+# Precompile bootsnap code for faster boot times
+RUN bundle exec bootsnap precompile app/ lib/
+
+# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
+RUN SKIP_SALESFORCE_INIT=true SKIP_FLIPPER_INIT=true SECRET_KEY_BASE=DUMMY ./bin/rails assets:precompile
+
+
+# Final stage for app image
+FROM base
+
+# Install packages needed for deployment
+RUN apt-get update -qq && \
+ apt-get install --no-install-recommends -y curl libjemalloc2 postgresql-client ruby-foreman && \
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
+
+# Copy built artifacts: gems, application
+COPY --from=build /usr/local/bundle /usr/local/bundle
+COPY --from=build /rails /rails
+
+# Run and own only the runtime files as a non-root user for security
+RUN useradd rails --create-home --shell /bin/bash && \
+ chown -R rails:rails db log storage tmp
+USER rails:rails
+
+# Deployment options
+ENV LD_PRELOAD="libjemalloc.so.2" \
+ MALLOC_CONF="dirty_decay_ms:1000,narenas:2,background_thread:true" \
+ RAILS_LOG_TO_STDOUT="1" \
+ RAILS_SERVE_STATIC_FILES="true"
+
+# Entrypoint prepares the database.
+ENTRYPOINT ["/rails/bin/docker-entrypoint"]
+
+# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
+CMD ["foreman", "start", "--procfile=Procfile"]
diff --git a/Procfile b/Procfile
new file mode 100644
index 000000000..aa4ffcb88
--- /dev/null
+++ b/Procfile
@@ -0,0 +1,2 @@
+web: bundle exec puma -C config/puma.rb
+worker: bundle exec rake jobs:work
diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint
new file mode 100755
index 000000000..3f8d37102
--- /dev/null
+++ b/bin/docker-entrypoint
@@ -0,0 +1,7 @@
+#!/bin/bash -e
+
+if [ "${*}" == "foreman start --procfile=Procfile" ]; then
+ ./bin/rails db:prepare
+fi
+
+exec "${@}"
diff --git a/config/puma.rb b/config/puma.rb
index 2d3d96983..5b97cb1a6 100644
--- a/config/puma.rb
+++ b/config/puma.rb
@@ -17,7 +17,7 @@
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the `pidfile` that Puma will use.
-pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
+# pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
@@ -25,14 +25,14 @@
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
-# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
+workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
-# preload_app!
+preload_app!
# Allow puma to be restarted by `rails restart` command.
-plugin :tmp_restart
+# plugin :tmp_restart
diff --git a/docker/puma.sh b/docker/puma.sh
deleted file mode 100644
index bfc8f2149..000000000
--- a/docker/puma.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-cd /home/app/deploy && exec bundle exec rails server -b 0.0.0.0 -p 3000 >>/var/log/puma.log 2>&1
diff --git a/docker/workers.sh b/docker/workers.sh
deleted file mode 100644
index 4aea5d71f..000000000
--- a/docker/workers.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-cd /home/app/deploy && exec bundle exec rake jobs:work >>/var/log/workers.log 2>&1
From bf461ccd6d6d044519de2d7bae51ab7ea7e6234b Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Wed, 27 Sep 2023 12:43:06 +0100
Subject: [PATCH 24/28] Update Gemfile.lock
---
Gemfile.lock | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Gemfile.lock b/Gemfile.lock
index 53149b244..bcdae14c0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -241,6 +241,8 @@ GEM
activerecord (>= 4.0.0)
activesupport (>= 4.0.0)
nio4r (2.5.9)
+ nokogiri (1.15.2-aarch64-linux)
+ racc (~> 1.4)
nokogiri (1.15.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.15.2-x86_64-darwin)
@@ -449,6 +451,7 @@ GEM
zeitwerk (2.6.8)
PLATFORMS
+ aarch64-linux
arm64-darwin-23
x86_64-darwin-20
x86_64-linux
From 6a3eff9c21b44a8fa7a793b2237421279ec4838f Mon Sep 17 00:00:00 2001
From: Matthew Ford
Date: Wed, 27 Sep 2023 12:47:49 +0100
Subject: [PATCH 25/28] Set node-version to 16.20.2
---
.github/workflows/azure-deploy-production.yml | 2 +-
.github/workflows/continuous-integration-workflow.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/azure-deploy-production.yml b/.github/workflows/azure-deploy-production.yml
index 954a10c7d..e9c3a710f 100644
--- a/.github/workflows/azure-deploy-production.yml
+++ b/.github/workflows/azure-deploy-production.yml
@@ -58,7 +58,7 @@ jobs:
ruby-version: 3.1.1
- uses: actions/setup-node@v2-beta
with:
- node-version: '16'
+ node-version: '16.20.2'
- run: npm install -g yarn
- uses: nanasess/setup-chromedriver@master
diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml
index 5a86ef69e..3b17d8008 100644
--- a/.github/workflows/continuous-integration-workflow.yml
+++ b/.github/workflows/continuous-integration-workflow.yml
@@ -36,7 +36,7 @@ jobs:
- uses: actions/setup-node@v1
with:
- node-version: '16.14.2'
+ node-version: '16.20.2'
- uses: ruby/setup-ruby@v1
with:
From 2e1b07d5dafc146ef0d692f9cfb057c9e23b234e Mon Sep 17 00:00:00 2001
From: Lubos Hricak
Date: Wed, 27 Sep 2023 09:15:35 -0300
Subject: [PATCH 26/28] Make workflow to deploy to `uat`
---
.../{azure-deploy-production.yml => azure-deploy-uat.yml} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename .github/workflows/{azure-deploy-production.yml => azure-deploy-uat.yml} (98%)
diff --git a/.github/workflows/azure-deploy-production.yml b/.github/workflows/azure-deploy-uat.yml
similarity index 98%
rename from .github/workflows/azure-deploy-production.yml
rename to .github/workflows/azure-deploy-uat.yml
index e9c3a710f..d6ea48040 100644
--- a/.github/workflows/azure-deploy-production.yml
+++ b/.github/workflows/azure-deploy-uat.yml
@@ -1,7 +1,7 @@
name: Build, test & deploy to Azure Web App
env:
- AZURE_WEBAPP_NAME: funding-frontend # Name set within Azure Web App
+ AZURE_WEBAPP_NAME: uat
REGISTRY: ghcr.io
on:
From d2185e4010302c00a3d623dbd57e052982c89627 Mon Sep 17 00:00:00 2001
From: Lubos Hricak
Date: Wed, 27 Sep 2023 01:01:14 -0300
Subject: [PATCH 27/28] Add workflow to deploy application to Azure container
---
.github/workflows/azure-deploy-production.yml | 130 ++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 .github/workflows/azure-deploy-production.yml
diff --git a/.github/workflows/azure-deploy-production.yml b/.github/workflows/azure-deploy-production.yml
new file mode 100644
index 000000000..954a10c7d
--- /dev/null
+++ b/.github/workflows/azure-deploy-production.yml
@@ -0,0 +1,130 @@
+name: Build, test & deploy to Azure Web App
+
+env:
+ AZURE_WEBAPP_NAME: funding-frontend # Name set within Azure Web App
+ REGISTRY: ghcr.io
+
+on:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ packages: write
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ services:
+ db:
+ image: postgres:11-alpine
+ ports: ['5432:5432']
+ env:
+ POSTGRES_DB: funding_frontend_test
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 15s
+ --health-retries 5
+ redis:
+ image: redis
+ ports: ['6379:6379']
+ options: --entrypoint redis-server
+
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ with:
+ path: vendor/bundle
+ key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-gems-
+
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
+ - uses: actions/cache@v2
+ id: yarn-cache
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Setup Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.1.1
+ - uses: actions/setup-node@v2-beta
+ with:
+ node-version: '16'
+ - run: npm install -g yarn
+ - uses: nanasess/setup-chromedriver@master
+
+ - name: Build and run tests
+ env:
+ DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/funding_frontend_test'
+ BUNDLER_VERSION: 2.3.11
+ DOCKER_TLS_CERTDIR: ''
+ run: |
+ sudo apt update
+ sudo apt-get -yqq install postgresql postgresql-client libpq-dev xvfb unzip libcurl4 libcurl3-gnutls libcurl4-openssl-dev
+ gem install bundler
+ gem update --system && gem update bundler
+ yarn install
+ bundle install --jobs 4 --retry 3
+ RAILS_ENV=test bundle exec rake db:setup
+ RAILS_ENV=test RAILS_DISABLE_TEST_LOG=true bundle exec rspec
+
+ buildx:
+ runs-on: ubuntu-latest
+ needs: [test]
+ if: github.ref == 'refs/heads/master'
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ github.token }}
+
+ - name: Lowercase the repository name and username
+ run: echo "REPOSITORY=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
+
+ - name: Build the container image and push it to the registry
+ uses: docker/build-push-action@v2
+ with:
+ push: true
+ tags: ${{ env.REGISTRY }}/${{ env.REPOSITORY }}:${{ github.sha }}
+ file: ./Dockerfile
+
+ deploy:
+ runs-on: ubuntu-latest
+ needs: [buildx]
+
+ permissions:
+ contents: none
+
+ environment:
+ name: 'Production'
+ url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
+
+ steps:
+ - name: Lowercase the repository name and username
+ run: echo "REPOSITORY=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
+
+ - name: Deploy to Azure Web App
+ id: deploy-to-webapp
+ uses: azure/webapps-deploy@v2
+ with:
+ app-name: ${{ env.AZURE_WEBAPP_NAME }}
+ publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
+ images: '${{ env.REGISTRY }}/${{ env.REPOSITORY }}:${{ github.sha }}'
From c3fc326073c0ee8690dd493399dd805e7913e654 Mon Sep 17 00:00:00 2001
From: Lubos Hricak
Date: Tue, 3 Oct 2023 14:46:23 -0300
Subject: [PATCH 28/28] Switch from GitHub to Azure container registry
---
.github/workflows/azure-deploy-uat.yml | 60 ++++++++++----------------
1 file changed, 23 insertions(+), 37 deletions(-)
diff --git a/.github/workflows/azure-deploy-uat.yml b/.github/workflows/azure-deploy-uat.yml
index d6ea48040..259dafc49 100644
--- a/.github/workflows/azure-deploy-uat.yml
+++ b/.github/workflows/azure-deploy-uat.yml
@@ -2,7 +2,6 @@ name: Build, test & deploy to Azure Web App
env:
AZURE_WEBAPP_NAME: uat
- REGISTRY: ghcr.io
on:
workflow_dispatch:
@@ -77,7 +76,7 @@ jobs:
RAILS_ENV=test bundle exec rake db:setup
RAILS_ENV=test RAILS_DISABLE_TEST_LOG=true bundle exec rspec
- buildx:
+ build-and-deploy:
runs-on: ubuntu-latest
needs: [test]
if: github.ref == 'refs/heads/master'
@@ -86,45 +85,32 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Login to GitHub Container Registry
- uses: docker/login-action@v3
+ - name: Login via Azure CLI
+ uses: azure/login@v1
with:
- registry: ${{ env.REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ github.token }}
+ creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Lowercase the repository name and username
run: echo "REPOSITORY=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
- - name: Build the container image and push it to the registry
- uses: docker/build-push-action@v2
+ - name: Build and push image
+ uses: azure/docker-login@v1
with:
- push: true
- tags: ${{ env.REGISTRY }}/${{ env.REPOSITORY }}:${{ github.sha }}
- file: ./Dockerfile
-
- deploy:
- runs-on: ubuntu-latest
- needs: [buildx]
-
- permissions:
- contents: none
-
- environment:
- name: 'Production'
- url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
-
- steps:
- - name: Lowercase the repository name and username
- run: echo "REPOSITORY=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
-
- - name: Deploy to Azure Web App
- id: deploy-to-webapp
- uses: azure/webapps-deploy@v2
+ login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
+ username: ${{ secrets.REGISTRY_USERNAME }}
+ password: ${{ secrets.REGISTRY_PASSWORD }}
+ - run: |
+ docker build . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/${{ env.REPOSITORY }}/${{ env.AZURE_WEBAPP_NAME }}:${{ github.sha }}
+ docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/${{ env.REPOSITORY }}/${{ env.AZURE_WEBAPP_NAME }}:${{ github.sha }}
+
+ - name: Deploy to Azure Container Instance
+ uses: azure/aci-deploy@v1
with:
- app-name: ${{ env.AZURE_WEBAPP_NAME }}
- publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
- images: '${{ env.REGISTRY }}/${{ env.REPOSITORY }}:${{ github.sha }}'
+ resource-group: ${{ secrets.RESOURCE_GROUP }}
+ dns-name-label: ${{ secrets.RESOURCE_GROUP }}${{ github.run_number }}
+ image: ${{ secrets.REGISTRY_LOGIN_SERVER }}/${{ env.REPOSITORY }}/${{ env.AZURE_WEBAPP_NAME }}:${{ github.sha }}
+ registry-login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
+ registry-username: ${{ secrets.REGISTRY_USERNAME }}
+ registry-password: ${{ secrets.REGISTRY_PASSWORD }}
+ name: ${{ env.AZURE_WEBAPP_NAME }}
+ location: uksouth