diff --git a/.circleci/config.yml b/.circleci/config.yml index 828cc9bbe4..5cb8ce2352 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -199,11 +199,10 @@ commands: working_directory: integration-tests name: Slack notification on dev branch only command: | - if [ "$CIRCLE_NODE_INDEX" -eq 0 ] && [ "$CIRCLE_BRANCH" = "dev" ]; then + if [ "$CIRCLE_NODE_INDEX" -eq 0 ] && [ "$CIRCLE_BRANCH" = "alex-ci-testing" ]; then bash ../.circleci/wait-for-job-finish.sh node --require ../.pnp.cjs ./slack/notify-circleci-test-results.js fi - no_output_timeout: 30m when: always jobs: @@ -227,18 +226,7 @@ jobs: fi - run: yarn run build - run: yarn eslint --max-warnings=0 . - - run: yarn workspaces foreach --exclude terra-integration-tests run test --coverage --maxWorkers=2 --passWithNoTests - - store_artifacts: - path: test-report/index.html - - run: yarn check-types - - save_cache: - key: deps-{{ .Branch }}-{{ checksum ".pnp.cjs" }} - paths: - - .yarn/unplugged - - node_modules/.cache - run: tar -czf build.tgz .gcloudignore app.yaml build config - - store_artifacts: - path: build.tgz - persist_to_workspace: root: . paths: @@ -295,10 +283,6 @@ workflows: <<: *filter-pr-branch requires: - build - - deploy-pr: - <<: *filter-pr-branch - requires: - - build - deploy-dev: <<: *filter-dev-branch requires: diff --git a/.circleci/wait-for-job-finish.sh b/.circleci/wait-for-job-finish.sh index 7d9531dfa5..a60a3a4d89 100755 --- a/.circleci/wait-for-job-finish.sh +++ b/.circleci/wait-for-job-finish.sh @@ -6,26 +6,40 @@ set -o nounset # Use the error status of the first failure, rather than that of the last item in a pipeline. Also fail explicitly on any exit code. set -eo pipefail +trap 's=$?; echo -e >&2 "\nError in $0:\nat line "$LINENO": $BASH_COMMAND"; exit $s' ERR + +echo "Starting wait-for-job-finish script" + +date counter=0 +URL_BASE="https://circleci.com/api/v2/project/github/DataBiosphere/terra-ui" + +# Wait up to 30 minutes for job to finish. A job can run on multiple nodes: parallelism > 1 +while [ "$counter" -le 1800 ]; do + counter=$(($counter + 10)) + sleep 10 -# Wait up to 25 minutes for job to finish. A job can run on multiple nodes: parallelism > 1 -while [ "$counter" -le 1500 ]; do - # Find number of nodes in running - job_detail=$(curl -s "https://circleci.com/api/v2/project/github/DataBiosphere/terra-ui/job/$CIRCLE_BUILD_NUM") - job_running_nodes_count=$(echo "$job_detail" | jq -r '[.parallel_runs[] | select(.status == "running") | select(.index != '"$CIRCLE_NODE_INDEX"')] | length') + # Get job details + job_detail=$(curl -s "$URL_BASE/job/$CIRCLE_BUILD_NUM") - if [ "$job_running_nodes_count" -eq 0 ]; then - exit 0 + # Wait for all nodes with status==running excluding self node + nodes=$(echo "$job_detail" | jq -r '.parallel_runs[]') + running_nodes=$(echo "$nodes" | jq -r --arg IDX "$CIRCLE_NODE_INDEX" 'select(.status=="running") | select(.index|tostring!=$IDX)') + count=$(echo "$running_nodes" | grep -c -e "running" || test $? = 1;) + + if [ "$count" -eq 0 ]; then + echo "Checking from NODE_INDEX #$CIRCLE_NODE_INDEX: Parallel running nodes have finished. Waited $counter seconds." + echo "$nodes" + + artifacts=$(curl -s "$URL_BASE/$CIRCLE_BUILD_NUM/artifacts") + echo "$artifacts" + exit 0 fi - sleep 10 - counter=$(($counter + 10)) + echo "Checking from NODE_INDEX #$CIRCLE_NODE_INDEX: Waiting for parallel running nodes to finish." done -echo "Waited total $counter seconds" -date - # Something is wrong. Log response for error troubleshooting curl -s "https://circleci.com/api/v2/project/github/DataBiosphere/terra-ui/job/$CIRCLE_BUILD_NUM" | jq -r '.' -echo "ERROR: Exceeded maximum waiting time 25 minutes." +echo "ERROR: Exceeded maximum wait time 25 minutes." exit 1 diff --git a/integration-tests/slack/circleci-utils.js b/integration-tests/slack/circleci-utils.js index 94bb4d7cf3..1c8e902b99 100644 --- a/integration-tests/slack/circleci-utils.js +++ b/integration-tests/slack/circleci-utils.js @@ -18,8 +18,15 @@ const fetchJobArtifacts = async ({ buildNum = process.env.CIRCLE_BUILD_NUM } = { try { // Because terra-ui is a public repository on GitHub, API token is not required. See: https://circleci.com/docs/oss#security const response = await fetch(`${apiUrlRoot}/${buildNum}/artifacts`); + const resp = await response.json(); + console.log(`response json: ${JSON.stringify(resp, null, 2)}`); + const { items } = await response.json(); - const testSummaryArtifacts = _.filter(_.flow(_.get('path'), _.includes('tests-summary')), items); + const itm = JSON.stringify(items, null, 2); + console.log(`items: ${itm}`); + + const testSummaryArtifacts = _.filter(_.flow(_.get('path'), _.includes('tests-summary-')), items); + console.log(`testSummaryArtifacts: ${testSummaryArtifacts}`); return _.map('url', testSummaryArtifacts); } catch (e) { console.error(`** ERROR: Encountered error when getting CircleCI JOB_BUILD_NUM: ${buildNum} artifacts.`, e); @@ -33,6 +40,8 @@ const fetchJobArtifacts = async ({ buildNum = process.env.CIRCLE_BUILD_NUM } = { * @returns {Array[string]} */ const getFailedTestNames = (aggregatedResults) => { + console.log(`aggregatedResults.testResults: ${aggregatedResults.testResults}`); + console.log('**'); return _.flow( _.filter((testResult) => testResult.numFailingTests > 0), _.map((testResult) => parse(testResult.testFilePath).name) @@ -45,6 +54,7 @@ const getFailedTestNames = (aggregatedResults) => { */ const getFailedTestNamesFromArtifacts = async () => { const urls = await fetchJobArtifacts(); + console.log(`urls: ${urls}`); return _.flatten( await Promise.all( _.map(async (url) => { diff --git a/integration-tests/slack/notify-circleci-test-results.js b/integration-tests/slack/notify-circleci-test-results.js index 446725b0e8..e4749fd206 100644 --- a/integration-tests/slack/notify-circleci-test-results.js +++ b/integration-tests/slack/notify-circleci-test-results.js @@ -1,6 +1,8 @@ const _ = require('lodash/fp'); const { getFailedTestNamesFromArtifacts } = require('./circleci-utils'); +// eslint-disable-next-line @typescript-eslint/no-unused-vars const { getMessageBlockTemplate } = require('./message-templates'); +// eslint-disable-next-line @typescript-eslint/no-unused-vars const { postMessage } = require('./post-message'); const testsInfo = require('./slack-notify-channels.json'); @@ -8,6 +10,7 @@ const testsInfo = require('./slack-notify-channels.json'); * Get array of Slack channel IDs for succeeded job notification * @returns {Array[string]} */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars const getAllSlackChannelsForPassedJob = () => { return _.map('id', testsInfo.pass); }; @@ -31,6 +34,7 @@ const getAllSlackChannelsForFailedJob = () => { * @param {Array[string]} failedTests * @returns {Map} A map object where key is channel_id, value is test_names array */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars const getFailedTestsAndChannelIDs = (failedTests) => { const allChannelsAndTests = getAllSlackChannelsForFailedJob(); @@ -53,7 +57,8 @@ const getFailedTestsAndChannelIDs = (failedTests) => { // Post CircleCI UI test report to Slack channels const notifyCircleCITestResults = async () => { const failedTestNames = await getFailedTestNamesFromArtifacts(); - + console.log(`failedTestNames: ${failedTestNames}`); + /* if (failedTestNames.length === 0) { // Slack notification: CircleCI job succeeded const channelIDs = getAllSlackChannelsForPassedJob(); @@ -70,7 +75,7 @@ const notifyCircleCITestResults = async () => { console.log(`Notifying channel ${channelId} of ${testNames.length} test failures (${testNames.join(', ')})`); const messageBlocks = getMessageBlockTemplate(testNames); await postMessage({ channel: channelId, blocks: messageBlocks }); - }, _.toPairs(channelIDsAndNames)); + }, _.toPairs(channelIDsAndNames)); */ }; (async () => {