mcp-dbutils 0.13.0__tar.gz → 0.15.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.15.0/.github/workflows/code-style.yml +17 -0
- mcp_dbutils-0.15.0/.github/workflows/quality-assurance.yml +266 -0
- mcp_dbutils-0.15.0/.pre-commit-config.yaml +7 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/CHANGELOG.md +14 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/PKG-INFO +36 -1
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/README.md +33 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/README_CN.md +65 -0
- mcp_dbutils-0.15.0/pyproject.toml +119 -0
- mcp_dbutils-0.15.0/sonar-project.properties +14 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/__init__.py +4 -3
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/base.py +5 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/config.py +3 -4
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/log.py +2 -1
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/mysql/config.py +4 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/mysql/handler.py +2 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/mysql/server.py +6 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/postgres/config.py +4 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/postgres/handler.py +2 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/postgres/server.py +6 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/sqlite/config.py +4 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/sqlite/handler.py +2 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/sqlite/server.py +5 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/stats.py +4 -3
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/conftest.py +6 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/conftest.py +3 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/fixtures.py +8 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_logging.py +4 -7
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_monitoring.py +5 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_monitoring_enhanced.py +6 -5
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_mysql.py +7 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_mysql_config.py +5 -4
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_postgres.py +7 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_postgres_config.py +4 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_prompts.py +4 -3
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_sqlite.py +8 -3
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_sqlite_config.py +4 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_tools.py +4 -3
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/test_tools_advanced.py +4 -3
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/unit/test_log.py +5 -2
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/unit/test_stats.py +2 -1
- mcp_dbutils-0.13.0/.github/workflows/quality-assurance.yml +0 -110
- mcp_dbutils-0.13.0/pyproject.toml +0 -58
- mcp_dbutils-0.13.0/sonar-project.properties +0 -6
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/.coveragerc +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/.github/workflows/release.yml +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/.gitignore +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/.releaserc.json +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/Dockerfile +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/LICENSE +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/config.yaml.example +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/smithery.yaml +0 -0
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/mysql/__init__.py +1 -1
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/postgres/__init__.py +1 -1
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/src/mcp_dbutils/sqlite/__init__.py +1 -1
- {mcp_dbutils-0.13.0 → mcp_dbutils-0.15.0}/tests/integration/__init__.py +0 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
name: Code Style
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
ruff:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
steps:
|
13
|
+
- uses: actions/checkout@v4
|
14
|
+
|
15
|
+
- uses: astral-sh/ruff-action@v3.2.1
|
16
|
+
with:
|
17
|
+
version: latest
|
@@ -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.15.0](https://github.com/donghao1393/mcp-dbutils/compare/v0.14.0...v0.15.0) (2025-03-14)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* integrate Ruff code style automation ([#35](https://github.com/donghao1393/mcp-dbutils/issues/35)) ([6b2bdd7](https://github.com/donghao1393/mcp-dbutils/commit/6b2bdd749cecf2ad9167867c6e41149d1a57746f)), closes [#34](https://github.com/donghao1393/mcp-dbutils/issues/34)
|
7
|
+
|
8
|
+
# [0.14.0](https://github.com/donghao1393/mcp-dbutils/compare/v0.13.0...v0.14.0) (2025-03-14)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* 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)
|
14
|
+
|
1
15
|
# [0.13.0](https://github.com/donghao1393/mcp-dbutils/compare/v0.12.0...v0.13.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.15.0
|
4
4
|
Summary: MCP Database Utilities Service
|
5
5
|
Author: Dong Hao
|
6
6
|
License-Expression: MIT
|
@@ -14,10 +14,12 @@ Requires-Dist: pyyaml>=6.0.2
|
|
14
14
|
Provides-Extra: test
|
15
15
|
Requires-Dist: aiosqlite>=0.19.0; extra == 'test'
|
16
16
|
Requires-Dist: docker>=7.0.0; extra == 'test'
|
17
|
+
Requires-Dist: pre-commit>=3.6.0; extra == 'test'
|
17
18
|
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
|
18
19
|
Requires-Dist: pytest-cov>=4.1.0; extra == 'test'
|
19
20
|
Requires-Dist: pytest-docker>=2.0.0; extra == 'test'
|
20
21
|
Requires-Dist: pytest>=7.0.0; extra == 'test'
|
22
|
+
Requires-Dist: ruff>=0.3.0; extra == 'test'
|
21
23
|
Requires-Dist: testcontainers>=3.7.0; extra == 'test'
|
22
24
|
Description-Content-Type: text/markdown
|
23
25
|
|
@@ -483,6 +485,19 @@ Our CI/CD pipeline automatically performs:
|
|
483
485
|
|
484
486
|
Pull requests that don't meet these standards will be automatically blocked from merging.
|
485
487
|
|
488
|
+
### Code Style
|
489
|
+
We use Ruff for code style checking and formatting:
|
490
|
+
|
491
|
+
[](https://github.com/astral-sh/ruff)
|
492
|
+
|
493
|
+
All code must follow our style guide:
|
494
|
+
- Line length: 88 characters
|
495
|
+
- Indentation: 4 spaces
|
496
|
+
- Quotes: Double quotes
|
497
|
+
- Naming: PEP8 conventions
|
498
|
+
|
499
|
+
For detailed guidelines, see [STYLE_GUIDE.md](docs/STYLE_GUIDE.md).
|
500
|
+
|
486
501
|
### Local Development
|
487
502
|
To check code quality locally:
|
488
503
|
1. Run tests with coverage:
|
@@ -491,6 +506,26 @@ To check code quality locally:
|
|
491
506
|
```
|
492
507
|
2. Use SonarLint in your IDE to catch issues early
|
493
508
|
3. Review SonarCloud analysis results in PR comments
|
509
|
+
4. Run Ruff for code style checking:
|
510
|
+
```bash
|
511
|
+
# Install Ruff
|
512
|
+
uv pip install ruff
|
513
|
+
|
514
|
+
# Check code style
|
515
|
+
ruff check .
|
516
|
+
|
517
|
+
# Format code
|
518
|
+
ruff format .
|
519
|
+
```
|
520
|
+
5. Use pre-commit hooks for automatic checks:
|
521
|
+
```bash
|
522
|
+
# Install pre-commit
|
523
|
+
uv pip install pre-commit
|
524
|
+
pre-commit install
|
525
|
+
|
526
|
+
# Run all checks
|
527
|
+
pre-commit run --all-files
|
528
|
+
```
|
494
529
|
|
495
530
|
## Contributing
|
496
531
|
Contributions are welcome! Here's how you can help:
|
@@ -460,6 +460,19 @@ Our CI/CD pipeline automatically performs:
|
|
460
460
|
|
461
461
|
Pull requests that don't meet these standards will be automatically blocked from merging.
|
462
462
|
|
463
|
+
### Code Style
|
464
|
+
We use Ruff for code style checking and formatting:
|
465
|
+
|
466
|
+
[](https://github.com/astral-sh/ruff)
|
467
|
+
|
468
|
+
All code must follow our style guide:
|
469
|
+
- Line length: 88 characters
|
470
|
+
- Indentation: 4 spaces
|
471
|
+
- Quotes: Double quotes
|
472
|
+
- Naming: PEP8 conventions
|
473
|
+
|
474
|
+
For detailed guidelines, see [STYLE_GUIDE.md](docs/STYLE_GUIDE.md).
|
475
|
+
|
463
476
|
### Local Development
|
464
477
|
To check code quality locally:
|
465
478
|
1. Run tests with coverage:
|
@@ -468,6 +481,26 @@ To check code quality locally:
|
|
468
481
|
```
|
469
482
|
2. Use SonarLint in your IDE to catch issues early
|
470
483
|
3. Review SonarCloud analysis results in PR comments
|
484
|
+
4. Run Ruff for code style checking:
|
485
|
+
```bash
|
486
|
+
# Install Ruff
|
487
|
+
uv pip install ruff
|
488
|
+
|
489
|
+
# Check code style
|
490
|
+
ruff check .
|
491
|
+
|
492
|
+
# Format code
|
493
|
+
ruff format .
|
494
|
+
```
|
495
|
+
5. Use pre-commit hooks for automatic checks:
|
496
|
+
```bash
|
497
|
+
# Install pre-commit
|
498
|
+
uv pip install pre-commit
|
499
|
+
pre-commit install
|
500
|
+
|
501
|
+
# Run all checks
|
502
|
+
pre-commit run --all-files
|
503
|
+
```
|
471
504
|
|
472
505
|
## Contributing
|
473
506
|
Contributions are welcome! Here's how you can help:
|
@@ -419,6 +419,71 @@ except Exception as e:
|
|
419
419
|
- SSL/TLS安全连接
|
420
420
|
- URL和标准连接方式
|
421
421
|
|
422
|
+
## 代码质量
|
423
|
+
|
424
|
+
### 质量门禁
|
425
|
+
我们使用SonarCloud维持高代码质量标准。所有的Pull Request必须通过以下质量门禁:
|
426
|
+
|
427
|
+
- 代码覆盖率:≥ 80%
|
428
|
+
- 代码质量:
|
429
|
+
* 无阻塞级和严重级问题
|
430
|
+
* 主要问题数少于10个
|
431
|
+
* 代码重复率 < 3%
|
432
|
+
- 安全性:
|
433
|
+
* 无安全漏洞
|
434
|
+
* 无安全热点问题
|
435
|
+
|
436
|
+
### 自动化检查
|
437
|
+
我们的CI/CD流程自动执行:
|
438
|
+
1. 完整测试套件运行
|
439
|
+
2. 代码覆盖率分析
|
440
|
+
3. SonarCloud静态代码分析
|
441
|
+
4. 质量门禁验证
|
442
|
+
|
443
|
+
不符合这些标准的Pull Request将被自动阻止合并。
|
444
|
+
|
445
|
+
### 代码风格
|
446
|
+
我们使用Ruff进行代码风格检查和格式化:
|
447
|
+
|
448
|
+
[](https://github.com/astral-sh/ruff)
|
449
|
+
|
450
|
+
所有代码必须遵循我们的风格指南:
|
451
|
+
- 行长度:88个字符
|
452
|
+
- 缩进:4个空格
|
453
|
+
- 引号:双引号
|
454
|
+
- 命名:PEP8约定
|
455
|
+
|
456
|
+
详细指南请参见[STYLE_GUIDE.md](docs/STYLE_GUIDE.md)。
|
457
|
+
|
458
|
+
### 本地开发
|
459
|
+
本地检查代码质量:
|
460
|
+
1. 运行带覆盖率的测试:
|
461
|
+
```bash
|
462
|
+
pytest --cov=src/mcp_dbutils --cov-report=xml:coverage.xml tests/
|
463
|
+
```
|
464
|
+
2. 在IDE中使用SonarLint及早发现问题
|
465
|
+
3. 在PR评论中查看SonarCloud分析结果
|
466
|
+
4. 运行Ruff进行代码风格检查:
|
467
|
+
```bash
|
468
|
+
# 安装Ruff
|
469
|
+
uv pip install ruff
|
470
|
+
|
471
|
+
# 检查代码风格
|
472
|
+
ruff check .
|
473
|
+
|
474
|
+
# 格式化代码
|
475
|
+
ruff format .
|
476
|
+
```
|
477
|
+
5. 使用pre-commit钩子进行自动检查:
|
478
|
+
```bash
|
479
|
+
# 安装pre-commit
|
480
|
+
uv pip install pre-commit
|
481
|
+
pre-commit install
|
482
|
+
|
483
|
+
# 运行所有检查
|
484
|
+
pre-commit run --all-files
|
485
|
+
```
|
486
|
+
|
422
487
|
## 参与贡献
|
423
488
|
欢迎贡献!以下是参与项目的方式:
|
424
489
|
|
@@ -0,0 +1,119 @@
|
|
1
|
+
[project]
|
2
|
+
name = "mcp-dbutils"
|
3
|
+
version = "0.15.0"
|
4
|
+
description = "MCP Database Utilities Service"
|
5
|
+
readme = "README.md"
|
6
|
+
license = "MIT"
|
7
|
+
authors = [
|
8
|
+
{name = "Dong Hao"}
|
9
|
+
]
|
10
|
+
dependencies = [
|
11
|
+
"mcp>=1.2.1",
|
12
|
+
"psycopg2-binary>=2.9.10",
|
13
|
+
"python-dotenv>=1.0.1",
|
14
|
+
"pyyaml>=6.0.2",
|
15
|
+
"mysql-connector-python>=8.2.0",
|
16
|
+
]
|
17
|
+
requires-python = ">=3.10"
|
18
|
+
|
19
|
+
[build-system]
|
20
|
+
requires = ["hatchling"]
|
21
|
+
build-backend = "hatchling.build"
|
22
|
+
|
23
|
+
[project.scripts]
|
24
|
+
mcp-dbutils = "mcp_dbutils:main"
|
25
|
+
|
26
|
+
[tool.semantic_release]
|
27
|
+
version_variables = [
|
28
|
+
"pyproject.toml:project.version"
|
29
|
+
]
|
30
|
+
version_toml = [
|
31
|
+
"pyproject.toml:project.version"
|
32
|
+
]
|
33
|
+
commit_parser = "conventional"
|
34
|
+
major_on_zero = false
|
35
|
+
branch = "main"
|
36
|
+
changelog_components = "semantic_release.changelog.changelog"
|
37
|
+
build_command = "uv build"
|
38
|
+
|
39
|
+
[project.optional-dependencies]
|
40
|
+
test = [
|
41
|
+
"pytest>=7.0.0",
|
42
|
+
"pytest-asyncio>=0.23.0",
|
43
|
+
"pytest-docker>=2.0.0",
|
44
|
+
"docker>=7.0.0",
|
45
|
+
"aiosqlite>=0.19.0",
|
46
|
+
"testcontainers>=3.7.0",
|
47
|
+
"pytest-cov>=4.1.0",
|
48
|
+
"ruff>=0.3.0",
|
49
|
+
"pre-commit>=3.6.0"
|
50
|
+
]
|
51
|
+
|
52
|
+
[tool.pytest.ini_options]
|
53
|
+
asyncio_mode = "strict"
|
54
|
+
asyncio_default_fixture_loop_scope = "function"
|
55
|
+
markers = [
|
56
|
+
"no_collect: marks test classes that should not be collected as test cases"
|
57
|
+
]
|
58
|
+
filterwarnings = [
|
59
|
+
"ignore::pytest.PytestCollectionWarning"
|
60
|
+
]
|
61
|
+
|
62
|
+
# Ruff配置
|
63
|
+
[tool.ruff]
|
64
|
+
# 目标Python版本
|
65
|
+
target-version = "0.15.0"
|
66
|
+
# 行长度限制
|
67
|
+
line-length = 88
|
68
|
+
# 排除的文件和目录
|
69
|
+
exclude = [
|
70
|
+
".git",
|
71
|
+
".venv",
|
72
|
+
"__pycache__",
|
73
|
+
"build",
|
74
|
+
"dist",
|
75
|
+
]
|
76
|
+
|
77
|
+
# Lint配置
|
78
|
+
[tool.ruff.lint]
|
79
|
+
# 选择的规则集
|
80
|
+
select = [
|
81
|
+
"E", # pycodestyle错误
|
82
|
+
"F", # pyflakes
|
83
|
+
"I", # isort
|
84
|
+
"N", # pep8-naming
|
85
|
+
"UP", # pyupgrade
|
86
|
+
"B", # flake8-bugbear
|
87
|
+
"C4", # flake8-comprehensions
|
88
|
+
"SIM", # flake8-simplify
|
89
|
+
"T20", # flake8-print
|
90
|
+
]
|
91
|
+
# 忽略的规则 - 暂时忽略,后续PR中逐步修复
|
92
|
+
ignore = [
|
93
|
+
"E501", # 行太长
|
94
|
+
"B904", # 在except子句中使用raise ... from err
|
95
|
+
"UP035", # 使用新的typing语法
|
96
|
+
"UP006", # 使用新的类型注解语法
|
97
|
+
"UP007", # 使用X | Y替代Union
|
98
|
+
"F401", # 未使用的导入
|
99
|
+
"F541", # f-string没有占位符
|
100
|
+
"UP015", # 不必要的mode参数
|
101
|
+
"UP032", # 使用f-string替代format
|
102
|
+
"B905", # zip()没有strict参数
|
103
|
+
"SIM105", # 使用contextlib.suppress
|
104
|
+
"UP038", # 在isinstance调用中使用X | Y
|
105
|
+
"F821", # 未定义的名称
|
106
|
+
"F841", # 未使用的局部变量
|
107
|
+
"E402", # 模块级导入不在文件顶部
|
108
|
+
"T201", # print语句 - 在日志模块中是必要的
|
109
|
+
]
|
110
|
+
|
111
|
+
# isort配置
|
112
|
+
[tool.ruff.lint.isort]
|
113
|
+
known-first-party = ["mcp_dbutils"]
|
114
|
+
|
115
|
+
# 格式化配置
|
116
|
+
[tool.ruff.format]
|
117
|
+
quote-style = "double"
|
118
|
+
indent-style = "space"
|
119
|
+
line-ending = "auto"
|
@@ -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,15 +1,16 @@
|
|
1
1
|
"""MCP Connection Utilities Service"""
|
2
2
|
|
3
|
-
import asyncio
|
4
3
|
import argparse
|
4
|
+
import asyncio
|
5
5
|
import os
|
6
6
|
import sys
|
7
|
+
from importlib.metadata import metadata
|
7
8
|
from pathlib import Path
|
9
|
+
|
8
10
|
import yaml
|
9
|
-
from importlib.metadata import metadata
|
10
11
|
|
12
|
+
from .base import LOG_NAME, ConnectionServer
|
11
13
|
from .log import create_logger
|
12
|
-
from .base import ConnectionServer, LOG_NAME
|
13
14
|
|
14
15
|
# 获取包信息
|
15
16
|
pkg_meta = metadata("mcp-dbutils")
|
@@ -12,18 +12,17 @@ class ConnectionError(ConnectionHandlerError):
|
|
12
12
|
"""Connection related errors"""
|
13
13
|
pass
|
14
14
|
|
15
|
+
import json
|
15
16
|
from abc import ABC, abstractmethod
|
16
|
-
from typing import Any, List, Optional, AsyncContextManager
|
17
17
|
from contextlib import asynccontextmanager
|
18
|
-
import json
|
19
|
-
import yaml
|
20
|
-
import time
|
21
18
|
from datetime import datetime
|
22
19
|
from importlib.metadata import metadata
|
23
|
-
from
|
20
|
+
from typing import AsyncContextManager
|
21
|
+
|
24
22
|
import mcp.server.stdio
|
25
23
|
import mcp.types as types
|
26
|
-
|
24
|
+
import yaml
|
25
|
+
from mcp.server import Server
|
27
26
|
|
28
27
|
from .log import create_logger
|
29
28
|
from .stats import ResourceStats
|
@@ -1,11 +1,10 @@
|
|
1
1
|
"""Common configuration utilities"""
|
2
2
|
|
3
3
|
import os
|
4
|
-
import yaml
|
5
4
|
from abc import ABC, abstractmethod
|
6
|
-
from
|
7
|
-
|
8
|
-
|
5
|
+
from typing import Any, Dict, Literal
|
6
|
+
|
7
|
+
import yaml
|
9
8
|
|
10
9
|
# Supported connection types
|
11
10
|
ConnectionType = Literal['sqlite', 'postgres', 'mysql']
|