mcp-dbutils 0.12.0__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_dbutils-0.14.0/.github/workflows/quality-assurance.yml +266 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/CHANGELOG.md +14 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/PKG-INFO +33 -1
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/README.md +32 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/pyproject.toml +1 -1
- mcp_dbutils-0.14.0/sonar-project.properties +14 -0
- mcp_dbutils-0.12.0/.github/workflows/quality-assurance.yml +0 -102
- mcp_dbutils-0.12.0/sonar-project.properties +0 -6
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/.coveragerc +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/.github/workflows/release.yml +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/.gitignore +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/.releaserc.json +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/Dockerfile +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/LICENSE +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/README_CN.md +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/config.yaml.example +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/smithery.yaml +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/__init__.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/base.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/log.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/mysql/__init__.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/mysql/config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/mysql/handler.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/mysql/server.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/postgres/__init__.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/postgres/config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/postgres/handler.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/postgres/server.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/sqlite/__init__.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/sqlite/config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/sqlite/handler.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/sqlite/server.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/src/mcp_dbutils/stats.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/conftest.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/__init__.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/conftest.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/fixtures.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_logging.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_monitoring.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_monitoring_enhanced.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_mysql.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_mysql_config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_postgres.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_postgres_config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_prompts.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_sqlite.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_sqlite_config.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_tools.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/integration/test_tools_advanced.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/unit/test_log.py +0 -0
- {mcp_dbutils-0.12.0 → mcp_dbutils-0.14.0}/tests/unit/test_stats.py +0 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
name: Quality Assurance
|
2
|
+
|
3
|
+
# 添加明确的权限声明
|
4
|
+
permissions:
|
5
|
+
contents: read
|
6
|
+
pull-requests: write # 允许创建PR评论
|
7
|
+
issues: write # 允许创建issue评论
|
8
|
+
checks: write # 允许更新检查状态
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ main ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ main ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
pytest:
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
|
20
|
+
services:
|
21
|
+
postgres:
|
22
|
+
image: postgres:15-alpine
|
23
|
+
env:
|
24
|
+
POSTGRES_PASSWORD: postgres
|
25
|
+
ports:
|
26
|
+
- 5432:5432
|
27
|
+
options: >-
|
28
|
+
--health-cmd pg_isready
|
29
|
+
--health-interval 10s
|
30
|
+
--health-timeout 5s
|
31
|
+
--health-retries 5
|
32
|
+
|
33
|
+
steps:
|
34
|
+
- uses: actions/checkout@v4
|
35
|
+
|
36
|
+
- name: Install uv
|
37
|
+
uses: astral-sh/setup-uv@v4
|
38
|
+
|
39
|
+
- name: Set up Python
|
40
|
+
run: uv python install
|
41
|
+
|
42
|
+
- name: Create and activate venv
|
43
|
+
run: |
|
44
|
+
uv venv
|
45
|
+
. .venv/bin/activate
|
46
|
+
|
47
|
+
- name: Install dependencies
|
48
|
+
run: uv pip install -e ".[test]"
|
49
|
+
|
50
|
+
- name: Run tests with coverage
|
51
|
+
id: tests
|
52
|
+
run: |
|
53
|
+
uv run pytest \
|
54
|
+
-v \
|
55
|
+
--cov=src/mcp_dbutils \
|
56
|
+
--cov-report=html \
|
57
|
+
--cov-report=term-missing \
|
58
|
+
--cov-report=json:coverage.json \
|
59
|
+
--cov-report=xml:coverage.xml \
|
60
|
+
tests/
|
61
|
+
|
62
|
+
- name: Upload coverage report
|
63
|
+
uses: actions/upload-artifact@v4
|
64
|
+
with:
|
65
|
+
name: coverage-report
|
66
|
+
path: coverage.xml
|
67
|
+
|
68
|
+
- name: Calculate coverage percentage
|
69
|
+
id: calc_coverage
|
70
|
+
run: |
|
71
|
+
COVERAGE=$(jq -r '.totals.percent_covered' coverage.json)
|
72
|
+
echo "Coverage: $COVERAGE"
|
73
|
+
echo "percentage=${COVERAGE%.*}" >> $GITHUB_OUTPUT
|
74
|
+
if (( $(echo "$COVERAGE >= 90" | bc -l) )); then
|
75
|
+
echo "color=green" >> $GITHUB_OUTPUT
|
76
|
+
elif (( $(echo "$COVERAGE >= 80" | bc -l) )); then
|
77
|
+
echo "color=yellow" >> $GITHUB_OUTPUT
|
78
|
+
else
|
79
|
+
echo "color=red" >> $GITHUB_OUTPUT
|
80
|
+
fi
|
81
|
+
|
82
|
+
- name: Create Coverage Badge
|
83
|
+
uses: schneegans/dynamic-badges-action@v1.7.0
|
84
|
+
with:
|
85
|
+
auth: ${{ secrets.GIST_SECRET }}
|
86
|
+
gistID: bdd0a63ec2a816539ff8c136ceb41e48
|
87
|
+
filename: coverage.json
|
88
|
+
label: "coverage"
|
89
|
+
message: "${{ steps.calc_coverage.outputs.percentage }}%"
|
90
|
+
color: "${{ steps.calc_coverage.outputs.color }}"
|
91
|
+
namedLogo: python
|
92
|
+
|
93
|
+
sonarcloud:
|
94
|
+
name: SonarCloud
|
95
|
+
needs: pytest
|
96
|
+
runs-on: ubuntu-latest
|
97
|
+
steps:
|
98
|
+
- uses: actions/checkout@v4
|
99
|
+
with:
|
100
|
+
fetch-depth: 0
|
101
|
+
- name: Download coverage report
|
102
|
+
uses: actions/download-artifact@v4
|
103
|
+
with:
|
104
|
+
name: coverage-report
|
105
|
+
- name: SonarCloud Scan
|
106
|
+
uses: SonarSource/sonarqube-scan-action@v5.0.0
|
107
|
+
env:
|
108
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
109
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
110
|
+
|
111
|
+
- name: SonarQube Quality Gate Check
|
112
|
+
uses: sonarsource/sonarqube-quality-gate-action@master
|
113
|
+
timeout-minutes: 5
|
114
|
+
env:
|
115
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
116
|
+
with:
|
117
|
+
scanMetadataReportFile: .scannerwork/report-task.txt
|
118
|
+
|
119
|
+
- name: SonarCloud PR Comment
|
120
|
+
if: github.event_name == 'pull_request'
|
121
|
+
uses: actions/github-script@v6
|
122
|
+
env:
|
123
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
124
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
125
|
+
SONAR_PROJECT_KEY: 'donghao1393_mcp-dbutils'
|
126
|
+
with:
|
127
|
+
script: |
|
128
|
+
const fs = require('fs');
|
129
|
+
|
130
|
+
// 读取质量门禁结果
|
131
|
+
let qualityGateStatus = 'Unknown';
|
132
|
+
try {
|
133
|
+
const reportTaskContent = fs.readFileSync('.scannerwork/report-task.txt', 'utf8');
|
134
|
+
const ceTaskIdMatch = reportTaskContent.match(/ceTaskId=(.+)/);
|
135
|
+
if (ceTaskIdMatch && ceTaskIdMatch[1]) {
|
136
|
+
const ceTaskId = ceTaskIdMatch[1];
|
137
|
+
|
138
|
+
// 等待分析完成
|
139
|
+
let analysisComplete = false;
|
140
|
+
let retries = 0;
|
141
|
+
while (!analysisComplete && retries < 10) {
|
142
|
+
const ceTaskResponse = await fetch(
|
143
|
+
`https://sonarcloud.io/api/ce/task?id=${ceTaskId}`,
|
144
|
+
{ headers: { Authorization: `Bearer ${process.env.SONAR_TOKEN}` } }
|
145
|
+
).then(res => res.json());
|
146
|
+
|
147
|
+
if (ceTaskResponse.task && ceTaskResponse.task.status === 'SUCCESS') {
|
148
|
+
analysisComplete = true;
|
149
|
+
} else {
|
150
|
+
retries++;
|
151
|
+
await new Promise(resolve => setTimeout(resolve, 5000)); // 等待5秒
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
} catch (error) {
|
156
|
+
console.error('Error reading report task file:', error);
|
157
|
+
}
|
158
|
+
|
159
|
+
// 获取SonarCloud分析结果
|
160
|
+
const projectKey = process.env.SONAR_PROJECT_KEY;
|
161
|
+
const sonarResponse = await fetch(
|
162
|
+
`https://sonarcloud.io/api/measures/component?component=${projectKey}&metricKeys=bugs,vulnerabilities,code_smells,coverage,duplicated_lines_density`,
|
163
|
+
{ headers: { Authorization: `Bearer ${process.env.SONAR_TOKEN}` } }
|
164
|
+
).then(res => res.json());
|
165
|
+
|
166
|
+
// 解析结果
|
167
|
+
let coverage = 'N/A';
|
168
|
+
let bugs = 'N/A';
|
169
|
+
let vulnerabilities = 'N/A';
|
170
|
+
let codeSmells = 'N/A';
|
171
|
+
let duplication = 'N/A';
|
172
|
+
|
173
|
+
if (sonarResponse && sonarResponse.component && sonarResponse.component.measures) {
|
174
|
+
const measures = sonarResponse.component.measures;
|
175
|
+
|
176
|
+
for (const measure of measures) {
|
177
|
+
switch (measure.metric) {
|
178
|
+
case 'coverage':
|
179
|
+
coverage = `${parseFloat(measure.value).toFixed(2)}%`;
|
180
|
+
break;
|
181
|
+
case 'bugs':
|
182
|
+
bugs = measure.value;
|
183
|
+
break;
|
184
|
+
case 'vulnerabilities':
|
185
|
+
vulnerabilities = measure.value;
|
186
|
+
break;
|
187
|
+
case 'code_smells':
|
188
|
+
codeSmells = measure.value;
|
189
|
+
break;
|
190
|
+
case 'duplicated_lines_density':
|
191
|
+
duplication = `${parseFloat(measure.value).toFixed(2)}%`;
|
192
|
+
break;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
// 获取质量门禁状态
|
198
|
+
const qualityGateResponse = await fetch(
|
199
|
+
`https://sonarcloud.io/api/qualitygates/project_status?projectKey=${projectKey}`,
|
200
|
+
{ headers: { Authorization: `Bearer ${process.env.SONAR_TOKEN}` } }
|
201
|
+
).then(res => res.json());
|
202
|
+
|
203
|
+
if (qualityGateResponse && qualityGateResponse.projectStatus) {
|
204
|
+
qualityGateStatus = qualityGateResponse.projectStatus.status === 'OK' ? '✅ Passed' : '❌ Failed';
|
205
|
+
}
|
206
|
+
|
207
|
+
// 计算总问题数
|
208
|
+
const totalIssues = parseInt(bugs || 0) + parseInt(vulnerabilities || 0) + parseInt(codeSmells || 0);
|
209
|
+
|
210
|
+
// 生成评论内容
|
211
|
+
let recommendations = [];
|
212
|
+
if (parseInt(bugs) > 0) recommendations.push('- Fix identified bugs to improve code reliability');
|
213
|
+
if (parseInt(vulnerabilities) > 0) recommendations.push('- Address security vulnerabilities to enhance application security');
|
214
|
+
if (parseInt(codeSmells) > 5) recommendations.push('- Refactor code to reduce code smells and improve maintainability');
|
215
|
+
if (parseFloat(coverage) < 80) recommendations.push('- Increase test coverage to meet the 80% minimum requirement');
|
216
|
+
if (parseFloat(duplication) > 3) recommendations.push('- Reduce code duplication to improve maintainability');
|
217
|
+
|
218
|
+
const comment = [
|
219
|
+
'## SonarCloud Analysis Results',
|
220
|
+
'',
|
221
|
+
'### Summary',
|
222
|
+
`- **Quality Gate**: ${qualityGateStatus}`,
|
223
|
+
`- **Coverage**: ${coverage}`,
|
224
|
+
`- **Total Issues**: ${totalIssues}`,
|
225
|
+
`- **Code Duplication**: ${duplication}`,
|
226
|
+
'',
|
227
|
+
'### Details',
|
228
|
+
`- **Code Smells**: ${codeSmells}`,
|
229
|
+
`- **Bugs**: ${bugs}`,
|
230
|
+
`- **Security Vulnerabilities**: ${vulnerabilities}`,
|
231
|
+
'',
|
232
|
+
'### Recommendations',
|
233
|
+
...recommendations,
|
234
|
+
'',
|
235
|
+
`[View full report on SonarCloud](https://sonarcloud.io/dashboard?id=${projectKey})`
|
236
|
+
].join('\n');
|
237
|
+
|
238
|
+
// 发布或更新PR评论
|
239
|
+
const { data: comments } = await github.rest.issues.listComments({
|
240
|
+
owner: context.repo.owner,
|
241
|
+
repo: context.repo.repo,
|
242
|
+
issue_number: context.issue.number,
|
243
|
+
});
|
244
|
+
|
245
|
+
const botComment = comments.find(comment =>
|
246
|
+
comment.user.login === 'github-actions[bot]' &&
|
247
|
+
comment.body.includes('SonarCloud Analysis Results')
|
248
|
+
);
|
249
|
+
|
250
|
+
if (botComment) {
|
251
|
+
await github.rest.issues.updateComment({
|
252
|
+
owner: context.repo.owner,
|
253
|
+
repo: context.repo.repo,
|
254
|
+
comment_id: botComment.id,
|
255
|
+
body: comment,
|
256
|
+
});
|
257
|
+
console.log('Updated existing SonarCloud comment');
|
258
|
+
} else {
|
259
|
+
await github.rest.issues.createComment({
|
260
|
+
owner: context.repo.owner,
|
261
|
+
repo: context.repo.repo,
|
262
|
+
issue_number: context.issue.number,
|
263
|
+
body: comment,
|
264
|
+
});
|
265
|
+
console.log('Created new SonarCloud comment');
|
266
|
+
}
|
@@ -1,3 +1,17 @@
|
|
1
|
+
# [0.14.0](https://github.com/donghao1393/mcp-dbutils/compare/v0.13.0...v0.14.0) (2025-03-14)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* implement SonarCloud PR auto-comment system ([#33](https://github.com/donghao1393/mcp-dbutils/issues/33)) ([4e83211](https://github.com/donghao1393/mcp-dbutils/commit/4e83211c4c7a289a6b794cdc5e03caac301d173c)), closes [#32](https://github.com/donghao1393/mcp-dbutils/issues/32)
|
7
|
+
|
8
|
+
# [0.13.0](https://github.com/donghao1393/mcp-dbutils/compare/v0.12.0...v0.13.0) (2025-03-14)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* configure SonarCloud quality gates ([#31](https://github.com/donghao1393/mcp-dbutils/issues/31)) ([454c4d3](https://github.com/donghao1393/mcp-dbutils/commit/454c4d384e4ddd8d324fe4292b13436c6b22328c)), closes [#30](https://github.com/donghao1393/mcp-dbutils/issues/30)
|
14
|
+
|
1
15
|
# [0.12.0](https://github.com/donghao1393/mcp-dbutils/compare/v0.11.0...v0.12.0) (2025-03-14)
|
2
16
|
|
3
17
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-dbutils
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.14.0
|
4
4
|
Summary: MCP Database Utilities Service
|
5
5
|
Author: Dong Hao
|
6
6
|
License-Expression: MIT
|
@@ -460,6 +460,38 @@ Provides MySQL-specific features:
|
|
460
460
|
- SSL/TLS secure connection
|
461
461
|
- URL and standard connection methods
|
462
462
|
|
463
|
+
## Code Quality
|
464
|
+
|
465
|
+
### Quality Gates
|
466
|
+
We use SonarCloud to maintain high code quality standards. All pull requests must pass the following quality gates:
|
467
|
+
|
468
|
+
- Code Coverage: ≥ 80%
|
469
|
+
- Code Quality:
|
470
|
+
* No blocker or critical issues
|
471
|
+
* Less than 10 major issues
|
472
|
+
* Code duplication < 3%
|
473
|
+
- Security:
|
474
|
+
* No security vulnerabilities
|
475
|
+
* No security hotspots
|
476
|
+
|
477
|
+
### Automated Checks
|
478
|
+
Our CI/CD pipeline automatically performs:
|
479
|
+
1. Full test suite execution
|
480
|
+
2. Code coverage analysis
|
481
|
+
3. SonarCloud static code analysis
|
482
|
+
4. Quality gate validation
|
483
|
+
|
484
|
+
Pull requests that don't meet these standards will be automatically blocked from merging.
|
485
|
+
|
486
|
+
### Local Development
|
487
|
+
To check code quality locally:
|
488
|
+
1. Run tests with coverage:
|
489
|
+
```bash
|
490
|
+
pytest --cov=src/mcp_dbutils --cov-report=xml:coverage.xml tests/
|
491
|
+
```
|
492
|
+
2. Use SonarLint in your IDE to catch issues early
|
493
|
+
3. Review SonarCloud analysis results in PR comments
|
494
|
+
|
463
495
|
## Contributing
|
464
496
|
Contributions are welcome! Here's how you can help:
|
465
497
|
|
@@ -437,6 +437,38 @@ Provides MySQL-specific features:
|
|
437
437
|
- SSL/TLS secure connection
|
438
438
|
- URL and standard connection methods
|
439
439
|
|
440
|
+
## Code Quality
|
441
|
+
|
442
|
+
### Quality Gates
|
443
|
+
We use SonarCloud to maintain high code quality standards. All pull requests must pass the following quality gates:
|
444
|
+
|
445
|
+
- Code Coverage: ≥ 80%
|
446
|
+
- Code Quality:
|
447
|
+
* No blocker or critical issues
|
448
|
+
* Less than 10 major issues
|
449
|
+
* Code duplication < 3%
|
450
|
+
- Security:
|
451
|
+
* No security vulnerabilities
|
452
|
+
* No security hotspots
|
453
|
+
|
454
|
+
### Automated Checks
|
455
|
+
Our CI/CD pipeline automatically performs:
|
456
|
+
1. Full test suite execution
|
457
|
+
2. Code coverage analysis
|
458
|
+
3. SonarCloud static code analysis
|
459
|
+
4. Quality gate validation
|
460
|
+
|
461
|
+
Pull requests that don't meet these standards will be automatically blocked from merging.
|
462
|
+
|
463
|
+
### Local Development
|
464
|
+
To check code quality locally:
|
465
|
+
1. Run tests with coverage:
|
466
|
+
```bash
|
467
|
+
pytest --cov=src/mcp_dbutils --cov-report=xml:coverage.xml tests/
|
468
|
+
```
|
469
|
+
2. Use SonarLint in your IDE to catch issues early
|
470
|
+
3. Review SonarCloud analysis results in PR comments
|
471
|
+
|
440
472
|
## Contributing
|
441
473
|
Contributions are welcome! Here's how you can help:
|
442
474
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
sonar.organization=donghao1393
|
2
|
+
sonar.projectKey=donghao1393_mcp-dbutils
|
3
|
+
sonar.sources=src/mcp_dbutils
|
4
|
+
sonar.tests=tests
|
5
|
+
sonar.python.coverage.reportPaths=coverage.xml
|
6
|
+
sonar.python.version=3.10
|
7
|
+
|
8
|
+
# PR Analysis Configuration
|
9
|
+
sonar.pullrequest.provider=github
|
10
|
+
sonar.pullrequest.github.repository=donghao1393/mcp-dbutils
|
11
|
+
sonar.pullrequest.github.endpoint=https://api.github.com/
|
12
|
+
|
13
|
+
# Quality Gate Settings
|
14
|
+
sonar.qualitygate.wait=true
|
@@ -1,102 +0,0 @@
|
|
1
|
-
name: Quality Assurance
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ main ]
|
6
|
-
pull_request:
|
7
|
-
branches: [ main ]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
pytest:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
|
13
|
-
services:
|
14
|
-
postgres:
|
15
|
-
image: postgres:15-alpine
|
16
|
-
env:
|
17
|
-
POSTGRES_PASSWORD: postgres
|
18
|
-
ports:
|
19
|
-
- 5432:5432
|
20
|
-
options: >-
|
21
|
-
--health-cmd pg_isready
|
22
|
-
--health-interval 10s
|
23
|
-
--health-timeout 5s
|
24
|
-
--health-retries 5
|
25
|
-
|
26
|
-
steps:
|
27
|
-
- uses: actions/checkout@v4
|
28
|
-
|
29
|
-
- name: Install uv
|
30
|
-
uses: astral-sh/setup-uv@v4
|
31
|
-
|
32
|
-
- name: Set up Python
|
33
|
-
run: uv python install
|
34
|
-
|
35
|
-
- name: Create and activate venv
|
36
|
-
run: |
|
37
|
-
uv venv
|
38
|
-
. .venv/bin/activate
|
39
|
-
|
40
|
-
- name: Install dependencies
|
41
|
-
run: uv pip install -e ".[test]"
|
42
|
-
|
43
|
-
- name: Run tests with coverage
|
44
|
-
id: tests
|
45
|
-
run: |
|
46
|
-
uv run pytest \
|
47
|
-
-v \
|
48
|
-
--cov=src/mcp_dbutils \
|
49
|
-
--cov-report=html \
|
50
|
-
--cov-report=term-missing \
|
51
|
-
--cov-report=json:coverage.json \
|
52
|
-
--cov-report=xml:coverage.xml \
|
53
|
-
tests/
|
54
|
-
|
55
|
-
- name: Upload coverage report
|
56
|
-
uses: actions/upload-artifact@v4
|
57
|
-
with:
|
58
|
-
name: coverage-report
|
59
|
-
path: coverage.xml
|
60
|
-
|
61
|
-
- name: Calculate coverage percentage
|
62
|
-
id: calc_coverage
|
63
|
-
run: |
|
64
|
-
COVERAGE=$(jq -r '.totals.percent_covered' coverage.json)
|
65
|
-
echo "Coverage: $COVERAGE"
|
66
|
-
echo "percentage=${COVERAGE%.*}" >> $GITHUB_OUTPUT
|
67
|
-
if (( $(echo "$COVERAGE >= 90" | bc -l) )); then
|
68
|
-
echo "color=green" >> $GITHUB_OUTPUT
|
69
|
-
elif (( $(echo "$COVERAGE >= 80" | bc -l) )); then
|
70
|
-
echo "color=yellow" >> $GITHUB_OUTPUT
|
71
|
-
else
|
72
|
-
echo "color=red" >> $GITHUB_OUTPUT
|
73
|
-
fi
|
74
|
-
|
75
|
-
- name: Create Coverage Badge
|
76
|
-
uses: schneegans/dynamic-badges-action@v1.7.0
|
77
|
-
with:
|
78
|
-
auth: ${{ secrets.GIST_SECRET }}
|
79
|
-
gistID: bdd0a63ec2a816539ff8c136ceb41e48
|
80
|
-
filename: coverage.json
|
81
|
-
label: "coverage"
|
82
|
-
message: "${{ steps.calc_coverage.outputs.percentage }}%"
|
83
|
-
color: "${{ steps.calc_coverage.outputs.color }}"
|
84
|
-
namedLogo: python
|
85
|
-
|
86
|
-
sonarcloud:
|
87
|
-
name: SonarCloud
|
88
|
-
needs: pytest
|
89
|
-
runs-on: ubuntu-latest
|
90
|
-
steps:
|
91
|
-
- uses: actions/checkout@v4
|
92
|
-
with:
|
93
|
-
fetch-depth: 0
|
94
|
-
- name: Download coverage report
|
95
|
-
uses: actions/download-artifact@v4
|
96
|
-
with:
|
97
|
-
name: coverage-report
|
98
|
-
- name: SonarCloud Scan
|
99
|
-
uses: SonarSource/sonarqube-scan-action@v5.0.0
|
100
|
-
env:
|
101
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
102
|
-
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|