Skip to content

[KLC-2394] feat: operator add ms sign subcommand to sign multisi #334

[KLC-2394] feat: operator add ms sign subcommand to sign multisi

[KLC-2394] feat: operator add ms sign subcommand to sign multisi #334

Workflow file for this run

name: QA Sec
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
push:
branches: [master, main, develop]
workflow_dispatch:
jobs:
setup-and-lint:
uses: ./.github/workflows/go-setup-lint.yaml
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
with:
go-version: ${{ vars.GO_VERSION || '1.25.7' }}
golangci-lint-version: ${{ vars.GOLANGCI_VERSION || 'latest' }}
secrets:
git-user: ${{ secrets.GIT_USER }}
git-pass: ${{ secrets.GIT_PASS }}
test:
needs: setup-and-lint
runs-on: klever-pipe
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Go Setup
uses: ./.github/actions/go-setup-action
with:
go-version: ${{ vars.GO_VERSION || '1.25.7' }}
- name: Run tests
id: run-tests
continue-on-error: true
run: |
set +e # Disable immediate exit on error
if [[ "${{ github.event_name }}" != "pull_request" ]]; then
echo "Running full tests..."
go test -covermode=atomic -coverprofile=coverage.out -json ./... > test-output.json
else
echo "Running short tests..."
go test -short -covermode=atomic -coverprofile=coverage.out -json ./... > test-output.json
fi
echo "test_exit_code=$?" >> $GITHUB_OUTPUT
- name: Process test results
if: always()
id: coverage
run: |
# Generate coverage summary
if [ -f coverage.out ]; then
go tool cover -func=coverage.out > coverage-summary.txt
COVERAGE=$(grep "total:" coverage-summary.txt | awk '{print $3}')
echo "total=$COVERAGE" >> $GITHUB_OUTPUT
else
echo "No coverage data generated" > coverage-summary.txt
echo "total=0.0%" >> $GITHUB_OUTPUT
fi
# Create test summary and check for failures
echo "### Test Results 🧪" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.run-tests.outputs.test_exit_code }}" == "0" ]; then
echo "✅ All tests passed successfully" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Some tests failed" >> $GITHUB_STEP_SUMMARY
echo "::error::🔴 Test failures detected!"
if [ -f test-output.json ]; then
echo "#### Failed Tests" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
jq -r 'select(.Action=="fail") | "- \(.Package) - \(.Test)"' test-output.json | tee -a $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
# Output failures as GitHub annotations
jq -r 'select(.Action=="fail") | "::error file=\(.Package)::❌ \(.Test): \(.Action)"' test-output.json
fi
exit 1
fi
echo "Coverage: ${{ steps.coverage.outputs.total }}" >> $GITHUB_STEP_SUMMARY
- name: Upload test results
if: always()
uses: actions/upload-artifact@v5
with:
name: test-artifacts
path: |
coverage.out
test-output.json
coverage-summary.txt
retention-days: 1
overwrite: true
outputs:
coverage: ${{ steps.coverage.outputs.total }}
test_exit_code: ${{ steps.run-tests.outputs.test_exit_code }}
sonarqube:
needs: [setup-and-lint, test]
runs-on: klever-pipe
if: |
always() &&
github.event_name != 'pull_request' || github.event.pull_request.draft == false
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download lint results
uses: actions/download-artifact@v6
with:
name: lint-results
- name: Download test results
uses: actions/download-artifact@v6
with:
name: test-artifacts
- uses: twingate/github-action@v1.8
with:
service-key: ${{ secrets.TWINGATE_SERVICE_ACCOUNT }}
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@v6
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=${{ github.event.repository.name }}
-Dsonar.plugins.downloadOnlyRequired=true
-Dsonar.exclusions=**/*.json,**/*.xml,**/*_test.go,**/*.pb.go,vendor/**,coverage.out,integrationTest/**
-Dsonar.coverage.exclusions=cmd/**,**/testcommon/**,**/mock/**,**/vmhost/testInitializer*.go,**/scenarioexec/**
"-Dsonar.test.inclusions=**/*_test.go"
-Dsonar.go.coverage.reportPaths=coverage.out
-Dsonar.go.tests.reportPaths=test-output.json
-Dsonar.go.golangci-lint.reportPaths=golangci-report.xml
-Dsonar.branch.name=${{ github.ref_name }}
if: github.event_name != 'pull_request'
- name: SonarQube Go detailed scan PR
uses: sonarsource/sonarqube-scan-action@v6
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=${{ github.event.repository.name }}
-Dsonar.plugins.downloadOnlyRequired=true
-Dsonar.exclusions=**/*.json,**/*.xml,**/*_test.go,**/*.pb.go,vendor/**,coverage.out,integrationTest/**
-Dsonar.coverage.exclusions=cmd/**,**/testcommon/**,**/mock/**,**/vmhost/testInitializer*.go,**/scenarioexec/**
"-Dsonar.test.inclusions=**/*_test.go"
-Dsonar.go.coverage.reportPaths=coverage.out
-Dsonar.go.tests.reportPaths=test-output.json
-Dsonar.go.golangci-lint.reportPaths=golangci-report.xml
-Dsonar.pullrequest.branch=${{ github.head_ref }}
-Dsonar.pullrequest.base=${{ github.base_ref }}
-Dsonar.pullrequest.key=${{ github.event.number }}
if: github.event_name == 'pull_request'
- name: SonarQube Quality Gate check
continue-on-error: ${{ github.event_name != 'pull_request' }}
uses: sonarsource/sonarqube-quality-gate-action@v1.2.0
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
notify:
needs: [setup-and-lint, test, sonarqube]
runs-on: klever-pipe
if: |
always() &&
github.event_name != 'pull_request' || github.event.pull_request.draft == false
permissions:
contents: read
pull-requests: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Determine job statuses
id: job-status
run: |
echo "sonarqube_status=${{ needs.sonarqube.result == 'success' && '✅' || '❌' }}" >> $GITHUB_OUTPUT
echo "test_status=${{ needs.test.outputs.test_exit_code == '0' && '✅' || '❌' }}" >> $GITHUB_OUTPUT
if [[ "${{ needs.sonarqube.result }}" == "failure" || "${{ needs.test.outputs.test_exit_code }}" == "1" || "${{ needs.setup-and-lint.result }}" == "failure" ]]; then
echo "overall_status=Failure" >> $GITHUB_OUTPUT
echo "color=#FF0000" >> $GITHUB_OUTPUT
echo "icon=❌" >> $GITHUB_OUTPUT
else
echo "overall_status=Success" >> $GITHUB_OUTPUT
echo "color=#36a64f" >> $GITHUB_OUTPUT
echo "icon=✅" >> $GITHUB_OUTPUT
fi
- name: Get event context
id: context
env:
GH_TOKEN: ${{ github.token }}
run: |
echo "name=${{ github.event.sender.login }}" >> $GITHUB_OUTPUT
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "event_title=${{ github.event.pull_request.title }}" >> $GITHUB_OUTPUT
echo "changed_files=${{ github.event.pull_request.changed_files }}" >> $GITHUB_OUTPUT
echo "additions=${{ github.event.pull_request.additions }}" >> $GITHUB_OUTPUT
echo "deletions=${{ github.event.pull_request.deletions }}" >> $GITHUB_OUTPUT
# Get file list for PR
pr_files=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --jq '.[].filename')
echo "file_list<<EOF" >> $GITHUB_OUTPUT
echo "$pr_files" | head -n 10 >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "REPORT_URL=${{ secrets.SONAR_HOST_URL }}/dashboard?id=klever-go&pullRequest=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
echo "REVIEW_URL=${{ github.event.pull_request.html_url }}/files" >> $GITHUB_ENV
echo "REVIEW_TEXT=Review PR" >> $GITHUB_ENV
else
echo "event_title=MERGE ${{ github.event.number }}" >> $GITHUB_OUTPUT
# Use GitHub API to get commit details
commit_data=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }} --jq '{files:.files}')
changed_files=$(echo $commit_data | jq '.files | length')
echo "changed_files=$changed_files" >> $GITHUB_OUTPUT
echo "file_list<<EOF" >> $GITHUB_OUTPUT
echo $commit_data | jq -r '.files[].filename' | head -n 10 >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
additions=$(echo $commit_data | jq '[.files[].additions] | add')
deletions=$(echo $commit_data | jq '[.files[].deletions] | add')
echo "additions=$additions" >> $GITHUB_OUTPUT
echo "deletions=$deletions" >> $GITHUB_OUTPUT
echo "REPORT_URL=${{ secrets.SONAR_HOST_URL }}/dashboard?id=klever-go&branch=${{ github.ref_name }}" >> $GITHUB_ENV
echo "REVIEW_URL=${{ github.event.repository.html_url }}/commits/${{ github.ref_name }}" >> $GITHUB_ENV
echo "REVIEW_TEXT=View Commits" >> $GITHUB_ENV
fi
- name: Slack Notification
run: |
curl -X POST -H 'Content-type: application/json' --data '
{
"text": "🚀 CI/CD Pipeline ${{ steps.job-status.outputs.icon }} Update for ${{ github.repository }}",
"attachments": [
{
"color": "${{ steps.job-status.outputs.color }}",
"blocks": [
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Status:*\n${{ steps.job-status.outputs.overall_status }}"
},
{
"type": "mrkdwn",
"text": "*Branch:*\n${{ github.ref_name || github.ref }}"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Event:*\n${{ github.event_name }}"
},
{
"type": "mrkdwn",
"text": "*Author:*\n${{ github.event.sender.login }}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${{ github.event_name == 'pull_request' && 'PR Title' || 'Commit Message' }}:*\n${{ steps.context.outputs.event_title }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Changes:*\n• Files changed: ${{ steps.context.outputs.changed_files }} (+${{ steps.context.outputs.additions }}/-${{ steps.context.outputs.deletions }})\n• First 10 changed files:\n```${{ steps.context.outputs.file_list }}```"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Job Results:*\n• SonarQube: ${{ steps.job-status.outputs.sonarqube_status }}\n• Tests: ${{ steps.job-status.outputs.test_status }}\n• Project Coverage: ${{ needs.test.outputs.coverage }}\n"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Actions Run"
},
"url": "${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }}"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View SonarQube Report"
},
"url": "${{ env.REPORT_URL }}"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "${{ env.REVIEW_TEXT }}"
},
"url": "${{ env.REVIEW_URL }}",
"style": "primary"
}
]
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Need help? <${{ github.event.repository.html_url }}/issues/new|Create an issue>"
}
]
}
]
}
]
}' ${{ secrets.SLACK_WEBHOOK_URL }}
env:
# build Sonar URL based on the event type
SONAR_URL: ${{ secrets.SONAR_HOST_URL }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
REPORT_URL: ${{ env.REPORT_URL }}
REVIEW_URL: ${{ env.REVIEW_URL }}
REVIEW_TEXT: ${{ env.REVIEW_TEXT }}
result-check:
needs: [sonarqube, test]
runs-on: klever-pipe
steps:
- name: Check for failed jobs
run: |
if [[ "${{ needs.sonarqube.result }}" == "failure" || "${{ needs.test.outputs.test_exit_code }}" == "1" ]]; then
echo "One or more jobs failed. Exiting with status 1."
exit 1
fi