name: QA
on:
push:
branches:
- main
release:
types: [published]
pull_request:
types:
[
opened,
synchronize,
reopened,
ready_for_review,
converted_to_draft,
closed,
]
pull_request_review:
types: [submitted, dismissed]
permissions:
contents: read
pull-requests: write
packages: write
concurrency:
group:
${{ github.workflow }}-${{ github.event.pull_request.number || github.ref
}}-${{ github.event_name }}-${{ github.event.action || 'default' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
qa:
name: QA
if: |
github.event_name == 'push' ||
(github.event_name == 'pull_request' && github.event.action != 'closed') ||
github.event_name == 'pull_request_review' ||
github.event_name == 'release'
runs-on: namespace-profile-sdk
timeout-minutes: 30
permissions:
contents: read
pull-requests: write
issues: write
security-events: write
actions: read
packages: write
env:
SLACK_BOT_TOKEN: ""
SLACK_CHANNEL_ID: ""
HARBOR_USER: ""
HARBOR_PASS: ""
PAT_TOKEN: ""
NPM_TOKEN: ""
TAG: ""
VERSION: ""
CONSOLE_GRAPHQL: ""
steps:
- name: Checkout repository
uses: namespacelabs/nscloud-checkout-action@0c5e6ce59a41299aba2ad91baa0126f1bfde8e5c # v8
with:
fetch-depth: ${{ github.event_name == 'push' && 2 || 0 }}
persist-credentials: false
- name: Setup 1Password
uses: 1password/load-secrets-action/configure@13f58eec611f8e5db52ec16247f58c508398f3e6 # v3
with:
service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
- name: Load all secrets
id: secrets
uses: 1password/load-secrets-action@13f58eec611f8e5db52ec16247f58c508398f3e6 # v3
with:
export-env: true
env:
SLACK_BOT_TOKEN: op://platform/slack-bot/SLACK_BOT_TOKEN
SLACK_CHANNEL_ID: op://platform/slack-bot/SLACK_CHANNEL_ID
HARBOR_USER: op://platform/harbor/username
HARBOR_PASS: op://platform/harbor/password
PAT_TOKEN: op://platform/github-commit-pat/credential
NPM_TOKEN: op://platform/npmjs/credential
# Label QA as running and notify Slack (only for non-draft PRs)
- name: Label QA as running
if: |
github.event_name == 'pull_request' &&
github.event.pull_request.draft == false
uses: settlemint/shared-actions/.github/actions/build-status-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
workflow_status: "running"
# Initial Slack notification - creates or updates message
- name: Send Slack notification for QA starting
if: |
github.event_name == 'pull_request' &&
github.event.pull_request.draft == false
uses: settlemint/shared-actions/.github/actions/slack-pr-notifier@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_title: ${{ github.event.pull_request.title }}
pr_url: ${{ github.event.pull_request.html_url }}
pr_author: ${{ github.event.pull_request.user.login }}
pr_author_type: ${{ github.event.pull_request.user.type }}
pr_author_avatar: ${{ github.event.pull_request.user.avatar_url }}
slack_bot_token: ${{ env.SLACK_BOT_TOKEN }}
slack_channel_id: ${{ env.SLACK_CHANNEL_ID }}
# Setup dependencies for QA (skip for draft PRs)
- name: Setup dependencies
if: |
github.event_name == 'push' ||
github.event_name == 'pull_request' ||
github.event_name == 'pull_request_review' ||
github.event_name == 'release'
uses: settlemint/shared-actions/.github/actions/setup-dependencies@main
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
npm_token: ${{ env.NPM_TOKEN }}
disable_node: "true"
- name: Inject slug/short variables
uses: rlespinasse/github-slug-action@6f7a8d2348e2a4aa5defafcdaafe5aef3f83bd4b # v5
- name: Update package versions
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'release'
id: package-version
run: |
OLD_VERSION=$(jq -r '.version' package.json)
echo "Old version: $OLD_VERSION"
if [[ $GITHUB_REF_SLUG =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
VERSION=$(echo $GITHUB_REF_SLUG | sed 's/^v//')
echo "TAG=latest" >> $GITHUB_ENV
echo "CONSOLE_GRAPHQL=https://console.settlemint.com/api/graphql" >> $GITHUB_ENV
elif [[ $GITHUB_REF_NAME == "main" ]]; then
VERSION="${OLD_VERSION}-main$(echo $GITHUB_SHA_SHORT | sed 's/^v//')"
echo "TAG=main" >> $GITHUB_ENV
echo "CONSOLE_GRAPHQL=https://console-release.settlemint.com/api/graphql" >> $GITHUB_ENV
else
VERSION="${OLD_VERSION}-pr$(echo $GITHUB_SHA_SHORT | sed 's/^v//')"
echo "TAG=pr" >> $GITHUB_ENV
echo "CONSOLE_GRAPHQL=https://console-release.settlemint.com/api/graphql" >> $GITHUB_ENV
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "Updating version to $VERSION"
jq --arg version "$VERSION" '.version = $version' package.json > package.json.tmp && mv package.json.tmp package.json
update_package_json() {
local dir="$1"
local version="$2"
echo "Updating $dir/package.json version to $version and updating workspace dependencies"
jq --arg version "$version" '
.version = $version |
(.dependencies) |= with_entries(if .value == "workspace:*" then .value = $version else . end) |
(.devDependencies) |= with_entries(if .value == "workspace:*" then .value = $version else . end) |
(.peerDependencies) |= with_entries(if .value == "workspace:*" then .value = $version else . end)
' "$dir/package.json" > "$dir/package.json.tmp" && mv "$dir/package.json.tmp" "$dir/package.json" || {
echo "Error updating $dir/package.json"
cat "$dir/package.json.tmp"
exit 1
}
}
if [ -z "$VERSION" ]; then
echo "Error: VERSION is not set"
exit 1
fi
for dir in ./sdk/*; do
if [ -f "$dir/package.json" ]; then
update_package_json "$dir" "$VERSION"
fi
done
for dir in ./apps/*; do
if [ -f "$dir/package.json" ]; then
update_package_json "$dir" "$VERSION"
fi
done
echo "Updated version to $VERSION"
- name: Login to npm
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'release'
run: |
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc
echo "//registry.npmjs.org/:_authToken=${{ env.NPM_TOKEN }}" >> ~/.npmrc
- name: Setup git user
run: |
git config --global user.name "$(git --no-pager log --format=format:'%an' -n 1)"
git config --global user.email "$(git --no-pager log --format=format:'%ae' -n 1)"
git remote set-url origin https://$PAT_TOKEN@github.com/settlemint/sdk.git
env:
PAT_TOKEN: ${{ env.PAT_TOKEN }}
- name: Update docs and README
if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_review' }}
run: bun docs
- name: Auto-commit changes to docs and README
if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_review' && github.ref == 'refs/heads/main' && env.TAG == 'main' }}
uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # v7
with:
commit_message: "chore: update docs [skip ci]"
branch: main
file_pattern: 'sdk/cli/docs/settlemint.md sdk/cli/docs/**/*.md sdk/**/README.md README.md'
- name: Run tests and checks
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'release'
id: qa-tests
run: bunx turbo lint typecheck build attw publint test:coverage publish-npm --env-mode=loose
- name: Check typings of E2E tests
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'release'
run: bun test:typecheck
- name: Create or update PR comment
if: ${{ github.event_name == 'pull_request' }}
uses: taoliujun/action-unique-comment@95aa81645432e8f3f10cca47ae832a25f31a9d92 # v1
with:
uniqueIdentifier: ${{ github.workflow }}
body: |
# 📦 Packages
| Package | NPM | Docker |
| ------- | -------------------- | -------------------- |
| SDK Cli | `@settlemint/sdk-cli@${{ env.VERSION }}` | |
| SDK The Graph | `@settlemint/sdk-thegraph@${{ env.VERSION }}` | |
| SDK Portal | `@settlemint/sdk-portal@${{ env.VERSION }}` | |
| SDK Hasura | `@settlemint/sdk-hasura@${{ env.VERSION }}` | |
| SDK JS | `@settlemint/sdk-js@${{ env.VERSION }}` | |
| SDK Utils | `@settlemint/sdk-utils@${{ env.VERSION }}` | |
| SDK Next | `@settlemint/sdk-next@${{ env.VERSION }}` | |
| SDK Minio | `@settlemint/sdk-minio@${{ env.VERSION }}` | |
| SDK IPFS | `@settlemint/sdk-ipfs@${{ env.VERSION }}` | |
| SDK Blockscout | `@settlemint/sdk-blockscout@${{ env.VERSION }}` | |
| SDK MCP | `@settlemint/sdk-mcp@${{ env.VERSION }}` | |
| SDK Viem | `@settlemint/sdk-viem@${{ env.VERSION }}` | |
| SDK EAS | `@settlemint/sdk-eas@${{ env.VERSION }}` | |
- name: Auto-commit updated package versions
uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # v7
if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_review' && env.TAG == 'latest' }}
with:
commit_message: "chore: update package versions [skip ci]"
branch: main
file_pattern: 'package.json **/schema.graphql sdk/cli/docs/settlemint.md sdk/cli/docs/**/*.md sdk/**/README.md'
# Label QA results (PR only)
- name: Label QA build status
if: |
always() &&
github.event_name == 'pull_request' &&
steps.qa-tests.conclusion != 'skipped'
uses: settlemint/shared-actions/.github/actions/build-status-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
workflow_status:
${{ steps.qa-tests.outcome == 'success' && 'success' || 'failure' }}
# Skip redundant notification - handled by consolidated step at the end
# Label PR based on title/branch (PR only)
- name: Label PR based on convention
id: label-pr
if: |
github.event_name == 'pull_request' &&
(github.event.action == 'opened' || github.event.action == 'synchronize')
uses: settlemint/shared-actions/.github/actions/pr-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_title: ${{ github.event.pull_request.title }}
pr_body: ${{ github.event.pull_request.body || '' }}
# Skip redundant notification - handled by consolidated step at the end
# Run secret scanning (PR only)
- name: Run secret scanning
id: secret-scan
if: github.event_name == 'pull_request'
uses: settlemint/shared-actions/.github/actions/secret-scanner@main
continue-on-error: true
# Label secret scanning results (PR only)
- name: Label secret scanning status
if: |
always() &&
github.event_name == 'pull_request' &&
steps.secret-scan.conclusion != 'skipped'
uses: settlemint/shared-actions/.github/actions/build-status-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
workflow_status:
${{ steps.secret-scan.outcome == 'success' && 'success' || 'failure'
}}
# Skip redundant notification - handled by consolidated step at the end
# Check PR review status (PR and PR review events only)
- name: Check PR review status
id: pr-review-check
if: |
always() &&
(github.event_name == 'pull_request' || github.event_name == 'pull_request_review')
uses: settlemint/shared-actions/.github/actions/pr-review-check@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_author: ${{ github.event.pull_request.user.login }}
event_name: ${{ github.event_name }}
qa_result: ${{ steps.qa-tests.outcome }}
secret_scanning_result: ${{ steps.secret-scan.outcome }}
# Apply final PR status label (PR and PR review events only)
- name: Label PR final status
id: label-final-status
if: |
always() &&
(github.event_name == 'pull_request' || github.event_name == 'pull_request_review')
uses: settlemint/shared-actions/.github/actions/pr-status-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
is_draft: ${{ github.event.pull_request.draft }}
has_approval:
${{ steps.pr-review-check.outputs.has_approval == 'true' }}
qa_status: ${{ steps.pr-review-check.outputs.qa_status }}
# Consolidated Slack notification - updates existing message or creates one if needed
- name: Update Slack notification with final status
if: |
always() &&
steps.label-final-status.conclusion == 'success' &&
(github.event_name == 'pull_request' || github.event_name == 'pull_request_review') &&
github.event.pull_request.draft == false
uses: settlemint/shared-actions/.github/actions/slack-pr-notifier@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_title: ${{ github.event.pull_request.title }}
pr_url: ${{ github.event.pull_request.html_url }}
pr_author: ${{ github.event.pull_request.user.login }}
pr_author_type: ${{ github.event.pull_request.user.type }}
pr_author_avatar: ${{ github.event.pull_request.user.avatar_url }}
slack_bot_token: ${{ env.SLACK_BOT_TOKEN }}
slack_channel_id: ${{ env.SLACK_CHANNEL_ID }}
# Manage auto-merge (PR and PR review events only)
- name: Manage auto-merge
if: |
always() &&
(github.event_name == 'pull_request' || github.event_name == 'pull_request_review')
uses: settlemint/shared-actions/.github/actions/auto-merge@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_author: ${{ github.event.pull_request.user.login }}
pr_author_type: ${{ github.event.pull_request.user.type }}
has_approval:
${{ steps.pr-review-check.outputs.has_approval == 'true' }}
qa_status: ${{ steps.pr-review-check.outputs.qa_status }}
is_draft: ${{ github.event.pull_request.draft }}
merge_method: "squash"
# Handle merged PR notifications
merged:
name: Handle Merged PR
if: |
github.event_name == 'pull_request' &&
github.event.action == 'closed' &&
github.event.pull_request.merged == true
runs-on: namespace-profile-btp-scs-portal
permissions:
contents: read
pull-requests: write
issues: write
env:
SLACK_BOT_TOKEN: ""
SLACK_CHANNEL_ID: ""
steps:
- name: Checkout repository
uses: namespacelabs/nscloud-checkout-action@0c5e6ce59a41299aba2ad91baa0126f1bfde8e5c # v8
with:
fetch-depth: ${{ github.event_name == 'push' && 2 || 0 }}
- name: Setup 1Password
uses: 1password/load-secrets-action/configure@13f58eec611f8e5db52ec16247f58c508398f3e6 # v3
with:
service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
- name: Load Slack secrets
uses: 1password/load-secrets-action@13f58eec611f8e5db52ec16247f58c508398f3e6 # v3
with:
export-env: true
env:
SLACK_BOT_TOKEN: op://platform/slack-bot/SLACK_BOT_TOKEN
SLACK_CHANNEL_ID: op://platform/slack-bot/SLACK_CHANNEL_ID
- name: Label PR as merged
uses: settlemint/shared-actions/.github/actions/pr-status-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
is_draft: false
is_merged: true
- name: Update Slack notification for merged PR
uses: settlemint/shared-actions/.github/actions/slack-pr-notifier@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_title: ${{ github.event.pull_request.title }}
pr_url: ${{ github.event.pull_request.html_url }}
pr_author: ${{ github.event.pull_request.user.login }}
pr_author_type: ${{ github.event.pull_request.user.type }}
pr_author_avatar: ${{ github.event.pull_request.user.avatar_url }}
slack_bot_token: ${{ env.SLACK_BOT_TOKEN }}
slack_channel_id: ${{ env.SLACK_CHANNEL_ID }}
wait_time: "15000"
# Handle abandoned (closed but not merged) PR notifications
abandoned:
name: Handle Abandoned PR
if: |
github.event_name == 'pull_request' &&
github.event.action == 'closed' &&
github.event.pull_request.merged == false
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
env:
SLACK_BOT_TOKEN: ""
SLACK_CHANNEL_ID: ""
steps:
- name: Checkout repository
uses: namespacelabs/nscloud-checkout-action@0c5e6ce59a41299aba2ad91baa0126f1bfde8e5c # v8
with:
fetch-depth: ${{ github.event_name == 'push' && 2 || 0 }}
- name: Setup 1Password
uses: 1password/load-secrets-action/configure@13f58eec611f8e5db52ec16247f58c508398f3e6 # v3
with:
service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
- name: Load Slack secrets
uses: 1password/load-secrets-action@13f58eec611f8e5db52ec16247f58c508398f3e6 # v3
with:
export-env: true
env:
SLACK_BOT_TOKEN: op://platform/slack-bot/SLACK_BOT_TOKEN
SLACK_CHANNEL_ID: op://platform/slack-bot/SLACK_CHANNEL_ID
- name: Label PR as abandoned
uses: settlemint/shared-actions/.github/actions/pr-status-labeler@main
with:
pr_number: ${{ github.event.pull_request.number }}
is_draft: false
is_abandoned: true
- name: Update Slack notification for abandoned PR
uses: settlemint/shared-actions/.github/actions/slack-pr-notifier@main
with:
pr_number: ${{ github.event.pull_request.number }}
pr_title: ${{ github.event.pull_request.title }}
pr_url: ${{ github.event.pull_request.html_url }}
pr_author: ${{ github.event.pull_request.user.login }}
pr_author_type: ${{ github.event.pull_request.user.type }}
pr_author_avatar: ${{ github.event.pull_request.user.avatar_url }}
slack_bot_token: ${{ env.SLACK_BOT_TOKEN }}
slack_channel_id: ${{ env.SLACK_CHANNEL_ID }}
is_abandoned: true
wait_time: "15000"