Skip to content

Commit

Permalink
Merge pull request #2478 from HHS/main
Browse files Browse the repository at this point in the history
[Prod] Goal source bugfix, update python, don't roll up goals, create hidden monitoring goal template, store uncovered code report as build artifact
  • Loading branch information
kryswisnaskas authored Nov 14, 2024
2 parents 06e0675 + a6c7c63 commit 4b59d5f
Show file tree
Hide file tree
Showing 58 changed files with 3,627 additions and 840 deletions.
175 changes: 49 additions & 126 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ executors:
POSTGRES_DB: ttasmarthub
docker-python-executor:
docker:
- image: cimg/python:3.9.19
- image: cimg/python:3.9.20
machine-executor:
machine:
image: ubuntu-2204:current
Expand Down Expand Up @@ -560,10 +560,10 @@ parameters:
type: string
dev_git_branch: # change to feature branch to test deployment
description: "Name of github branch that will deploy to dev"
default: "mb/TTAHUB-3484/insert-standard-goals"
default: "kw-unsafe-inline"
type: string
sandbox_git_branch: # change to feature branch to test deployment
default: "mb/TTAHUB-3478/goal-nudge-version-2"
default: "mb/TTAHUB-3483/checkbox-to-activity-reports"
type: string
prod_new_relic_app_id:
default: "877570491"
Expand All @@ -580,19 +580,7 @@ parameters:
manual-trigger:
type: boolean
default: false
env_list:
description: "List of environments to manage (start/stop)"
type: string
default: "tta-smarthub-dev,tta-smarthub-sandbox"
space_list:
description: "List of Cloud Foundry spaces corresponding to each environment"
type: string
default: ""
env_state:
description: "State of the environment to change (start, stop, restart, restage)"
type: string
default: "none"
manual-manage-env:
fail-on-modified-lines:
type: boolean
default: false
jobs:
Expand Down Expand Up @@ -695,6 +683,9 @@ jobs:
at: .
- setup_remote_docker:
version: default
- run:
name: Add GitHub to known_hosts
command: ssh-keyscan -H github.com >> ~/.ssh/known_hosts
- run:
name: Run migrations ci
command: yarn db:migrate:ci
Expand All @@ -711,6 +702,19 @@ jobs:
command: |
chmod 744 ./bin/test-backend-ci
./bin/test-backend-ci
# Run coverage check script
- run:
name: Check coverage for modified lines
command: |
if [ -n "${CIRCLE_PULL_REQUEST}" ]; then
chmod +x ./tools/check-coverage.js
node -r esm ./tools/check-coverage.js \
--fail-on-uncovered=<< pipeline.parameters.fail-on-modified-lines >> \
--output-format=json,html
else
echo "Not a PR build. Skipping coverage check."
fi
when: always
- run:
name: Compress coverage artifacts
command: tar -cvzf backend-coverage-artifacts.tar coverage/
Expand All @@ -720,6 +724,10 @@ jobs:
path: backend-coverage-artifacts.tar
- store_test_results:
path: reports/
# Store uncovered lines artifact if exists
- store_artifacts:
path: coverage-artifacts/
destination: uncovered-lines
resource_class: large
test_similarity_api:
executor: docker-python-executor
Expand Down Expand Up @@ -775,13 +783,37 @@ jobs:
command: |
chmod 744 ./checkcolorhash.sh
./checkcolorhash.sh;
- run:
name: Add GitHub to known_hosts
command: |
mkdir -p /home/circleci/.ssh
ssh-keyscan -H github.com >> /home/circleci/.ssh/known_hosts
- run:
name: Test frontend
command: yarn --cwd frontend run test:ci --maxWorkers=50%
- run:
name: Check coverage for modified lines
command: |
if [ -n "${CIRCLE_PULL_REQUEST}" ]; then
chmod +x ./tools/check-coverage.js
node -r esm ./tools/check-coverage.js \
--coverage-file=../frontend/coverage/coverage-final.json \
--artifact-dir=../frontend/coverage-artifacts \
--directory-filter=frontend/ \
--fail-on-uncovered=<< pipeline.parameters.fail-on-modified-lines >> \
--output-format=json,html
else
echo "Not a PR build. Skipping coverage check."
fi
when: always
- store_test_results:
path: frontend/reports/
- store_artifacts:
path: frontend/coverage/
- store_artifacts:
path: frontend/coverage-artifacts/
destination: uncovered-lines
resource_class: large
test_e2e:
executor: docker-postgres-executor
Expand Down Expand Up @@ -1264,88 +1296,10 @@ jobs:
rds_service_name: ttahub-prod
s3_service_name: ttahub-db-backups
backup_prefix: production
manage_env_apps:
executor: docker-executor
parameters:
env_list:
type: string
description: "Comma-separated list of environments to manage"
default: "<< pipeline.parameters.env_list >>"
env_state:
type: string
description: "Action to perform on apps (start, stop, restart, restage)"
default: "<< pipeline.parameters.env_state >>"
steps:
- run:
name: Install Cloud Foundry CLI
command: |
curl -v -L -o cf-cli_amd64.deb 'https://packages.cloudfoundry.org/stable?release=debian64&version=v7&source=github'
sudo dpkg -i cf-cli_amd64.deb
- run:
name: Manage Apps
command: |
set -x
env_list="<< parameters.env_list >>"
env_state="<< parameters.env_state >>"
# Split env_list manually
apps=(${env_list//,/ })
for env in "${apps[@]}"; do
# Map full environment name to variable prefixes
if [[ "$env" == "tta-smarthub-sandbox" ]]; then
prefix="SANDBOX"
elif [[ "$env" == "tta-smarthub-dev" ]]; then
prefix="DEV"
else
echo "Unrecognized environment: $env"
exit 1
fi
# Retrieve the environment-specific variables
space_var="CLOUDGOV_${prefix}_SPACE"
username_var="CLOUDGOV_${prefix}_USERNAME"
password_var="CLOUDGOV_${prefix}_PASSWORD"
space="${!space_var}"
username="${!username_var}"
password="${!password_var}"
echo "Logging into space: $space for environment: $env"
cf login \
-a << pipeline.parameters.cg_api >> \
-u "$username" \
-p "$password" \
-o << pipeline.parameters.cg_org >> \
-s "$space"
# Get the current state of the app
state=$(cf app "$env" | grep "state:" | awk '{print $2}')
# Control app state based on env_state parameter
if [[ "$env_state" == "stop" && "$state" != "stopped" ]]; then
echo "Stopping $env..."
cf stop "$env"
elif [[ "$env_state" == "start" && "$state" != "started" ]]; then
echo "Starting $env..."
cf start "$env"
elif [[ "$env_state" == "restart" ]]; then
echo "Restarting $env..."
cf restart "$env"
elif [[ "$env_state" == "restage" ]]; then
echo "Restaging $env..."
cf restage "$env"
else
echo "$env is already in the desired state: $state"
fi
done
workflows:
build_test_deploy:
when:
and:
# Ensure the workflow is only triggered when `manual-trigger` is false
# and `env_state` is empty (i.e., it's not for starting/stopping environments)
- equal: [false, << pipeline.parameters.manual-trigger >>]
- equal: [false, << pipeline.parameters.manual-manage-env >>]
equal: [false, << pipeline.parameters.manual-trigger >>]
jobs:
- build_and_lint
- build_and_lint_similarity_api
Expand Down Expand Up @@ -1453,34 +1407,3 @@ workflows:
equal: [true, << pipeline.parameters.manual-trigger >>]
jobs:
- backup_upload_production
stop_lower_env_workflow:
triggers:
- schedule:
cron: "0 1 * * 2-6" # Runs at 6 PM PST M-F (1 AM UTC next day)
filters:
branches:
only:
- main
jobs:
- manage_env_apps:
env_state: "stop"
env_list: "<< pipeline.parameters.env_list >>"
start_lower_env_workflow:
triggers:
- schedule:
cron: "0 11 * * 1-5" # Runs at 6 AM EST M-F(11 AM UTC)
filters:
branches:
only:
- main
jobs:
- manage_env_apps:
env_state: "start"
env_list: "<< pipeline.parameters.env_list >>"
manual_manage_env_workflow:
when:
equal: [true, << pipeline.parameters.manual-manage-env >>]
jobs:
- manage_env_apps:
env_state: "<< pipeline.parameters.env_state >>"
env_list: "<< pipeline.parameters.env_list >>"
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ On the frontend, the lcov and HTML files are generated as normal, however on the
Another important note for running tests on the backend - we specifically exclude files on the backend that follow the ```*CLI.js``` naming convention (for example, ```adminToolsCLI.js```) from test coverage. This is meant to exclude files intended to be run in the shell. Any functionality in theses files should be imported from a file that is tested. The ```src/tools folder``` is where these files have usually lived and there are lots of great examples of the desired pattern in that folder.
### Coverage reports: Uncovered lines on PR builds
The uncovered lines on PR is generated by finding the intersection between the jest generated coverage file with the git change list for the PR. The additional set of artifacts is generated to aid in providing test coverage for each PR.
* coverage/coverage-final.json - Only on test_backend, all the distinct jest run outputs are consolidated into a unified coverage-final.json file.
* uncovered-lines/uncovered-lines.html - A human readable structure identifing all the lines from this PR that are uncovered by jest tests.
* uncovered-lines/uncovered-lines.json - A json structure identifing all the lines from this PR that are uncovered by jest tests.
This Uncovered lines on PR builds can be configured to fail builds by either perminently changing or overiding the pipeline perameter ```fail-on-modified-lines``` to true, defaults to false.
## Yarn Commands
Expand Down
29 changes: 29 additions & 0 deletions bin/test-backend-ci
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,35 @@ main(){
log "Errors occurred during script execution"
fi

#run tests on tools
node_modules/.bin/cross-env \
JEST_JUNIT_OUTPUT_DIR=reports \
JEST_JUNIT_OUTPUT_NAME="tools".xml \
POSTGRES_USERNAME=postgres \
POSTGRES_DB=ttasmarthub \
CURRENT_USER_ID=5 \
CI=true \
node \
--expose-gc \
./node_modules/.bin/jest \
tools \
--coverage \
--colors \
--reporters=jest-junit \
--reporters=default \
--runInBand \
--silent \
--colors \
--logHeapUsage \
--coverageDirectory="$(pwd)"/coverage/tools \
--collectCoverageFrom="tools/**/!(*CLI).{js,ts}" \
--forceExit

check_exit "$?"

# Merge coverage reports
node ./tools/merge-coverage.js

exit "$exit_code"
}

Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/ExpanderButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default function ExpanderButton({
className={`usa-button--outline usa-button text-no-underline text-middle tta-smarthub--expander-row-${type}s tta-smarthub--expander-row-${type}s-enabled`}
onClick={() => closeOrOpen()}
aria-label={`${expanded ? 'Hide' : 'View'} ${ariaLabel}`}
data-testid="expander-button"
>
{expanded ? 'Hide' : 'View'}
{' '}
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/GoalCards/ObjectiveCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function ObjectiveCard({
<ObjectiveStatusDropdown
currentStatus={localStatus}
goalStatus={goalStatus}
objectiveId={objective.id}
objectiveTitle={objective.title}
regionId={regionId}
className="line-height-sans-5"
onUpdateObjectiveStatus={onUpdateObjectiveStatus}
Expand Down Expand Up @@ -192,7 +192,6 @@ function ObjectiveCard({
}

export const objectivePropTypes = PropTypes.shape({
id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
endDate: PropTypes.string,
reasons: PropTypes.arrayOf(PropTypes.string),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export default function ObjectiveStatusDropdown({
onUpdateObjectiveStatus,
regionId,
className,
objectiveId,
goalStatus,
forceReadOnly,
objectiveTitle,
}) {
const { user } = useContext(UserContext);
const [statusOptions, isReadOnly] = useValidObjectiveStatuses(
Expand Down Expand Up @@ -44,7 +44,7 @@ export default function ObjectiveStatusDropdown({

return (
<StatusDropdown
label={`Change status for objective ${objectiveId}`}
label={`Change status for objective ${objectiveTitle}`}
options={options}
className={className}
icon={icon}
Expand All @@ -57,15 +57,16 @@ ObjectiveStatusDropdown.propTypes = {
onUpdateObjectiveStatus: PropTypes.func.isRequired,
goalStatus: PropTypes.string,
currentStatus: PropTypes.string,
objectiveId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
regionId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
className: PropTypes.string,
forceReadOnly: PropTypes.bool,
objectiveTitle: PropTypes.string,
};

ObjectiveStatusDropdown.defaultProps = {
goalStatus: '',
currentStatus: '',
objectiveTitle: '',
className: '',
forceReadOnly: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('ObjectiveStatusDropdown', () => {
onUpdateObjectiveStatus={onUpdate}
forceReadOnly={forceReadOnly}
regionId={1}
objectiveId={345345}
objectiveTitle={345345}
goalStatus="In Progress"
className="test-class"
/>
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/components/GoalForm/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,18 @@ describe('create goal', () => {
const save = await screen.findByRole('button', { name: /save/i });
userEvent.click(save);

const sourceValidation = await screen.findByText('Select a goal source');
expect(sourceValidation).toBeVisible();

await act(async () => {
const source = await screen.findByRole('combobox', { name: /goal source/i });
userEvent.selectOptions(source, 'Federal monitoring issues, including CLASS and RANs');
});

act(() => {
userEvent.click(save);
});

let alert = await screen.findByRole('alert');
expect(alert.textContent).toBe('There was an error saving your goal');

Expand Down
Loading

0 comments on commit 4b59d5f

Please sign in to comment.