43 changed files with 578 additions and 77 deletions
@ -0,0 +1,24 @@
|
||||
name: Review app deploy prompt |
||||
|
||||
on: |
||||
pull_request: |
||||
types: [opened] |
||||
|
||||
jobs: |
||||
prompt: |
||||
name: Add review app deploy instructions |
||||
runs-on: ubuntu-latest |
||||
permissions: |
||||
pull-requests: write |
||||
|
||||
steps: |
||||
- name: Comment with deploy instructions |
||||
uses: actions/github-script@v7 |
||||
with: |
||||
script: | |
||||
await github.rest.issues.createComment({ |
||||
owner: context.repo.owner, |
||||
repo: context.repo.repo, |
||||
issue_number: context.issue.number, |
||||
body: 'To deploy a review app for this PR, comment `/deploy-review`.', |
||||
}); |
||||
@ -1,57 +1,94 @@
|
||||
name: Review app pipeline |
||||
|
||||
concurrency: |
||||
group: review-${{ github.event.pull_request.number }} |
||||
|
||||
on: |
||||
pull_request: |
||||
types: |
||||
- opened |
||||
- synchronize |
||||
- reopened |
||||
issue_comment: |
||||
types: [created] |
||||
workflow_dispatch: |
||||
inputs: |
||||
pr_number: |
||||
required: true |
||||
type: string |
||||
description: "The number of the PR for which to deploy a review app. Note: this is NOT the ticket number" |
||||
|
||||
defaults: |
||||
run: |
||||
shell: bash |
||||
permissions: {} |
||||
|
||||
jobs: |
||||
get_pr_details: |
||||
name: Get PR details |
||||
if: github.event_name == 'workflow_dispatch' || (github.event.issue.pull_request && startsWith(github.event.comment.body, '/deploy-review')) |
||||
runs-on: ubuntu-latest |
||||
outputs: |
||||
pr_number: ${{ steps.get_pr_details.outputs.pr_number }} |
||||
pr_head_sha: ${{ steps.get_pr_details.outputs.pr_head_sha }} |
||||
steps: |
||||
- name: Get PR number and HEAD SHA |
||||
id: get_pr_details |
||||
uses: actions/github-script@v7 |
||||
with: |
||||
script: | |
||||
let prNumber; |
||||
if (context.eventName === 'workflow_dispatch') { |
||||
prNumber = '${{ inputs.pr_number }}'; |
||||
} else { |
||||
prNumber = context.issue.number.toString(); |
||||
} |
||||
core.setOutput('pr_number', prNumber); |
||||
const { data: pr } = await github.rest.pulls.get({ |
||||
owner: context.repo.owner, |
||||
repo: context.repo.repo, |
||||
pull_number: parseInt(prNumber), |
||||
}); |
||||
core.setOutput('pr_head_sha', pr.head.sha); |
||||
|
||||
infra: |
||||
name: Deploy review app infrastructure |
||||
needs: [get_pr_details] |
||||
uses: communitiesuk/submit-social-housing-lettings-and-sales-data-infrastructure/.github/workflows/create_review_app_infra.yml@main |
||||
with: |
||||
key: ${{ github.event.pull_request.number }} |
||||
key: ${{ needs.get_pr_details.outputs.pr_number }} |
||||
app_repo_role: arn:aws:iam::815624722760:role/core-application-repo |
||||
permissions: |
||||
id-token: write |
||||
|
||||
code: |
||||
name: Deploy review app code |
||||
needs: [infra] |
||||
needs: [get_pr_details, infra] |
||||
uses: ./.github/workflows/aws_deploy.yml |
||||
with: |
||||
aws_account_id: 837698168072 |
||||
aws_role_prefix: core-dev |
||||
aws_task_prefix: core-review-${{ github.event.pull_request.number }} |
||||
concurrency_tag: ${{ github.event.pull_request.number }} |
||||
aws_task_prefix: core-review-${{ needs.get_pr_details.outputs.pr_number }} |
||||
concurrency_tag: ${{ needs.get_pr_details.outputs.pr_number }} |
||||
environment: review |
||||
ref: ${{ needs.get_pr_details.outputs.pr_head_sha }} |
||||
permissions: |
||||
id-token: write |
||||
|
||||
comment: |
||||
name: Add link to PR |
||||
needs: [code] |
||||
needs: [get_pr_details, code] |
||||
runs-on: ubuntu-latest |
||||
permissions: |
||||
issues: write |
||||
pull-requests: write |
||||
|
||||
steps: |
||||
- name: Comment on PR with URL |
||||
uses: unsplash/comment-on-pr@v1.3.0 |
||||
env: |
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
||||
uses: actions/github-script@v7 |
||||
with: |
||||
msg: "Created review app at https://review.submit-social-housing-data.communities.gov.uk/${{ github.event.pull_request.number }}. Note that the review app will be automatically deprovisioned after 30 days and will need the review app pipeline running again." |
||||
check_for_duplicate_msg: true |
||||
duplicate_msg_pattern: Created review app at* |
||||
script: | |
||||
const prNumber = ${{ needs.get_pr_details.outputs.pr_number }}; |
||||
const body = `Created review app at https://review.submit-social-housing-data.communities.gov.uk/${prNumber}. Note that the review app will be automatically deprovisioned after 30 days and will need the review app pipeline running again.`; |
||||
const { data: comments } = await github.rest.issues.listComments({ |
||||
owner: context.repo.owner, |
||||
repo: context.repo.repo, |
||||
issue_number: prNumber, |
||||
}); |
||||
const duplicate = comments.find(c => c.body.startsWith('Created review app at')); |
||||
if (!duplicate) { |
||||
await github.rest.issues.createComment({ |
||||
owner: context.repo.owner, |
||||
repo: context.repo.repo, |
||||
issue_number: prNumber, |
||||
body: body, |
||||
}); |
||||
} |
||||
|
||||
@ -0,0 +1,14 @@
|
||||
class Form::Sales::Pages::ServiceChargeChanged < ::Form::Page |
||||
def initialize(id, hsh, subsection) |
||||
super |
||||
@id = "service_charge_changed" |
||||
@copy_key = "sales.sale_information.servicecharges_changed" |
||||
end |
||||
|
||||
def questions |
||||
@questions ||= [ |
||||
Form::Sales::Questions::HasServiceChargesChanged.new(nil, nil, self), |
||||
Form::Sales::Questions::NewServiceCharges.new(nil, nil, self), |
||||
] |
||||
end |
||||
end |
||||
@ -0,0 +1,27 @@
|
||||
class Form::Sales::Questions::HasServiceChargesChanged < ::Form::Question |
||||
def initialize(id, hsh, page) |
||||
super |
||||
@id = "hasservicechargeschanged" |
||||
@type = "radio" |
||||
@answer_options = ANSWER_OPTIONS |
||||
@conditional_for = { |
||||
"newservicecharges" => [1], |
||||
} |
||||
@hidden_in_check_answers = { |
||||
"depends_on" => [ |
||||
{ |
||||
"hasservicechargeschanged" => 1, |
||||
}, |
||||
], |
||||
} |
||||
@copy_key = "sales.sale_information.servicecharges_changed.has_service_charges_changed" |
||||
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] |
||||
end |
||||
|
||||
ANSWER_OPTIONS = { |
||||
"1" => { "value" => "Yes" }, |
||||
"2" => { "value" => "No" }, |
||||
}.freeze |
||||
|
||||
QUESTION_NUMBER_FROM_YEAR = { 2026 => 0 }.freeze |
||||
end |
||||
@ -0,0 +1,17 @@
|
||||
class Form::Sales::Questions::NewServiceCharges < ::Form::Question |
||||
def initialize(id, hsh, page) |
||||
super |
||||
@id = "newservicecharges" |
||||
@type = "numeric" |
||||
@min = 0 |
||||
@max = 9999.99 |
||||
@step = 0.01 |
||||
@width = 5 |
||||
@prefix = "£" |
||||
@copy_key = "sales.sale_information.servicecharges_changed.new_service_charges" |
||||
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] |
||||
@strip_commas = true |
||||
end |
||||
|
||||
QUESTION_NUMBER_FROM_YEAR = { 2026 => 0 }.freeze |
||||
end |
||||
@ -1,3 +1,3 @@
|
||||
<div class="govuk-button-group"> |
||||
<%= govuk_link_to "Clear address and search instead", address_search_input_path(@log.log_type, @log.id), class: "govuk-button govuk-button--secondary" %> |
||||
<%= govuk_link_to "Clear address and search by UPRN instead", address_search_input_path(@log.log_type, @log.id), class: "govuk-button govuk-button--secondary" %> |
||||
</div> |
||||
|
||||
@ -0,0 +1,8 @@
|
||||
class AddServiceChargeChangedToSalesLogs < ActiveRecord::Migration[7.2] |
||||
def change |
||||
change_table :sales_logs, bulk: true do |t| |
||||
t.column :hasservicechargeschanged, :integer |
||||
t.column :newservicecharges, :decimal, precision: 10, scale: 2 |
||||
end |
||||
end |
||||
end |
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,31 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe Form::Sales::Pages::ServiceChargeChanged, type: :model do |
||||
include CollectionTimeHelper |
||||
|
||||
subject(:page) { described_class.new(page_id, page_definition, subsection) } |
||||
|
||||
let(:page_id) { nil } |
||||
let(:page_definition) { nil } |
||||
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: collection_start_date_for_year(2026))) } |
||||
|
||||
it "has correct subsection" do |
||||
expect(page.subsection).to eq(subsection) |
||||
end |
||||
|
||||
it "has correct questions" do |
||||
expect(page.questions.map(&:id)).to eq(%w[hasservicechargeschanged newservicecharges]) |
||||
end |
||||
|
||||
it "has the correct id" do |
||||
expect(page.id).to eq("service_charge_changed") |
||||
end |
||||
|
||||
it "has the correct description" do |
||||
expect(page.description).to be_nil |
||||
end |
||||
|
||||
it "has correct depends_on" do |
||||
expect(page.depends_on).to be_nil |
||||
end |
||||
end |
||||
@ -0,0 +1,56 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe Form::Sales::Questions::HasServiceChargesChanged, type: :model do |
||||
include CollectionTimeHelper |
||||
|
||||
subject(:question) { described_class.new(question_id, question_definition, page) } |
||||
|
||||
let(:question_id) { nil } |
||||
let(:question_definition) { nil } |
||||
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date:)) } |
||||
let(:page) { instance_double(Form::Page, subsection:) } |
||||
let(:start_date) { collection_start_date_for_year(2026) } |
||||
|
||||
it "has correct page" do |
||||
expect(question.page).to eq(page) |
||||
end |
||||
|
||||
it "has the correct id" do |
||||
expect(question.id).to eq("hasservicechargeschanged") |
||||
end |
||||
|
||||
it "has the correct type" do |
||||
expect(question.type).to eq("radio") |
||||
end |
||||
|
||||
it "is not marked as derived" do |
||||
expect(question.derived?(nil)).to be false |
||||
end |
||||
|
||||
it "has the correct answer_options" do |
||||
expect(question.answer_options).to eq({ |
||||
"1" => { "value" => "Yes" }, |
||||
"2" => { "value" => "No" }, |
||||
}) |
||||
end |
||||
|
||||
it "has correct conditional for" do |
||||
expect(question.conditional_for).to eq({ |
||||
"newservicecharges" => [1], |
||||
}) |
||||
end |
||||
|
||||
it "has correct hidden_in_check_answers for" do |
||||
expect(question.hidden_in_check_answers).to eq({ |
||||
"depends_on" => [ |
||||
{ |
||||
"hasservicechargeschanged" => 1, |
||||
}, |
||||
], |
||||
}) |
||||
end |
||||
|
||||
it "has the correct question number" do |
||||
expect(question.question_number).to eq(0) |
||||
end |
||||
end |
||||
@ -0,0 +1,53 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe Form::Sales::Questions::NewServiceCharges, type: :model do |
||||
include CollectionTimeHelper |
||||
|
||||
subject(:question) { described_class.new(question_id, question_definition, page) } |
||||
|
||||
let(:question_id) { nil } |
||||
let(:question_definition) { nil } |
||||
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date:)) } |
||||
let(:page) { instance_double(Form::Page, subsection:) } |
||||
let(:start_date) { collection_start_date_for_year(2026) } |
||||
|
||||
it "has correct page" do |
||||
expect(question.page).to eq(page) |
||||
end |
||||
|
||||
it "has the correct id" do |
||||
expect(question.id).to eq("newservicecharges") |
||||
end |
||||
|
||||
it "has the correct type" do |
||||
expect(question.type).to eq("numeric") |
||||
end |
||||
|
||||
it "is not marked as derived" do |
||||
expect(question.derived?(nil)).to be false |
||||
end |
||||
|
||||
it "has the correct width" do |
||||
expect(question.width).to be 5 |
||||
end |
||||
|
||||
it "has the correct min" do |
||||
expect(question.min).to be 0 |
||||
end |
||||
|
||||
it "has the correct max" do |
||||
expect(question.max).to be 9999.99 |
||||
end |
||||
|
||||
it "has the correct step" do |
||||
expect(question.step).to be 0.01 |
||||
end |
||||
|
||||
it "has the correct prefix" do |
||||
expect(question.prefix).to eq("£") |
||||
end |
||||
|
||||
it "has the correct question number" do |
||||
expect(question.question_number).to eq(0) |
||||
end |
||||
end |
||||
Loading…
Reference in new issue