manage-project-tool 0.1.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.
- manage_project_tool-0.1.0/.gitignore +76 -0
- manage_project_tool-0.1.0/LICENSE +21 -0
- manage_project_tool-0.1.0/PKG-INFO +113 -0
- manage_project_tool-0.1.0/README.md +91 -0
- manage_project_tool-0.1.0/docs/README.md +21 -0
- manage_project_tool-0.1.0/electron/assets/README.md +10 -0
- manage_project_tool-0.1.0/engine/__init__.py +1 -0
- manage_project_tool-0.1.0/engine/checks/__init__.py +49 -0
- manage_project_tool-0.1.0/engine/checks/changelog_presence.py +36 -0
- manage_project_tool-0.1.0/engine/checks/contributing_presence.py +33 -0
- manage_project_tool-0.1.0/engine/checks/dependency_freshness.py +98 -0
- manage_project_tool-0.1.0/engine/checks/env_example_presence.py +73 -0
- manage_project_tool-0.1.0/engine/checks/gitignore_presence.py +129 -0
- manage_project_tool-0.1.0/engine/checks/license_presence.py +37 -0
- manage_project_tool-0.1.0/engine/checks/package_json_fields.py +53 -0
- manage_project_tool-0.1.0/engine/checks/secrets_scan.py +132 -0
- manage_project_tool-0.1.0/engine/checks/security_audit.py +129 -0
- manage_project_tool-0.1.0/engine/checks/test_presence.py +52 -0
- manage_project_tool-0.1.0/engine/cli.py +376 -0
- manage_project_tool-0.1.0/engine/engine.py +1053 -0
- manage_project_tool-0.1.0/engine/github_action.py +215 -0
- manage_project_tool-0.1.0/pyproject.toml +45 -0
- manage_project_tool-0.1.0/requirements.txt +8 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# ManageProjectTool .gitignore
|
|
2
|
+
|
|
3
|
+
# Node
|
|
4
|
+
node_modules/
|
|
5
|
+
npm-debug.log*
|
|
6
|
+
yarn-debug.log*
|
|
7
|
+
yarn-error.log*
|
|
8
|
+
pnpm-debug.log*
|
|
9
|
+
.pnp.*
|
|
10
|
+
|
|
11
|
+
# Logs
|
|
12
|
+
logs/
|
|
13
|
+
*.log
|
|
14
|
+
*.log.*
|
|
15
|
+
|
|
16
|
+
# Runtime / environment
|
|
17
|
+
.env
|
|
18
|
+
.env.*
|
|
19
|
+
|
|
20
|
+
# Build outputs
|
|
21
|
+
dist/
|
|
22
|
+
build/
|
|
23
|
+
|
|
24
|
+
# Coverage
|
|
25
|
+
coverage/
|
|
26
|
+
.nyc_output/
|
|
27
|
+
htmlcov/
|
|
28
|
+
|
|
29
|
+
# Python
|
|
30
|
+
.venv/
|
|
31
|
+
venv/
|
|
32
|
+
ENV/
|
|
33
|
+
env/
|
|
34
|
+
__pycache__/
|
|
35
|
+
*.py[cod]
|
|
36
|
+
*$py.class
|
|
37
|
+
.pytest_cache/
|
|
38
|
+
.mypy_cache/
|
|
39
|
+
.coverage
|
|
40
|
+
pip-wheel-metadata/
|
|
41
|
+
*.egg-info/
|
|
42
|
+
.eggs/
|
|
43
|
+
*.egg
|
|
44
|
+
*.whl
|
|
45
|
+
|
|
46
|
+
# PyInstaller
|
|
47
|
+
__pycache__/
|
|
48
|
+
dist/
|
|
49
|
+
build/
|
|
50
|
+
|
|
51
|
+
# Caches
|
|
52
|
+
.cache/
|
|
53
|
+
|
|
54
|
+
# IDEs and editors
|
|
55
|
+
.vscode/
|
|
56
|
+
.idea/
|
|
57
|
+
*.suo
|
|
58
|
+
*.ntvs*
|
|
59
|
+
*.njsproj
|
|
60
|
+
*.sln
|
|
61
|
+
*.swp
|
|
62
|
+
*~
|
|
63
|
+
*.tmp
|
|
64
|
+
*.bak
|
|
65
|
+
|
|
66
|
+
# OS files
|
|
67
|
+
.DS_Store
|
|
68
|
+
Thumbs.db
|
|
69
|
+
desktop.ini
|
|
70
|
+
|
|
71
|
+
# Lint / tooling
|
|
72
|
+
.eslintcache
|
|
73
|
+
|
|
74
|
+
# Other
|
|
75
|
+
node-repl.history
|
|
76
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jaminsmoke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: manage-project-tool
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python engine for ManageProjectTool — audits and manages repositories
|
|
5
|
+
Project-URL: Homepage, https://github.com/jaminsmoke/ManageProjectTool
|
|
6
|
+
Project-URL: Repository, https://github.com/jaminsmoke/ManageProjectTool
|
|
7
|
+
Project-URL: Issues, https://github.com/jaminsmoke/ManageProjectTool/issues
|
|
8
|
+
Author: jaminsmoke
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: manageprojecttool,mpt,project-audit,static-analysis
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# ManageProjectTool
|
|
24
|
+
|
|
25
|
+
ManageProjectTool audita repositorios con un engine Python, un coordinator
|
|
26
|
+
Node.js, una app Electron y una GitHub Action reutilizable para CI.
|
|
27
|
+
|
|
28
|
+
## Capacidades actuales
|
|
29
|
+
|
|
30
|
+
- Ejecuta checks core y plugins sobre documentación, CI, dependencias y seguridad.
|
|
31
|
+
- Aplica severidades efectivas (`error`, `warning`, `info`) y umbrales como
|
|
32
|
+
`thresholds.maxWarnings` desde `mpt.config.json`.
|
|
33
|
+
- Expone un CLI standalone con `mpt scan` y `mpt init`.
|
|
34
|
+
- Genera reportes en JSON, HTML y Markdown según el flujo de uso.
|
|
35
|
+
|
|
36
|
+
## Uso local
|
|
37
|
+
|
|
38
|
+
### CLI Python
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python -m engine.cli scan .
|
|
42
|
+
python -m engine.cli scan . --format json
|
|
43
|
+
python -m engine.cli init .
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Validación del workspace
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install
|
|
50
|
+
npm run validate
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`npm run validate` ejecuta formato, linters y tests en secuencia.
|
|
54
|
+
|
|
55
|
+
### Preparación de release (Fase B)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm run release:check
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Este comando valida prerequisitos implementables en el repo para `v0.1.0`
|
|
62
|
+
(`LICENSE`, artefactos de Action y assets de Electron) y lista pendientes
|
|
63
|
+
externos como Trusted Publisher en PyPI, `NPM_TOKEN` y Marketplace.
|
|
64
|
+
|
|
65
|
+
## GitHub Action
|
|
66
|
+
|
|
67
|
+
La Action Docker definida en la raíz permite reutilizar el engine sin levantar
|
|
68
|
+
el coordinator.
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
name: Scan repository
|
|
72
|
+
|
|
73
|
+
on:
|
|
74
|
+
pull_request:
|
|
75
|
+
workflow_dispatch:
|
|
76
|
+
|
|
77
|
+
jobs:
|
|
78
|
+
scan:
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
- name: Run ManageProjectTool
|
|
83
|
+
id: mpt
|
|
84
|
+
uses: jaminsmoke/ManageProjectTool@v0.1.0
|
|
85
|
+
with:
|
|
86
|
+
target-path: .
|
|
87
|
+
format: markdown
|
|
88
|
+
checks: readme-presence,lockfile,ci-workflow-presence
|
|
89
|
+
- name: Upload report
|
|
90
|
+
if: always()
|
|
91
|
+
uses: actions/upload-artifact@v4
|
|
92
|
+
with:
|
|
93
|
+
name: mpt-report
|
|
94
|
+
path: ${{ steps.mpt.outputs.report-path }}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Entradas soportadas:
|
|
98
|
+
|
|
99
|
+
- `target-path`: ruta relativa dentro de `GITHUB_WORKSPACE`.
|
|
100
|
+
- `checks`: lista separada por comas; vacía usa `mpt.config.json` o todos los checks.
|
|
101
|
+
- `format`: `markdown` o `json`.
|
|
102
|
+
|
|
103
|
+
Salidas expuestas:
|
|
104
|
+
|
|
105
|
+
- `report-path`: fichero generado en `reports/`.
|
|
106
|
+
- `exit-code`: resultado efectivo de la política de severidad.
|
|
107
|
+
- `summary-json`: resumen compacto para pasos posteriores.
|
|
108
|
+
|
|
109
|
+
## Documentación
|
|
110
|
+
|
|
111
|
+
- [docs/checks.md](docs/checks.md)
|
|
112
|
+
- [docs/github-action.md](docs/github-action.md)
|
|
113
|
+
- [docs/roadmaps/roadmap2.md](docs/roadmaps/roadmap2.md)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ManageProjectTool
|
|
2
|
+
|
|
3
|
+
ManageProjectTool audita repositorios con un engine Python, un coordinator
|
|
4
|
+
Node.js, una app Electron y una GitHub Action reutilizable para CI.
|
|
5
|
+
|
|
6
|
+
## Capacidades actuales
|
|
7
|
+
|
|
8
|
+
- Ejecuta checks core y plugins sobre documentación, CI, dependencias y seguridad.
|
|
9
|
+
- Aplica severidades efectivas (`error`, `warning`, `info`) y umbrales como
|
|
10
|
+
`thresholds.maxWarnings` desde `mpt.config.json`.
|
|
11
|
+
- Expone un CLI standalone con `mpt scan` y `mpt init`.
|
|
12
|
+
- Genera reportes en JSON, HTML y Markdown según el flujo de uso.
|
|
13
|
+
|
|
14
|
+
## Uso local
|
|
15
|
+
|
|
16
|
+
### CLI Python
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
python -m engine.cli scan .
|
|
20
|
+
python -m engine.cli scan . --format json
|
|
21
|
+
python -m engine.cli init .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Validación del workspace
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install
|
|
28
|
+
npm run validate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`npm run validate` ejecuta formato, linters y tests en secuencia.
|
|
32
|
+
|
|
33
|
+
### Preparación de release (Fase B)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm run release:check
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Este comando valida prerequisitos implementables en el repo para `v0.1.0`
|
|
40
|
+
(`LICENSE`, artefactos de Action y assets de Electron) y lista pendientes
|
|
41
|
+
externos como Trusted Publisher en PyPI, `NPM_TOKEN` y Marketplace.
|
|
42
|
+
|
|
43
|
+
## GitHub Action
|
|
44
|
+
|
|
45
|
+
La Action Docker definida en la raíz permite reutilizar el engine sin levantar
|
|
46
|
+
el coordinator.
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
name: Scan repository
|
|
50
|
+
|
|
51
|
+
on:
|
|
52
|
+
pull_request:
|
|
53
|
+
workflow_dispatch:
|
|
54
|
+
|
|
55
|
+
jobs:
|
|
56
|
+
scan:
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
- name: Run ManageProjectTool
|
|
61
|
+
id: mpt
|
|
62
|
+
uses: jaminsmoke/ManageProjectTool@v0.1.0
|
|
63
|
+
with:
|
|
64
|
+
target-path: .
|
|
65
|
+
format: markdown
|
|
66
|
+
checks: readme-presence,lockfile,ci-workflow-presence
|
|
67
|
+
- name: Upload report
|
|
68
|
+
if: always()
|
|
69
|
+
uses: actions/upload-artifact@v4
|
|
70
|
+
with:
|
|
71
|
+
name: mpt-report
|
|
72
|
+
path: ${{ steps.mpt.outputs.report-path }}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Entradas soportadas:
|
|
76
|
+
|
|
77
|
+
- `target-path`: ruta relativa dentro de `GITHUB_WORKSPACE`.
|
|
78
|
+
- `checks`: lista separada por comas; vacía usa `mpt.config.json` o todos los checks.
|
|
79
|
+
- `format`: `markdown` o `json`.
|
|
80
|
+
|
|
81
|
+
Salidas expuestas:
|
|
82
|
+
|
|
83
|
+
- `report-path`: fichero generado en `reports/`.
|
|
84
|
+
- `exit-code`: resultado efectivo de la política de severidad.
|
|
85
|
+
- `summary-json`: resumen compacto para pasos posteriores.
|
|
86
|
+
|
|
87
|
+
## Documentación
|
|
88
|
+
|
|
89
|
+
- [docs/checks.md](docs/checks.md)
|
|
90
|
+
- [docs/github-action.md](docs/github-action.md)
|
|
91
|
+
- [docs/roadmaps/roadmap2.md](docs/roadmaps/roadmap2.md)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Documentación del proyecto ManageProjectTool
|
|
2
|
+
|
|
3
|
+
Este directorio contiene los documentos que definen el alcance, diseño y roadmap del proyecto.
|
|
4
|
+
|
|
5
|
+
Archivos:
|
|
6
|
+
|
|
7
|
+
- `vision.md` — Visión y objetivos
|
|
8
|
+
- `requirements.md` — Requisitos y alcance
|
|
9
|
+
- `architecture.md` — Arquitectura y decisiones
|
|
10
|
+
- `structure_conventions.md` — Estructura del repositorio y convenciones
|
|
11
|
+
- `metrics.md` — Métricas y reglas para auditoría automática
|
|
12
|
+
- `checks.md` — Catálogo de checks, severidades y política de salida
|
|
13
|
+
- `github-action.md` — Uso de la GitHub Action Docker y sus outputs
|
|
14
|
+
- `roadmaps/roadmap2.md` — Roadmap activo y milestones vigentes
|
|
15
|
+
- `contribution.md` — Guía para contribuir
|
|
16
|
+
|
|
17
|
+
Cómo usar:
|
|
18
|
+
|
|
19
|
+
- Completa y revisa cada documento.
|
|
20
|
+
- Los cambios en la carpeta `docs` deben discutirse en PRs.
|
|
21
|
+
- Próximo paso: cerrar los pendientes externos de la Fase B y validar el primer release público.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Electron Assets
|
|
2
|
+
|
|
3
|
+
Esta carpeta contiene los iconos usados por `electron-builder`:
|
|
4
|
+
|
|
5
|
+
- `icon.ico` (Windows)
|
|
6
|
+
- `icon.icns` (macOS)
|
|
7
|
+
- `icon.png` (Linux)
|
|
8
|
+
|
|
9
|
+
Las referencias `icon:` ya están habilitadas en
|
|
10
|
+
[electron-builder.yml](../../electron-builder.yml).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""ManageProjectTool engine package."""
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""A1 checks package — nuevos checks estándar del roadmap v2 Fase A."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from engine.checks import (
|
|
8
|
+
changelog_presence,
|
|
9
|
+
contributing_presence,
|
|
10
|
+
dependency_freshness,
|
|
11
|
+
env_example_presence,
|
|
12
|
+
gitignore_presence,
|
|
13
|
+
license_presence,
|
|
14
|
+
package_json_fields,
|
|
15
|
+
secrets_scan,
|
|
16
|
+
security_audit,
|
|
17
|
+
test_presence,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from engine.engine import CheckDefinition, CheckRunner
|
|
22
|
+
|
|
23
|
+
ALL_DEFINITIONS: list[CheckDefinition] = [
|
|
24
|
+
contributing_presence.DEFINITION,
|
|
25
|
+
changelog_presence.DEFINITION,
|
|
26
|
+
license_presence.DEFINITION,
|
|
27
|
+
env_example_presence.DEFINITION,
|
|
28
|
+
package_json_fields.DEFINITION,
|
|
29
|
+
gitignore_presence.DEFINITION,
|
|
30
|
+
dependency_freshness.DEFINITION,
|
|
31
|
+
test_presence.DEFINITION,
|
|
32
|
+
security_audit.DEFINITION,
|
|
33
|
+
secrets_scan.DEFINITION,
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
ALL_RUNNERS: dict[str, CheckRunner] = {
|
|
37
|
+
contributing_presence.DEFINITION["id"]: contributing_presence.run,
|
|
38
|
+
changelog_presence.DEFINITION["id"]: changelog_presence.run,
|
|
39
|
+
license_presence.DEFINITION["id"]: license_presence.run,
|
|
40
|
+
env_example_presence.DEFINITION["id"]: env_example_presence.run,
|
|
41
|
+
package_json_fields.DEFINITION["id"]: package_json_fields.run,
|
|
42
|
+
gitignore_presence.DEFINITION["id"]: gitignore_presence.run,
|
|
43
|
+
dependency_freshness.DEFINITION["id"]: dependency_freshness.run,
|
|
44
|
+
test_presence.DEFINITION["id"]: test_presence.run,
|
|
45
|
+
security_audit.DEFINITION["id"]: security_audit.run,
|
|
46
|
+
secrets_scan.DEFINITION["id"]: secrets_scan.run,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
__all__ = ["ALL_DEFINITIONS", "ALL_RUNNERS"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Check: changelog-presence — verifica que existe CHANGELOG.md o RELEASES.md."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from engine.engine import CheckDefinition, CheckResult
|
|
11
|
+
|
|
12
|
+
DEFINITION: CheckDefinition = {
|
|
13
|
+
"id": "changelog-presence",
|
|
14
|
+
"name": "CHANGELOG presente",
|
|
15
|
+
"category": "docs",
|
|
16
|
+
"severity": "medium",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_CANDIDATES = [
|
|
20
|
+
"CHANGELOG.md",
|
|
21
|
+
"CHANGELOG.rst",
|
|
22
|
+
"CHANGELOG.txt",
|
|
23
|
+
"CHANGELOG",
|
|
24
|
+
"RELEASES.md",
|
|
25
|
+
"RELEASES.rst",
|
|
26
|
+
"HISTORY.md",
|
|
27
|
+
"CHANGES.md",
|
|
28
|
+
"docs/CHANGELOG.md",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run(repo_path: str) -> CheckResult:
|
|
33
|
+
for candidate in _CANDIDATES:
|
|
34
|
+
if os.path.isfile(os.path.join(repo_path, candidate)):
|
|
35
|
+
return {"ok": True, "file": candidate, "candidates": _CANDIDATES}
|
|
36
|
+
return {"ok": False, "file": None, "candidates": _CANDIDATES}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Check: contributing-presence — verifica que existe CONTRIBUTING.md."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from engine.engine import CheckDefinition, CheckResult
|
|
11
|
+
|
|
12
|
+
DEFINITION: CheckDefinition = {
|
|
13
|
+
"id": "contributing-presence",
|
|
14
|
+
"name": "CONTRIBUTING presente",
|
|
15
|
+
"category": "docs",
|
|
16
|
+
"severity": "medium",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_CANDIDATES = [
|
|
20
|
+
"CONTRIBUTING.md",
|
|
21
|
+
"CONTRIBUTING.rst",
|
|
22
|
+
"CONTRIBUTING.txt",
|
|
23
|
+
"CONTRIBUTING",
|
|
24
|
+
".github/CONTRIBUTING.md",
|
|
25
|
+
"docs/CONTRIBUTING.md",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run(repo_path: str) -> CheckResult:
|
|
30
|
+
for candidate in _CANDIDATES:
|
|
31
|
+
if os.path.isfile(os.path.join(repo_path, candidate)):
|
|
32
|
+
return {"ok": True, "file": candidate, "candidates": _CANDIDATES}
|
|
33
|
+
return {"ok": False, "file": None, "candidates": _CANDIDATES}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Check: dependency-freshness — detecta dependencias muy desactualizadas."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from engine.engine import CheckDefinition, CheckResult
|
|
13
|
+
|
|
14
|
+
DEFINITION: CheckDefinition = {
|
|
15
|
+
"id": "dependency-freshness",
|
|
16
|
+
"name": "Dependencias actualizadas",
|
|
17
|
+
"category": "dependencies",
|
|
18
|
+
"severity": "medium",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_SUBPROCESS_TIMEOUT = 30
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _run_npm_outdated(repo_path: str) -> dict[str, object] | None:
|
|
25
|
+
"""Run `npm outdated --json`. Returns parsed output or None if unavailable."""
|
|
26
|
+
pkg_path = os.path.join(repo_path, "package.json")
|
|
27
|
+
if not os.path.isfile(pkg_path):
|
|
28
|
+
return None
|
|
29
|
+
try:
|
|
30
|
+
proc = subprocess.run(
|
|
31
|
+
["npm", "outdated", "--json"],
|
|
32
|
+
cwd=repo_path,
|
|
33
|
+
capture_output=True,
|
|
34
|
+
text=True,
|
|
35
|
+
timeout=_SUBPROCESS_TIMEOUT,
|
|
36
|
+
check=False,
|
|
37
|
+
)
|
|
38
|
+
if proc.stdout.strip():
|
|
39
|
+
return json.loads(proc.stdout)
|
|
40
|
+
return {}
|
|
41
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _run_pip_outdated(repo_path: str) -> list[dict[str, str]] | None:
|
|
46
|
+
"""Run `pip list --outdated --format json`. Returns list or None if unavailable."""
|
|
47
|
+
has_reqs = any(
|
|
48
|
+
os.path.isfile(os.path.join(repo_path, f))
|
|
49
|
+
for f in (
|
|
50
|
+
"requirements.txt",
|
|
51
|
+
"pyproject.toml",
|
|
52
|
+
"Pipfile",
|
|
53
|
+
"setup.py",
|
|
54
|
+
"setup.cfg",
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
if not has_reqs:
|
|
58
|
+
return None
|
|
59
|
+
try:
|
|
60
|
+
proc = subprocess.run(
|
|
61
|
+
["pip", "list", "--outdated", "--format", "json"],
|
|
62
|
+
cwd=repo_path,
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
timeout=_SUBPROCESS_TIMEOUT,
|
|
66
|
+
check=False,
|
|
67
|
+
)
|
|
68
|
+
if proc.stdout.strip():
|
|
69
|
+
return json.loads(proc.stdout)
|
|
70
|
+
return []
|
|
71
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def run(repo_path: str) -> CheckResult:
|
|
76
|
+
npm_outdated = _run_npm_outdated(repo_path)
|
|
77
|
+
pip_outdated = _run_pip_outdated(repo_path)
|
|
78
|
+
|
|
79
|
+
if npm_outdated is None and pip_outdated is None:
|
|
80
|
+
return {
|
|
81
|
+
"ok": True,
|
|
82
|
+
"skipped": True,
|
|
83
|
+
"reason": "No supported ecosystems detected or tools unavailable",
|
|
84
|
+
"npm_outdated": None,
|
|
85
|
+
"pip_outdated": None,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
npm_count = len(npm_outdated) if npm_outdated else 0
|
|
89
|
+
pip_count = len(pip_outdated) if pip_outdated else 0
|
|
90
|
+
total_outdated = npm_count + pip_count
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
"ok": total_outdated == 0,
|
|
94
|
+
"skipped": False,
|
|
95
|
+
"total_outdated": total_outdated,
|
|
96
|
+
"npm_outdated": npm_outdated,
|
|
97
|
+
"pip_outdated": pip_outdated,
|
|
98
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Check: env-example-presence — si hay referencias a .env en el repo, existe .env.example."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from engine.engine import CheckDefinition, CheckResult
|
|
11
|
+
|
|
12
|
+
DEFINITION: CheckDefinition = {
|
|
13
|
+
"id": "env-example-presence",
|
|
14
|
+
"name": ".env.example presente cuando se usan variables de entorno",
|
|
15
|
+
"category": "hygiene",
|
|
16
|
+
"severity": "high",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_ENV_INDICATORS = [
|
|
20
|
+
".env",
|
|
21
|
+
"docker-compose.yml",
|
|
22
|
+
"docker-compose.yaml",
|
|
23
|
+
"docker-compose.override.yml",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
_DOCKER_COMPOSE_ENV_MARKER = ".env"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _has_env_usage(repo_path: str) -> bool:
|
|
30
|
+
"""Return True if the repo shows signs of relying on a .env file."""
|
|
31
|
+
if os.path.isfile(os.path.join(repo_path, ".env")):
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
for compose_name in ("docker-compose.yml", "docker-compose.yaml"):
|
|
35
|
+
compose_path = os.path.join(repo_path, compose_name)
|
|
36
|
+
if not os.path.isfile(compose_path):
|
|
37
|
+
continue
|
|
38
|
+
try:
|
|
39
|
+
with open(compose_path, encoding="utf-8") as f:
|
|
40
|
+
if ".env" in f.read():
|
|
41
|
+
return True
|
|
42
|
+
except OSError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
makefile_path = os.path.join(repo_path, "Makefile")
|
|
46
|
+
if os.path.isfile(makefile_path):
|
|
47
|
+
try:
|
|
48
|
+
with open(makefile_path, encoding="utf-8") as f:
|
|
49
|
+
if ".env" in f.read():
|
|
50
|
+
return True
|
|
51
|
+
except OSError:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def run(repo_path: str) -> CheckResult:
|
|
58
|
+
if not _has_env_usage(repo_path):
|
|
59
|
+
return {
|
|
60
|
+
"ok": True,
|
|
61
|
+
"skipped": True,
|
|
62
|
+
"reason": "No .env usage detected",
|
|
63
|
+
"file": None,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
example_path = os.path.join(repo_path, ".env.example")
|
|
67
|
+
found = os.path.isfile(example_path)
|
|
68
|
+
return {
|
|
69
|
+
"ok": found,
|
|
70
|
+
"skipped": False,
|
|
71
|
+
"file": ".env.example" if found else None,
|
|
72
|
+
"has_env_usage": True,
|
|
73
|
+
}
|