From 285373e51ef4fd42ca80700615debbf2a36dd103 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Sat, 17 Aug 2024 10:50:30 +1000 Subject: [PATCH] [#1065] Fixed failing GitHub notifications. --- .lagoon.yml | 3 +- .scaffold/.ahoy.yml | 5 + .../docs/content/workflows/variables.mdx | 8 +- .scaffold/tests/bats/notify.bats | 160 +++++++++++++++++- hooks/library/notify-deployment.sh | 2 +- scripts/drevops/notify-github.sh | 31 ++-- 6 files changed, 186 insertions(+), 23 deletions(-) diff --git a/.lagoon.yml b/.lagoon.yml index d1053b69b..5d35c29e9 100644 --- a/.lagoon.yml +++ b/.lagoon.yml @@ -92,10 +92,11 @@ tasks: DREVOPS_NOTIFY_EVENT=post_deployment \ DREVOPS_NOTIFY_PROJECT=$LAGOON_PROJECT \ DREVOPS_NOTIFY_ENVIRONMENT_URL=$LAGOON_ROUTE \ - ./scripts/drevops/notify.sh + ./scripts/drevops/notify.sh || true service: cli shell: bash #;> !NOTIFICATIONS + environments: # Branch name that represents production environment. main: diff --git a/.scaffold/.ahoy.yml b/.scaffold/.ahoy.yml index fc3912ecf..f8265f935 100644 --- a/.scaffold/.ahoy.yml +++ b/.scaffold/.ahoy.yml @@ -28,6 +28,11 @@ commands: ahoy test-common ahoy test-docs + test-bats: + cmd: | + [ ! -d tests/node_modules ] && ahoy install + tests/node_modules/.bin/bats "$@" + test-common: cmd: ./tests/test.common.sh diff --git a/.scaffold/docs/content/workflows/variables.mdx b/.scaffold/docs/content/workflows/variables.mdx index 6e257fdce..482ac46f8 100644 --- a/.scaffold/docs/content/workflows/variables.mdx +++ b/.scaffold/docs/content/workflows/variables.mdx @@ -931,11 +931,11 @@ Defined in: `scripts/drevops/mirror-code.sh` ### `DREVOPS_NOTIFY_BRANCH` -Deployment reference, such as a git SHA. +Deployment reference branch. Default value: `UNDEFINED` -Defined in: `scripts/drevops/notify-jira.sh` +Defined in: `scripts/drevops/notify-github.sh`, `scripts/drevops/notify-jira.sh` ### `DREVOPS_NOTIFY_CHANNELS` @@ -1167,11 +1167,11 @@ Defined in: `scripts/drevops/notify-webhook.sh`, `scripts/drevops/notify.sh` ### `DREVOPS_NOTIFY_REF` -Deployment reference, such as a git SHA. +Git reference to notify about. Default value: `UNDEFINED` -Defined in: `scripts/drevops/notify-github.sh`, `scripts/drevops/notify-webhook.sh` +Defined in: `scripts/drevops/notify-webhook.sh` ### `DREVOPS_NOTIFY_REPOSITORY` diff --git a/.scaffold/tests/bats/notify.bats b/.scaffold/tests/bats/notify.bats index 4efd6d084..553cdea46 100644 --- a/.scaffold/tests/bats/notify.bats +++ b/.scaffold/tests/bats/notify.bats @@ -118,7 +118,7 @@ load _helper.bash declare -a STEPS=( "Started dispatching notifications." "Started GitHub notification for pre_deployment event." - "@curl -X POST -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments -d {\"ref\":\"mybranch\", \"environment\": \"PR\", \"auto_merge\": false} # {\"id\": \"${app_id}\", \"othervar\": \"54321\"}" + "@curl -X POST -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments -d {\"ref\":\"existingbranch\", \"environment\": \"PR\", \"auto_merge\": false} # {\"id\": \"${app_id}\", \"othervar\": \"54321\"}" "Marked deployment as started." "Finished GitHub notification for pre_deployment event." "Finished dispatching notifications." @@ -130,7 +130,7 @@ load _helper.bash export DREVOPS_NOTIFY_EVENT="pre_deployment" export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" - export DREVOPS_NOTIFY_REF="mybranch" + export DREVOPS_NOTIFY_BRANCH="existingbranch" run ./scripts/drevops/notify.sh assert_success @@ -139,6 +139,62 @@ load _helper.bash popd >/dev/null || exit 1 } +@test "Notify: github, pre_deployment, longer ID" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + app_id="12345678987" + + declare -a STEPS=( + "Started dispatching notifications." + "Started GitHub notification for pre_deployment event." + "@curl -X POST -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments -d {\"ref\":\"existingbranch\", \"environment\": \"PR\", \"auto_merge\": false} # {\"id\": \"${app_id}\", \"othervar\": \"54321\"}" + "Marked deployment as started." + "Finished GitHub notification for pre_deployment event." + "Finished dispatching notifications." + ) + + mocks="$(run_steps "setup")" + + export DREVOPS_NOTIFY_CHANNELS="github" + export DREVOPS_NOTIFY_EVENT="pre_deployment" + export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" + export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" + export DREVOPS_NOTIFY_BRANCH="existingbranch" + run ./scripts/drevops/notify.sh + assert_success + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + +@test "Notify: github, pre_deployment, failure" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + declare -a STEPS=( + "Started dispatching notifications." + "Started GitHub notification for pre_deployment event." + "@curl -X POST -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments -d {\"ref\":\"nonexistingbranch\", \"environment\": \"PR\", \"auto_merge\": false} # {\"message\": \"No ref found for: nonexistingbranch\",\"documentation_url\": \"https://docs.github.com/rest/deployments/deployments#create-a-deployment\",\"status\": \"422\"}" + "Failed to get a deployment ID for a pre_deployment operation. Payload:" + "Wait for GitHub checks to finish and try again." + "-Marked deployment as finished." + ) + + mocks="$(run_steps "setup")" + + export DREVOPS_NOTIFY_CHANNELS="github" + export DREVOPS_NOTIFY_EVENT="pre_deployment" + export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" + export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" + export DREVOPS_NOTIFY_BRANCH="nonexistingbranch" + run ./scripts/drevops/notify.sh + assert_failure + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + @test "Notify: github, post_deployment" { pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 @@ -148,8 +204,39 @@ load _helper.bash declare -a STEPS=( "Started dispatching notifications." "Started GitHub notification for post_deployment event." - "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=mybranch # [{\"id\": \"${app_id}\", \"othervar\": \"54321\"},{\"id\": \"98765432101\", \"othervar\": \"12345\"}]" - "@curl -X POST -H Accept: application/vnd.github.v3+json -H Authorization: token token12345 https://api.github.com/repos/myorg/myrepo/deployments/123456789/statuses -s -d {\"state\":\"success\", \"environment_url\": \"https://develop.testproject.com\"} # {\"state\": \"success\", \"othervar\": \"54321\"}" + "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=existingbranch # [{\"id\": \"${app_id}\", \"othervar\": \"54321\"},{\"id\": \"98765432101\", \"othervar\": \"12345\"}]" + "@curl -X POST -H Accept: application/vnd.github.v3+json -H Authorization: token token12345 https://api.github.com/repos/myorg/myrepo/deployments/${app_id}/statuses -s -d {\"state\":\"success\", \"environment_url\": \"https://develop.testproject.com\"} # {\"state\": \"success\", \"othervar\": \"54321\"}" + "Marked deployment as finished." + "Finished GitHub notification for post_deployment event." + "Finished dispatching notifications." + ) + mocks="$(run_steps "setup")" + + export DREVOPS_NOTIFY_CHANNELS="github" + export DREVOPS_NOTIFY_EVENT="post_deployment" + export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" + export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" + export DREVOPS_NOTIFY_BRANCH="existingbranch" + export DREVOPS_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com" + run ./scripts/drevops/notify.sh + assert_success + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + +@test "Notify: github, post_deployment, longer ID" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + app_id="12345678987" + mock_curl=$(mock_command "curl") + + declare -a STEPS=( + "Started dispatching notifications." + "Started GitHub notification for post_deployment event." + "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=existingbranch # [{\"id\": \"${app_id}\", \"othervar\": \"54321\"},{\"id\": \"98765432101\", \"othervar\": \"12345\"}]" + "@curl -X POST -H Accept: application/vnd.github.v3+json -H Authorization: token token12345 https://api.github.com/repos/myorg/myrepo/deployments/${app_id}/statuses -s -d {\"state\":\"success\", \"environment_url\": \"https://develop.testproject.com\"} # {\"state\": \"success\", \"othervar\": \"54321\"}" "Marked deployment as finished." "Finished GitHub notification for post_deployment event." "Finished dispatching notifications." @@ -160,7 +247,7 @@ load _helper.bash export DREVOPS_NOTIFY_EVENT="post_deployment" export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" - export DREVOPS_NOTIFY_REF="mybranch" + export DREVOPS_NOTIFY_BRANCH="existingbranch" export DREVOPS_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com" run ./scripts/drevops/notify.sh assert_success @@ -170,6 +257,65 @@ load _helper.bash popd >/dev/null || exit 1 } +@test "Notify: github, post_deployment, failure to get id" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + mock_curl=$(mock_command "curl") + + declare -a STEPS=( + "Started dispatching notifications." + "Started GitHub notification for post_deployment event." + "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=nonexistingbranch # []" + "Failed to get a deployment ID for a post_deployment operation. Payload:" + "Check that a pre_deployment notification was dispatched." + "-Marked deployment as finished." + ) + mocks="$(run_steps "setup")" + + export DREVOPS_NOTIFY_CHANNELS="github" + export DREVOPS_NOTIFY_EVENT="post_deployment" + export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" + export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" + export DREVOPS_NOTIFY_BRANCH="nonexistingbranch" + export DREVOPS_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com" + run ./scripts/drevops/notify.sh + assert_failure + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + +@test "Notify: github, post_deployment, failure to set status" { + pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 + + app_id="12345678987" + mock_curl=$(mock_command "curl") + + declare -a STEPS=( + "Started dispatching notifications." + "Started GitHub notification for post_deployment event." + "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=existingbranch # [{\"id\": \"${app_id}\", \"othervar\": \"54321\"},{\"id\": \"98765432101\", \"othervar\": \"12345\"}]" + "@curl -X POST -H Accept: application/vnd.github.v3+json -H Authorization: token token12345 https://api.github.com/repos/myorg/myrepo/deployments/${app_id}/statuses -s -d {\"state\":\"success\", \"environment_url\": \"https://develop.testproject.com\"} # {\"state\": \"notsuccess\", \"othervar\": \"54321\"}" + "Previous deployment was found, but was unable to update the deployment status. Payload:" + "-Marked deployment as finished." + ) + mocks="$(run_steps "setup")" + + export DREVOPS_NOTIFY_CHANNELS="github" + export DREVOPS_NOTIFY_EVENT="post_deployment" + export DREVOPS_NOTIFY_GITHUB_TOKEN="token12345" + export DREVOPS_NOTIFY_REPOSITORY="myorg/myrepo" + export DREVOPS_NOTIFY_BRANCH="existingbranch" + export DREVOPS_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com" + run ./scripts/drevops/notify.sh + assert_failure + + run_steps "assert" "${mocks[@]}" + + popd >/dev/null || exit 1 +} + @test "Notify: jira" { pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 @@ -215,7 +361,7 @@ load _helper.bash popd >/dev/null || exit 1 } -@test "Notify: webhook success" { +@test "Notify: webhook" { pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 mock_curl=$(mock_command "curl") @@ -245,7 +391,7 @@ load _helper.bash popd >/dev/null || exit 1 } -@test "Notify: webhook failure" { +@test "Notify: webhook, failure" { pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1 mock_curl=$(mock_command "curl") diff --git a/hooks/library/notify-deployment.sh b/hooks/library/notify-deployment.sh index b0711b175..f4e18e71e 100755 --- a/hooks/library/notify-deployment.sh +++ b/hooks/library/notify-deployment.sh @@ -31,6 +31,6 @@ export DREVOPS_NOTIFY_REF="${ref}" export DREVOPS_NOTIFY_SHA="${target_env}" export DREVOPS_NOTIFY_ENVIRONMENT_URL="${url}" -./scripts/drevops/notify.sh +./scripts/drevops/notify.sh || true popd >/dev/null || exit 1 diff --git a/scripts/drevops/notify-github.sh b/scripts/drevops/notify-github.sh index 24f55b259..96495c3aa 100755 --- a/scripts/drevops/notify-github.sh +++ b/scripts/drevops/notify-github.sh @@ -22,8 +22,8 @@ DREVOPS_NOTIFY_GITHUB_TOKEN="${DREVOPS_NOTIFY_GITHUB_TOKEN:-${GITHUB_TOKEN}}" # Deployment repository. DREVOPS_NOTIFY_REPOSITORY="${DREVOPS_NOTIFY_REPOSITORY:-}" -# Deployment reference, such as a git SHA. -DREVOPS_NOTIFY_REF="${DREVOPS_NOTIFY_REF:-}" +# Deployment reference branch. +DREVOPS_NOTIFY_BRANCH="${DREVOPS_NOTIFY_BRANCH:-}" # The event to notify about. Can be 'pre_deployment' or 'post_deployment'. DREVOPS_NOTIFY_EVENT="${DREVOPS_NOTIFY_EVENT:-}" @@ -50,7 +50,7 @@ for cmd in php curl; do command -v ${cmd} >/dev/null || { [ -z "${DREVOPS_NOTIFY_GITHUB_TOKEN}" ] && fail "Missing required value for DREVOPS_NOTIFY_GITHUB_TOKEN" && exit 1 [ -z "${DREVOPS_NOTIFY_REPOSITORY}" ] && fail "Missing required value for DREVOPS_NOTIFY_REPOSITORY" && exit 1 -[ -z "${DREVOPS_NOTIFY_REF}" ] && fail "Missing required value for DREVOPS_NOTIFY_REF" && exit 1 +[ -z "${DREVOPS_NOTIFY_BRANCH}" ] && fail "Missing required value for DREVOPS_NOTIFY_BRANCH" && exit 1 [ -z "${DREVOPS_NOTIFY_EVENT}" ] && fail "Missing required value for DREVOPS_NOTIFY_EVENT" && exit 1 [ -z "${DREVOPS_NOTIFY_ENVIRONMENT_TYPE}" ] && fail "Missing required value for DREVOPS_NOTIFY_ENVIRONMENT_TYPE" && exit 1 @@ -79,12 +79,16 @@ if [ "${DREVOPS_NOTIFY_EVENT}" = "pre_deployment" ]; then -H "Accept: application/vnd.github.v3+json" \ -s \ "https://api.github.com/repos/${DREVOPS_NOTIFY_REPOSITORY}/deployments" \ - -d "{\"ref\":\"${DREVOPS_NOTIFY_REF}\", \"environment\": \"${DREVOPS_NOTIFY_ENVIRONMENT_TYPE}\", \"auto_merge\": false}")" + -d "{\"ref\":\"${DREVOPS_NOTIFY_BRANCH}\", \"environment\": \"${DREVOPS_NOTIFY_ENVIRONMENT_TYPE}\", \"auto_merge\": false}")" - deployment_id="$(echo "${payload}" | extract_json_value "id")" + deployment_id="$(echo "${payload}" | extract_json_value "id" || true)" # Check deployment ID. - { [ "${#deployment_id}" -lt 9 ] || [ "${#deployment_id}" -gt 11 ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; } && fail "Failed to get a deployment ID for a started operation. Payload: ${payload}" && exit 1 + if [ -z "${deployment_id}" ] || [ "${#deployment_id}" -lt 9 ] || [ "${#deployment_id}" -gt 11 ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; then + fail "Failed to get a deployment ID for a ${DREVOPS_NOTIFY_EVENT} operation. Payload: ${payload}" + fail "Wait for GitHub checks to finish and try again." + exit 1 + fi note "Marked deployment as started." else @@ -96,12 +100,16 @@ else -H "Authorization: token ${DREVOPS_NOTIFY_GITHUB_TOKEN}" \ -H "Accept: application/vnd.github.v3+json" \ -s \ - "https://api.github.com/repos/${DREVOPS_NOTIFY_REPOSITORY}/deployments?ref=${DREVOPS_NOTIFY_REF}")" + "https://api.github.com/repos/${DREVOPS_NOTIFY_REPOSITORY}/deployments?ref=${DREVOPS_NOTIFY_BRANCH}")" - deployment_id="$(echo "${payload}" | extract_json_first_value "id")" + deployment_id="$(echo "${payload}" | extract_json_first_value "id" || true)" # Check deployment ID. - { [ "${#deployment_id}" -lt 9 ] || [ "${#deployment_id}" -gt 11 ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; } && fail "Failed to get a deployment ID for a finished operation. Payload: ${payload}" && exit 1 + if [ -z "${deployment_id}" ] || [ "${#deployment_id}" -lt 9 ] || [ "${#deployment_id}" -gt 11 ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; then + fail "Failed to get a deployment ID for a ${DREVOPS_NOTIFY_EVENT} operation. Payload: ${payload}" + fail "Check that a pre_deployment notification was dispatched." + exit 1 + fi # Post status update. payload="$(curl \ @@ -114,7 +122,10 @@ else status="$(echo "${payload}" | extract_json_value "state")" - [ "${status}" != "success" ] && fail "Unable to set deployment status" && exit 1 + if [ "${status}" != "success" ]; then + fail "Previous deployment was found, but was unable to update the deployment status. Payload: ${payload}" + exit 1 + fi note "Marked deployment as finished." fi