Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 61 additions & 70 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,63 +97,71 @@ jobs:
path: /home/circleci/e2e-sdk-modular/reports
destination: test-report
- run:
name: Parse and send E2E test results to Slack
name: Parse and send test results to Slack
when: always
command: |
MOCHAWESOME_JSON_FILE=/home/circleci/e2e-sdk-modular/reports/aggregated-report.json
FAILED_TESTS_FILE=failed-tests.txt
# same parsing + slack notification script as before...

publish-npm-package:
working_directory: ~/etherspot-modular-sdk
docker:
- image: cimg/node:20.11.1
auth:
username: $DOCKERHUB_USER
password: $DOCKERHUB_PASSWORD
steps:
- checkout
- run:
name: Install Bun
command: |
curl -fsSL https://bun.sh/install | bash
echo 'export BUN_INSTALL="$HOME/.bun"' >> $BASH_ENV
echo 'export PATH="$BUN_INSTALL/bin:$PATH"' >> $BASH_ENV
source $BASH_ENV
- restore_cache:
key: dependency-cache-{{ checksum "bun.lockb" }}
- run:
name: Authenticate with registry
command: echo "//registry.npmjs.org/:_authToken=$ETHERSPOT_NPM_TOKEN" > ~/etherspot-modular-sdk/.npmrc
- run:
name: Install dependencies
command: bun install
- run:
name: Build Etherpot Prime SDK
command: bun run build
- run:
name: Publish package to npm
command: |
cd ~/etherspot-modular-sdk
bun publish --access public
- run:
name: Announce Publish
command: |
chmod +x .circleci/announcePublish.sh
.circleci/announcePublish.sh "Etherspot Modular SDK" "$(node -e "console.log(require('./package.json').version)")"
if [ ! -f "$MOCHAWESOME_JSON_FILE" ]; then
echo "❌ Aggregated mochawesome report not found at $MOCHAWESOME_JSON_FILE"
exit 0
fi
TOTAL_SUITES=$(jq '.stats.suites' $MOCHAWESOME_JSON_FILE)
TOTAL_PASSES=$(jq '.stats.passes' $MOCHAWESOME_JSON_FILE)
TOTAL_PENDING=$(jq '.stats.pending' $MOCHAWESOME_JSON_FILE)
TOTAL_FAILURES=$(jq '.stats.failures' $MOCHAWESOME_JSON_FILE)
START_TIME=$(jq -r '.stats.start' $MOCHAWESOME_JSON_FILE)
END_TIME=$(jq -r '.stats.end' $MOCHAWESOME_JSON_FILE)
DURATION_MS=$(jq -r '.stats.duration' $MOCHAWESOME_JSON_FILE)

publish-github-release:
docker:
- image: ardd97/ghr
steps:
- checkout
- run:
name: "Publish Release on GitHub"
command: |
PACKAGE_VERSION="$(jq .version package.json -r)"
echo $PACKAGE_VERSION
ghr -t "${GITHUB_TOKEN}" -u "${CIRCLE_PROJECT_USERNAME}" -r "${CIRCLE_PROJECT_REPONAME}" -c "${CIRCLE_SHA1}" "$PACKAGE_VERSION"
START_TIME_FORMATTED=$(date -d "$START_TIME" "+%Y-%m-%d %H:%M:%S")
END_TIME_FORMATTED=$(date -d "$END_TIME" "+%Y-%m-%d %H:%M:%S")
DURATION_MIN=$(awk "BEGIN {printf \"%.2f\",${DURATION_MS}/60000}")


jq -r '.results[] | .suites[] | select(.failures > 0) | {suite: .title, tests: [.tests[] | select(.fail) | .title]} | select(.tests | length > 0) |
"*Suite:* \(.suite)\n*Failing Tests:* \n\(.tests | map("- " + .) | join("\n"))\n"' $MOCHAWESOME_JSON_FILE > $FAILED_TESTS_FILE

if [ -s $FAILED_TESTS_FILE ]; then
MESSAGE=$(cat $FAILED_TESTS_FILE)
SLACK_MESSAGE=":x: *E2E Tests Failed :x: *\n\
*Project:* ${CIRCLE_PROJECT_REPONAME}\n\
*Triggered by:* ${CIRCLE_USERNAME}\n\
*Branch:* ${CIRCLE_BRANCH}\n\
*Commit:* <https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}|${CIRCLE_SHA1}>\n\n\
*Test Summary:*\n\
*Total Suites:* ${TOTAL_SUITES}\n\
*Passes:* ${TOTAL_PASSES}\n\
*Pending:* ${TOTAL_PENDING}\n\
*Failures:* ${TOTAL_FAILURES}\n\
*Start Time:* ${START_TIME_FORMATTED}\n\
*End Time:* ${END_TIME_FORMATTED}\n\
*Duration:* ${DURATION_MIN} minutes\n\n\
*Failed Tests:*\n${MESSAGE}\n\
*Report:* <https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/tmp/mochawesome-report/mochawesome.html|View HTML Report>\n\
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify artifact path construction matches CircleCI's artifact URL structure.

The Slack message links to /tmp/mochawesome-report/mochawesome.html within the CircleCI artifact URL, but the artifacts are stored from /home/circleci/e2e-sdk-modular/reports (line 97). Verify that the artifact path in the Slack links aligns with where the actual HTML report file is located.

Confirm the correct artifact path by checking:

  • Where the mochawesome HTML report is generated in the e2e test repository
  • Whether the artifact destination path (line 98: destination: test-report) affects the URL structure
  • The actual CircleCI artifact URL that should be used

Also applies to: 151-151


I'll verify the artifact path construction by examining the CircleCI configuration and understanding how CircleCI constructs artifact URLs.


---

🏁 Script executed:

```shell
#!/bin/bash
# Read the CircleCI config to examine artifact configuration and Slack messages
cat .circleci/config.yml

Length of output: 7974


🌐 Web query:

CircleCI artifact URL structure path construction

💡 Result:

Short answer — don’t guess the host; call the artifacts API and use the returned URL. Key facts and how the URL is formed:

  • List artifacts via the API (v1.1 or v2) and use the returned "url" field — e.g. GET /project/:vcs/:org/:repo/:build_num/artifacts (v1.1) or /project/{project-slug}/{job_number}/artifacts (v2). The API response contains the full download URLs. [1][4]

  • Artifact file URLs you’ll see are hosted on CircleCI’s artifact hosts and include a host-prefix + node index + the artifact path, e.g.:

    • https://--gh.circle-artifacts.com/0/<path/to/file>
    • or the older output host form: https://output.circle-artifacts.com/output/job//artifacts/0/<path/to/file>
      Use the exact "url" returned by the API rather than constructing hosts by hand. [1][2]
  • Path rules:

    • The artifact "path" in the API is relative to the project working directory (or to the optional store_artifacts.destination prefix). Use destination to add a prefix. [3]
    • Filenames are Java URLEncoder-encoded in the stored URL (spaces, special chars encoded). [3]
    • If you included .. in your store path, CircleCI strips .. when constructing the artifact URL. [2]

Recommended workflow:

  1. Call the artifacts API for the job/build to get the artifact objects.
  2. Use the returned "url" fields (they already include authentication/host). If you need programmatic downloads, pass your Circle-Token in the request headers. [1][4]

Sources: CircleCI API & artifacts docs and support notes. [1][2][3][4]


Fix incorrect artifact path in Slack message URLs.

The Slack message hardcodes /tmp/mochawesome-report/mochawesome.html, but CircleCI artifact URLs must include the destination prefix. Since store_artifacts (line 98) sets destination: test-report, the artifact URL should be test-report/<filename> in the CircleCI artifact URL structure. The current path /tmp/mochawesome-report/mochawesome.html will result in broken links.

Update lines 142 and 151 to use the correct path that aligns with the destination: test-report setting (e.g., test-report/aggregated-report.json or the appropriate filename from the reports directory).

🤖 Prompt for AI Agents
In .circleci/config.yml around lines 142 and 151, the Slack message links point
to /tmp/mochawesome-report/... which is incorrect because store_artifacts uses
destination: test-report; update both links to use the artifact destination
prefix (e.g., test-report/mochawesome.html and
test-report/aggregated-report.json or the actual filenames generated) so the
CircleCI artifact URLs resolve correctly; change the hardcoded /tmp/... paths to
test-report/<filename> in the Slack message templates.

*Job:* <https://circleci.com/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}|View Job>"
else
SLACK_MESSAGE=":white_check_mark: All E2E tests passed\n\
*Project:* ${CIRCLE_PROJECT_REPONAME}\n\
*Triggered by:* ${CIRCLE_USERNAME}\n\
*Branch:* ${CIRCLE_BRANCH}\n\
*Commit:* <https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}|${CIRCLE_SHA1}>\n\
*Job:* <https://circleci.com/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}|View Job>\n\
*Report:* <https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/tmp/mochawesome-report/mochawesome.html|View HTML Report>\n\
\n*Test Summary:*\n\
*Total Suites:* ${TOTAL_SUITES}\n\
*Passes:* ${TOTAL_PASSES}\n\
*Pending:* ${TOTAL_PENDING}\n\
*Failures:* ${TOTAL_FAILURES}\n\
*Start Time:* ${START_TIME_FORMATTED}\n\
*End Time:* ${END_TIME_FORMATTED}\n\
*Duration:* ${DURATION_MIN} minutes"
fi

curl -X POST -H 'Content-type: application/json' --data '{"text":"'"$SLACK_MESSAGE"'"}' $E2E_SLACK_WEBHOOK_URL
Comment on lines +100 to +162
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add defensive error handling to fail fast on script errors.

The script lacks error handling. If jq commands fail or environment variables are missing, execution continues and may produce incomplete or misleading Slack messages. Add set -e at the start of the command block to fail on errors.

           command: |
+            set -e
+            set -u  # Fail on undefined variables
             MOCHAWESOME_JSON_FILE=/home/circleci/e2e-sdk-modular/reports/aggregated-report.json
             FAILED_TESTS_FILE=failed-tests.txt
 
             if [ ! -f "$MOCHAWESOME_JSON_FILE" ]; then
               echo "❌ Aggregated mochawesome report not found at $MOCHAWESOME_JSON_FILE"
               exit 0
             fi
+            
+            # Validate jq command availability
+            if ! command -v jq &> /dev/null; then
+              echo "❌ jq is not installed"
+              exit 1
+            fi

This ensures the step fails visibly if dependencies are missing or commands fail unexpectedly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
name: Parse and send test results to Slack
when: always
command: |
MOCHAWESOME_JSON_FILE=/home/circleci/e2e-sdk-modular/reports/aggregated-report.json
FAILED_TESTS_FILE=failed-tests.txt
# same parsing + slack notification script as before...
publish-npm-package:
working_directory: ~/etherspot-modular-sdk
docker:
- image: cimg/node:20.11.1
auth:
username: $DOCKERHUB_USER
password: $DOCKERHUB_PASSWORD
steps:
- checkout
- run:
name: Install Bun
command: |
curl -fsSL https://bun.sh/install | bash
echo 'export BUN_INSTALL="$HOME/.bun"' >> $BASH_ENV
echo 'export PATH="$BUN_INSTALL/bin:$PATH"' >> $BASH_ENV
source $BASH_ENV
- restore_cache:
key: dependency-cache-{{ checksum "bun.lockb" }}
- run:
name: Authenticate with registry
command: echo "//registry.npmjs.org/:_authToken=$ETHERSPOT_NPM_TOKEN" > ~/etherspot-modular-sdk/.npmrc
- run:
name: Install dependencies
command: bun install
- run:
name: Build Etherpot Prime SDK
command: bun run build
- run:
name: Publish package to npm
command: |
cd ~/etherspot-modular-sdk
bun publish --access public
- run:
name: Announce Publish
command: |
chmod +x .circleci/announcePublish.sh
.circleci/announcePublish.sh "Etherspot Modular SDK" "$(node -e "console.log(require('./package.json').version)")"
if [ ! -f "$MOCHAWESOME_JSON_FILE" ]; then
echo "❌ Aggregated mochawesome report not found at $MOCHAWESOME_JSON_FILE"
exit 0
fi
TOTAL_SUITES=$(jq '.stats.suites' $MOCHAWESOME_JSON_FILE)
TOTAL_PASSES=$(jq '.stats.passes' $MOCHAWESOME_JSON_FILE)
TOTAL_PENDING=$(jq '.stats.pending' $MOCHAWESOME_JSON_FILE)
TOTAL_FAILURES=$(jq '.stats.failures' $MOCHAWESOME_JSON_FILE)
START_TIME=$(jq -r '.stats.start' $MOCHAWESOME_JSON_FILE)
END_TIME=$(jq -r '.stats.end' $MOCHAWESOME_JSON_FILE)
DURATION_MS=$(jq -r '.stats.duration' $MOCHAWESOME_JSON_FILE)
publish-github-release:
docker:
- image: ardd97/ghr
steps:
- checkout
- run:
name: "Publish Release on GitHub"
command: |
PACKAGE_VERSION="$(jq .version package.json -r)"
echo $PACKAGE_VERSION
ghr -t "${GITHUB_TOKEN}" -u "${CIRCLE_PROJECT_USERNAME}" -r "${CIRCLE_PROJECT_REPONAME}" -c "${CIRCLE_SHA1}" "$PACKAGE_VERSION"
START_TIME_FORMATTED=$(date -d "$START_TIME" "+%Y-%m-%d %H:%M:%S")
END_TIME_FORMATTED=$(date -d "$END_TIME" "+%Y-%m-%d %H:%M:%S")
DURATION_MIN=$(awk "BEGIN {printf \"%.2f\",${DURATION_MS}/60000}")
jq -r '.results[] | .suites[] | select(.failures > 0) | {suite: .title, tests: [.tests[] | select(.fail) | .title]} | select(.tests | length > 0) |
"*Suite:* \(.suite)\n*Failing Tests:* \n\(.tests | map("- " + .) | join("\n"))\n"' $MOCHAWESOME_JSON_FILE > $FAILED_TESTS_FILE
if [ -s $FAILED_TESTS_FILE ]; then
MESSAGE=$(cat $FAILED_TESTS_FILE)
SLACK_MESSAGE=":x: *E2E Tests Failed :x: *\n\
*Project:* ${CIRCLE_PROJECT_REPONAME}\n\
*Triggered by:* ${CIRCLE_USERNAME}\n\
*Branch:* ${CIRCLE_BRANCH}\n\
*Commit:* <https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}|${CIRCLE_SHA1}>\n\n\
*Test Summary:*\n\
*Total Suites:* ${TOTAL_SUITES}\n\
*Passes:* ${TOTAL_PASSES}\n\
*Pending:* ${TOTAL_PENDING}\n\
*Failures:* ${TOTAL_FAILURES}\n\
*Start Time:* ${START_TIME_FORMATTED}\n\
*End Time:* ${END_TIME_FORMATTED}\n\
*Duration:* ${DURATION_MIN} minutes\n\n\
*Failed Tests:*\n${MESSAGE}\n\
*Report:* <https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/tmp/mochawesome-report/mochawesome.html|View HTML Report>\n\
*Job:* <https://circleci.com/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}|View Job>"
else
SLACK_MESSAGE=":white_check_mark: All E2E tests passed\n\
*Project:* ${CIRCLE_PROJECT_REPONAME}\n\
*Triggered by:* ${CIRCLE_USERNAME}\n\
*Branch:* ${CIRCLE_BRANCH}\n\
*Commit:* <https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}|${CIRCLE_SHA1}>\n\
*Job:* <https://circleci.com/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}|View Job>\n\
*Report:* <https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/tmp/mochawesome-report/mochawesome.html|View HTML Report>\n\
\n*Test Summary:*\n\
*Total Suites:* ${TOTAL_SUITES}\n\
*Passes:* ${TOTAL_PASSES}\n\
*Pending:* ${TOTAL_PENDING}\n\
*Failures:* ${TOTAL_FAILURES}\n\
*Start Time:* ${START_TIME_FORMATTED}\n\
*End Time:* ${END_TIME_FORMATTED}\n\
*Duration:* ${DURATION_MIN} minutes"
fi
curl -X POST -H 'Content-type: application/json' --data '{"text":"'"$SLACK_MESSAGE"'"}' $E2E_SLACK_WEBHOOK_URL
name: Parse and send test results to Slack
when: always
command: |
set -e
set -u # Fail on undefined variables
MOCHAWESOME_JSON_FILE=/home/circleci/e2e-sdk-modular/reports/aggregated-report.json
FAILED_TESTS_FILE=failed-tests.txt
if [ ! -f "$MOCHAWESOME_JSON_FILE" ]; then
echo "❌ Aggregated mochawesome report not found at $MOCHAWESOME_JSON_FILE"
exit 0
fi
# Validate jq command availability
if ! command -v jq &> /dev/null; then
echo "❌ jq is not installed"
exit 1
fi
TOTAL_SUITES=$(jq '.stats.suites' $MOCHAWESOME_JSON_FILE)
TOTAL_PASSES=$(jq '.stats.passes' $MOCHAWESOME_JSON_FILE)
TOTAL_PENDING=$(jq '.stats.pending' $MOCHAWESOME_JSON_FILE)
TOTAL_FAILURES=$(jq '.stats.failures' $MOCHAWESOME_JSON_FILE)
START_TIME=$(jq -r '.stats.start' $MOCHAWESOME_JSON_FILE)
END_TIME=$(jq -r '.stats.end' $MOCHAWESOME_JSON_FILE)
DURATION_MS=$(jq -r '.stats.duration' $MOCHAWESOME_JSON_FILE)
START_TIME_FORMATTED=$(date -d "$START_TIME" "+%Y-%m-%d %H:%M:%S")
END_TIME_FORMATTED=$(date -d "$END_TIME" "+%Y-%m-%d %H:%M:%S")
DURATION_MIN=$(awk "BEGIN {printf \"%.2f\",${DURATION_MS}/60000}")
jq -r '.results[] | .suites[] | select(.failures > 0) | {suite: .title, tests: [.tests[] | select(.fail) | .title]} | select(.tests | length > 0) |
"*Suite:* \(.suite)\n*Failing Tests:* \n\(.tests | map("- " + .) | join("\n"))\n"' $MOCHAWESOME_JSON_FILE > $FAILED_TESTS_FILE
if [ -s $FAILED_TESTS_FILE ]; then
MESSAGE=$(cat $FAILED_TESTS_FILE)
SLACK_MESSAGE=":x: *E2E Tests Failed :x: *\n\
*Project:* ${CIRCLE_PROJECT_REPONAME}\n\
*Triggered by:* ${CIRCLE_USERNAME}\n\
*Branch:* ${CIRCLE_BRANCH}\n\
*Commit:* <https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}|${CIRCLE_SHA1}>\n\n\
*Test Summary:*\n\
*Total Suites:* ${TOTAL_SUITES}\n\
*Passes:* ${TOTAL_PASSES}\n\
*Pending:* ${TOTAL_PENDING}\n\
*Failures:* ${TOTAL_FAILURES}\n\
*Start Time:* ${START_TIME_FORMATTED}\n\
*End Time:* ${END_TIME_FORMATTED}\n\
*Duration:* ${DURATION_MIN} minutes\n\n\
*Failed Tests:*\n${MESSAGE}\n\
*Report:* <https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/tmp/mochawesome-report/mochawesome.html|View HTML Report>\n\
*Job:* <https://circleci.com/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}|View Job>"
else
SLACK_MESSAGE=":white_check_mark: All E2E tests passed\n\
*Project:* ${CIRCLE_PROJECT_REPONAME}\n\
*Triggered by:* ${CIRCLE_USERNAME}\n\
*Branch:* ${CIRCLE_BRANCH}\n\
*Commit:* <https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}|${CIRCLE_SHA1}>\n\
*Job:* <https://circleci.com/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}|View Job>\n\
*Report:* <https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/tmp/mochawesome-report/mochawesome.html|View HTML Report>\n\
\n*Test Summary:*\n\
*Total Suites:* ${TOTAL_SUITES}\n\
*Passes:* ${TOTAL_PASSES}\n\
*Pending:* ${TOTAL_PENDING}\n\
*Failures:* ${TOTAL_FAILURES}\n\
*Start Time:* ${START_TIME_FORMATTED}\n\
*End Time:* ${END_TIME_FORMATTED}\n\
*Duration:* ${DURATION_MIN} minutes"
fi
curl -X POST -H 'Content-type: application/json' --data '{"text":"'"$SLACK_MESSAGE"'"}' $E2E_SLACK_WEBHOOK_URL
🤖 Prompt for AI Agents
In .circleci/config.yml around lines 100 to 162 the shell command block that
parses the mochawesome report lacks defensive error handling; add a fail-fast
shell setting by enabling "set -e" (and optionally "set -o pipefail" and "set
-u") at the start of the command block so the step exits immediately on any
command failure or unset variable, preventing continuation with incomplete data
and ensuring the job fails visibly when jq or env variables are missing.



workflows:
install-and-publish:
jobs:
Expand All @@ -162,30 +170,13 @@ workflows:
filters:
branches:
only:
- master
- e2e-modular

- e2e-tests:
name: testnet-e2e-tests
context: general-vars
filters:
branches:
only:
- master

- publish-npm-package:
context: general-vars
requires:
- testnet-e2e-tests
filters:
branches:
only:
- master

- publish-github-release:
context: general-vars
requires:
- publish-npm-package
filters:
branches:
only:
- master
- e2e-modular

Loading