frostwatch 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.
- frostwatch-0.1.0/.github/CODEOWNERS +11 -0
- frostwatch-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +84 -0
- frostwatch-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +55 -0
- frostwatch-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +41 -0
- frostwatch-0.1.0/.github/dependabot.yml +71 -0
- frostwatch-0.1.0/.github/labeler.yml +36 -0
- frostwatch-0.1.0/.github/workflows/ci.yml +121 -0
- frostwatch-0.1.0/.github/workflows/pr-checks.yml +160 -0
- frostwatch-0.1.0/.github/workflows/release.yml +136 -0
- frostwatch-0.1.0/.github/workflows/security.yml +135 -0
- frostwatch-0.1.0/.gitignore +22 -0
- frostwatch-0.1.0/CHANGELOG.md +36 -0
- frostwatch-0.1.0/CODE_OF_CONDUCT.md +41 -0
- frostwatch-0.1.0/CONTRIBUTING.md +125 -0
- frostwatch-0.1.0/Dockerfile +48 -0
- frostwatch-0.1.0/LICENSE +21 -0
- frostwatch-0.1.0/PKG-INFO +36 -0
- frostwatch-0.1.0/README.md +147 -0
- frostwatch-0.1.0/ROADMAP.md +109 -0
- frostwatch-0.1.0/SECURITY.md +49 -0
- frostwatch-0.1.0/docker-compose.yml +24 -0
- frostwatch-0.1.0/frontend/index.html +13 -0
- frostwatch-0.1.0/frontend/package-lock.json +3229 -0
- frostwatch-0.1.0/frontend/package.json +31 -0
- frostwatch-0.1.0/frontend/postcss.config.js +6 -0
- frostwatch-0.1.0/frontend/src/App.tsx +24 -0
- frostwatch-0.1.0/frontend/src/api/client.ts +202 -0
- frostwatch-0.1.0/frontend/src/components/AnomalyBadge.tsx +48 -0
- frostwatch-0.1.0/frontend/src/components/CostChart.tsx +151 -0
- frostwatch-0.1.0/frontend/src/components/Layout.tsx +153 -0
- frostwatch-0.1.0/frontend/src/components/MetricCard.tsx +80 -0
- frostwatch-0.1.0/frontend/src/components/QueryTable.tsx +185 -0
- frostwatch-0.1.0/frontend/src/index.css +48 -0
- frostwatch-0.1.0/frontend/src/main.tsx +25 -0
- frostwatch-0.1.0/frontend/src/pages/Anomalies.tsx +212 -0
- frostwatch-0.1.0/frontend/src/pages/Dashboard.tsx +334 -0
- frostwatch-0.1.0/frontend/src/pages/Queries.tsx +231 -0
- frostwatch-0.1.0/frontend/src/pages/Reports.tsx +232 -0
- frostwatch-0.1.0/frontend/src/pages/Settings.tsx +617 -0
- frostwatch-0.1.0/frontend/src/pages/Warehouses.tsx +189 -0
- frostwatch-0.1.0/frontend/tailwind.config.js +30 -0
- frostwatch-0.1.0/frontend/tsconfig.json +21 -0
- frostwatch-0.1.0/frontend/tsconfig.node.json +10 -0
- frostwatch-0.1.0/frontend/vite.config.ts +26 -0
- frostwatch-0.1.0/frostwatch/__init__.py +1 -0
- frostwatch-0.1.0/frostwatch/alerts/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/alerts/email.py +69 -0
- frostwatch-0.1.0/frostwatch/alerts/slack.py +49 -0
- frostwatch-0.1.0/frostwatch/analysis/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/analysis/anomaly.py +120 -0
- frostwatch-0.1.0/frostwatch/analysis/cost.py +125 -0
- frostwatch-0.1.0/frostwatch/analysis/recommendations.py +102 -0
- frostwatch-0.1.0/frostwatch/api/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/api/app.py +111 -0
- frostwatch-0.1.0/frostwatch/api/limiter.py +6 -0
- frostwatch-0.1.0/frostwatch/api/models.py +135 -0
- frostwatch-0.1.0/frostwatch/api/routes/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/api/routes/anomalies.py +43 -0
- frostwatch-0.1.0/frostwatch/api/routes/dashboard.py +125 -0
- frostwatch-0.1.0/frostwatch/api/routes/queries.py +51 -0
- frostwatch-0.1.0/frostwatch/api/routes/reports.py +132 -0
- frostwatch-0.1.0/frostwatch/api/routes/scheduler_routes.py +44 -0
- frostwatch-0.1.0/frostwatch/api/routes/settings.py +125 -0
- frostwatch-0.1.0/frostwatch/api/routes/sync.py +231 -0
- frostwatch-0.1.0/frostwatch/api/routes/warehouses.py +107 -0
- frostwatch-0.1.0/frostwatch/cli.py +171 -0
- frostwatch-0.1.0/frostwatch/core/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/core/config.py +102 -0
- frostwatch-0.1.0/frostwatch/core/db.py +118 -0
- frostwatch-0.1.0/frostwatch/core/scheduler.py +135 -0
- frostwatch-0.1.0/frostwatch/llm/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/llm/anthropic_provider.py +33 -0
- frostwatch-0.1.0/frostwatch/llm/base.py +14 -0
- frostwatch-0.1.0/frostwatch/llm/factory.py +36 -0
- frostwatch-0.1.0/frostwatch/llm/gemini_provider.py +53 -0
- frostwatch-0.1.0/frostwatch/llm/ollama_provider.py +38 -0
- frostwatch-0.1.0/frostwatch/llm/openai_provider.py +35 -0
- frostwatch-0.1.0/frostwatch/snowflake/__init__.py +0 -0
- frostwatch-0.1.0/frostwatch/snowflake/client.py +60 -0
- frostwatch-0.1.0/frostwatch/snowflake/queries.py +62 -0
- frostwatch-0.1.0/frostwatch.yaml.example +42 -0
- frostwatch-0.1.0/pyproject.toml +74 -0
- frostwatch-0.1.0/tests/__init__.py +0 -0
- frostwatch-0.1.0/tests/unit/__init__.py +0 -0
- frostwatch-0.1.0/tests/unit/test_analysis_anomaly.py +48 -0
- frostwatch-0.1.0/tests/unit/test_analysis_cost.py +51 -0
- frostwatch-0.1.0/tests/unit/test_llm_factory.py +46 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report something that is broken or behaving unexpectedly
|
|
3
|
+
labels: ["bug", "needs-triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to report a bug. Please fill in as much detail as you can.
|
|
9
|
+
|
|
10
|
+
- type: input
|
|
11
|
+
id: version
|
|
12
|
+
attributes:
|
|
13
|
+
label: FrostWatch version
|
|
14
|
+
description: Run `frostwatch version` to get this
|
|
15
|
+
placeholder: "0.1.0"
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: input
|
|
20
|
+
id: python
|
|
21
|
+
attributes:
|
|
22
|
+
label: Python version
|
|
23
|
+
placeholder: "3.11.9"
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: input
|
|
28
|
+
id: os
|
|
29
|
+
attributes:
|
|
30
|
+
label: Operating system
|
|
31
|
+
placeholder: "macOS 14.5 / Ubuntu 22.04 / Docker"
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
34
|
+
|
|
35
|
+
- type: textarea
|
|
36
|
+
id: description
|
|
37
|
+
attributes:
|
|
38
|
+
label: Description
|
|
39
|
+
description: A clear and concise description of what the bug is
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
|
|
43
|
+
- type: textarea
|
|
44
|
+
id: reproduce
|
|
45
|
+
attributes:
|
|
46
|
+
label: Steps to reproduce
|
|
47
|
+
placeholder: |
|
|
48
|
+
1. Configure X as ...
|
|
49
|
+
2. Run `frostwatch serve`
|
|
50
|
+
3. Navigate to /warehouses
|
|
51
|
+
4. See error
|
|
52
|
+
validations:
|
|
53
|
+
required: true
|
|
54
|
+
|
|
55
|
+
- type: textarea
|
|
56
|
+
id: expected
|
|
57
|
+
attributes:
|
|
58
|
+
label: Expected behaviour
|
|
59
|
+
validations:
|
|
60
|
+
required: true
|
|
61
|
+
|
|
62
|
+
- type: textarea
|
|
63
|
+
id: actual
|
|
64
|
+
attributes:
|
|
65
|
+
label: Actual behaviour
|
|
66
|
+
validations:
|
|
67
|
+
required: true
|
|
68
|
+
|
|
69
|
+
- type: textarea
|
|
70
|
+
id: logs
|
|
71
|
+
attributes:
|
|
72
|
+
label: Relevant logs or stack traces
|
|
73
|
+
render: text
|
|
74
|
+
|
|
75
|
+
- type: dropdown
|
|
76
|
+
id: llm_provider
|
|
77
|
+
attributes:
|
|
78
|
+
label: LLM provider (if relevant)
|
|
79
|
+
options:
|
|
80
|
+
- anthropic
|
|
81
|
+
- openai
|
|
82
|
+
- gemini
|
|
83
|
+
- ollama
|
|
84
|
+
- N/A
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest a new feature or improvement
|
|
3
|
+
labels: ["enhancement", "needs-triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Check [ROADMAP.md](https://github.com/arunrajiah/frostwatch/blob/main/ROADMAP.md) first — your idea may already be planned.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: What problem does this solve?
|
|
14
|
+
description: Describe the pain point or use case. "I'm trying to do X but I can't because..."
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: solution
|
|
20
|
+
attributes:
|
|
21
|
+
label: Proposed solution
|
|
22
|
+
description: What would you like to see? How would it work?
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: alternatives
|
|
28
|
+
attributes:
|
|
29
|
+
label: Alternatives considered
|
|
30
|
+
description: What have you tried or considered instead?
|
|
31
|
+
|
|
32
|
+
- type: dropdown
|
|
33
|
+
id: area
|
|
34
|
+
attributes:
|
|
35
|
+
label: Area
|
|
36
|
+
options:
|
|
37
|
+
- Cost analysis
|
|
38
|
+
- Anomaly detection
|
|
39
|
+
- LLM / AI features
|
|
40
|
+
- Alerts (Slack / email)
|
|
41
|
+
- Web UI
|
|
42
|
+
- CLI
|
|
43
|
+
- Snowflake integration
|
|
44
|
+
- Deployment / Docker
|
|
45
|
+
- Documentation
|
|
46
|
+
- Other
|
|
47
|
+
validations:
|
|
48
|
+
required: true
|
|
49
|
+
|
|
50
|
+
- type: checkboxes
|
|
51
|
+
id: contribution
|
|
52
|
+
attributes:
|
|
53
|
+
label: Contribution
|
|
54
|
+
options:
|
|
55
|
+
- label: I am willing to submit a PR for this feature
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences describing what this PR does and why. -->
|
|
4
|
+
|
|
5
|
+
Fixes # <!-- issue number, if applicable -->
|
|
6
|
+
|
|
7
|
+
## Type of change
|
|
8
|
+
|
|
9
|
+
- [ ] Bug fix (non-breaking change that fixes an issue)
|
|
10
|
+
- [ ] New feature (non-breaking change that adds functionality)
|
|
11
|
+
- [ ] Breaking change (fix or feature that would cause existing behaviour to change)
|
|
12
|
+
- [ ] Documentation update
|
|
13
|
+
- [ ] Refactor / internal improvement
|
|
14
|
+
- [ ] CI / tooling
|
|
15
|
+
|
|
16
|
+
## Changes
|
|
17
|
+
|
|
18
|
+
<!-- Bullet-point list of what changed. Be specific — mention file names and function names where useful. -->
|
|
19
|
+
|
|
20
|
+
-
|
|
21
|
+
-
|
|
22
|
+
|
|
23
|
+
## Testing
|
|
24
|
+
|
|
25
|
+
<!-- Describe how you tested this change. -->
|
|
26
|
+
|
|
27
|
+
- [ ] Unit tests added / updated (`pytest tests/`)
|
|
28
|
+
- [ ] Manually tested locally
|
|
29
|
+
- [ ] Frontend build passes (`cd frontend && npm run build`)
|
|
30
|
+
- [ ] No new lint or type errors (`ruff check frostwatch/ && mypy frostwatch/`)
|
|
31
|
+
|
|
32
|
+
## Screenshots (if UI change)
|
|
33
|
+
|
|
34
|
+
<!-- Before / after screenshots help reviewers a lot. Delete this section if not applicable. -->
|
|
35
|
+
|
|
36
|
+
## Checklist
|
|
37
|
+
|
|
38
|
+
- [ ] PR title follows Conventional Commits format (`feat(scope): description`)
|
|
39
|
+
- [ ] I have read [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
40
|
+
- [ ] My changes do not introduce new security vulnerabilities
|
|
41
|
+
- [ ] I have updated documentation where relevant
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
updates:
|
|
4
|
+
- package-ecosystem: pip
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: weekly
|
|
8
|
+
day: monday
|
|
9
|
+
time: "06:00"
|
|
10
|
+
open-pull-requests-limit: 5
|
|
11
|
+
labels:
|
|
12
|
+
- dependencies
|
|
13
|
+
- backend
|
|
14
|
+
ignore:
|
|
15
|
+
- dependency-name: "*"
|
|
16
|
+
update-types: ["version-update:semver-major"]
|
|
17
|
+
groups:
|
|
18
|
+
llm-providers:
|
|
19
|
+
patterns:
|
|
20
|
+
- "anthropic"
|
|
21
|
+
- "openai"
|
|
22
|
+
- "google-genai"
|
|
23
|
+
fastapi-stack:
|
|
24
|
+
patterns:
|
|
25
|
+
- "fastapi"
|
|
26
|
+
- "uvicorn"
|
|
27
|
+
- "pydantic*"
|
|
28
|
+
- "sqlalchemy"
|
|
29
|
+
- "aiosqlite"
|
|
30
|
+
|
|
31
|
+
- package-ecosystem: npm
|
|
32
|
+
directory: "/frontend"
|
|
33
|
+
schedule:
|
|
34
|
+
interval: weekly
|
|
35
|
+
day: monday
|
|
36
|
+
time: "06:00"
|
|
37
|
+
open-pull-requests-limit: 5
|
|
38
|
+
labels:
|
|
39
|
+
- dependencies
|
|
40
|
+
- frontend
|
|
41
|
+
ignore:
|
|
42
|
+
- dependency-name: "*"
|
|
43
|
+
update-types: ["version-update:semver-major"]
|
|
44
|
+
groups:
|
|
45
|
+
react:
|
|
46
|
+
patterns:
|
|
47
|
+
- "react"
|
|
48
|
+
- "react-dom"
|
|
49
|
+
- "react-router-dom"
|
|
50
|
+
- "@types/react*"
|
|
51
|
+
build-tools:
|
|
52
|
+
patterns:
|
|
53
|
+
- "vite"
|
|
54
|
+
- "@vitejs/*"
|
|
55
|
+
- "typescript"
|
|
56
|
+
- "tailwindcss"
|
|
57
|
+
- "postcss"
|
|
58
|
+
- "autoprefixer"
|
|
59
|
+
|
|
60
|
+
- package-ecosystem: github-actions
|
|
61
|
+
directory: "/"
|
|
62
|
+
schedule:
|
|
63
|
+
interval: weekly
|
|
64
|
+
day: monday
|
|
65
|
+
time: "06:00"
|
|
66
|
+
labels:
|
|
67
|
+
- dependencies
|
|
68
|
+
- ci
|
|
69
|
+
ignore:
|
|
70
|
+
- dependency-name: "*"
|
|
71
|
+
update-types: ["version-update:semver-major"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
backend:
|
|
2
|
+
- changed-files:
|
|
3
|
+
- any-glob-to-any-file: "frostwatch/**/*"
|
|
4
|
+
|
|
5
|
+
frontend:
|
|
6
|
+
- changed-files:
|
|
7
|
+
- any-glob-to-any-file: "frontend/src/**/*"
|
|
8
|
+
|
|
9
|
+
ci:
|
|
10
|
+
- changed-files:
|
|
11
|
+
- any-glob-to-any-file: ".github/workflows/**/*"
|
|
12
|
+
|
|
13
|
+
docs:
|
|
14
|
+
- changed-files:
|
|
15
|
+
- any-glob-to-any-file:
|
|
16
|
+
- "*.md"
|
|
17
|
+
- "docs/**/*"
|
|
18
|
+
|
|
19
|
+
docker:
|
|
20
|
+
- changed-files:
|
|
21
|
+
- any-glob-to-any-file:
|
|
22
|
+
- "Dockerfile"
|
|
23
|
+
- "docker-compose.yml"
|
|
24
|
+
|
|
25
|
+
dependencies:
|
|
26
|
+
- changed-files:
|
|
27
|
+
- any-glob-to-any-file:
|
|
28
|
+
- "pyproject.toml"
|
|
29
|
+
- "frontend/package.json"
|
|
30
|
+
- "frontend/package-lock.json"
|
|
31
|
+
|
|
32
|
+
security:
|
|
33
|
+
- changed-files:
|
|
34
|
+
- any-glob-to-any-file:
|
|
35
|
+
- ".github/workflows/security.yml"
|
|
36
|
+
- "SECURITY.md"
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
name: Lint & format (Python)
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.11"
|
|
23
|
+
|
|
24
|
+
- name: Install ruff
|
|
25
|
+
run: pip install ruff==0.4.10
|
|
26
|
+
|
|
27
|
+
- name: Check formatting
|
|
28
|
+
run: ruff format --check frostwatch/
|
|
29
|
+
|
|
30
|
+
- name: Lint
|
|
31
|
+
run: ruff check frostwatch/
|
|
32
|
+
|
|
33
|
+
typecheck:
|
|
34
|
+
name: Type check (Python)
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.11"
|
|
42
|
+
|
|
43
|
+
- name: Install package + mypy
|
|
44
|
+
run: |
|
|
45
|
+
pip install -e ".[dev]"
|
|
46
|
+
pip install mypy types-PyYAML types-aiofiles
|
|
47
|
+
|
|
48
|
+
- name: mypy
|
|
49
|
+
run: mypy frostwatch/ --ignore-missing-imports --no-strict-optional
|
|
50
|
+
|
|
51
|
+
test:
|
|
52
|
+
name: Unit tests (Python ${{ matrix.python-version }})
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
strategy:
|
|
55
|
+
matrix:
|
|
56
|
+
python-version: ["3.11", "3.13"]
|
|
57
|
+
steps:
|
|
58
|
+
- uses: actions/checkout@v4
|
|
59
|
+
|
|
60
|
+
- uses: actions/setup-python@v5
|
|
61
|
+
with:
|
|
62
|
+
python-version: ${{ matrix.python-version }}
|
|
63
|
+
|
|
64
|
+
- name: Install package + test deps
|
|
65
|
+
run: pip install -e ".[dev]"
|
|
66
|
+
|
|
67
|
+
- name: Run tests
|
|
68
|
+
run: pytest tests/unit/ -v --cov=frostwatch --cov-report=xml --cov-report=term-missing
|
|
69
|
+
|
|
70
|
+
- name: Upload coverage
|
|
71
|
+
uses: codecov/codecov-action@v4
|
|
72
|
+
if: matrix.python-version == '3.11'
|
|
73
|
+
with:
|
|
74
|
+
files: coverage.xml
|
|
75
|
+
fail_ci_if_error: false
|
|
76
|
+
|
|
77
|
+
frontend:
|
|
78
|
+
name: Frontend build & type check
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
|
|
83
|
+
- uses: actions/setup-node@v4
|
|
84
|
+
with:
|
|
85
|
+
node-version: "20"
|
|
86
|
+
cache: "npm"
|
|
87
|
+
cache-dependency-path: frontend/package-lock.json
|
|
88
|
+
|
|
89
|
+
- name: Install dependencies
|
|
90
|
+
run: npm ci
|
|
91
|
+
working-directory: frontend
|
|
92
|
+
|
|
93
|
+
- name: Type check + build
|
|
94
|
+
run: npm run build
|
|
95
|
+
working-directory: frontend
|
|
96
|
+
|
|
97
|
+
- name: Upload dist artifact
|
|
98
|
+
uses: actions/upload-artifact@v4
|
|
99
|
+
with:
|
|
100
|
+
name: frontend-dist
|
|
101
|
+
path: frontend/dist/
|
|
102
|
+
retention-days: 7
|
|
103
|
+
|
|
104
|
+
docker-build:
|
|
105
|
+
name: Docker build (smoke test)
|
|
106
|
+
runs-on: ubuntu-latest
|
|
107
|
+
needs: [lint, typecheck, test, frontend]
|
|
108
|
+
steps:
|
|
109
|
+
- uses: actions/checkout@v4
|
|
110
|
+
|
|
111
|
+
- name: Download frontend dist
|
|
112
|
+
uses: actions/download-artifact@v4
|
|
113
|
+
with:
|
|
114
|
+
name: frontend-dist
|
|
115
|
+
path: frontend/dist/
|
|
116
|
+
|
|
117
|
+
- name: Build Docker image
|
|
118
|
+
run: docker build -t frostwatch:ci .
|
|
119
|
+
|
|
120
|
+
- name: Smoke test — frostwatch version
|
|
121
|
+
run: docker run --rm frostwatch:ci frostwatch version
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
name: PR Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, edited, synchronize, reopened, labeled, unlabeled]
|
|
6
|
+
pull_request_target:
|
|
7
|
+
types: [opened]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
pull-requests: write
|
|
12
|
+
issues: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
pr-title:
|
|
16
|
+
name: Conventional commit title
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
if: github.event_name == 'pull_request'
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check PR title
|
|
21
|
+
uses: amannn/action-semantic-pull-request@v5
|
|
22
|
+
env:
|
|
23
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
24
|
+
with:
|
|
25
|
+
types: |
|
|
26
|
+
feat
|
|
27
|
+
fix
|
|
28
|
+
docs
|
|
29
|
+
style
|
|
30
|
+
refactor
|
|
31
|
+
test
|
|
32
|
+
chore
|
|
33
|
+
ci
|
|
34
|
+
perf
|
|
35
|
+
revert
|
|
36
|
+
build
|
|
37
|
+
requireScope: false
|
|
38
|
+
|
|
39
|
+
pr-description:
|
|
40
|
+
name: PR description not empty
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
if: github.event_name == 'pull_request'
|
|
43
|
+
steps:
|
|
44
|
+
- name: Validate description
|
|
45
|
+
uses: actions/github-script@v7
|
|
46
|
+
with:
|
|
47
|
+
script: |
|
|
48
|
+
const body = context.payload.pull_request.body || '';
|
|
49
|
+
const stripped = body
|
|
50
|
+
.replace(/<!--.*?-->/gs, '') // strip HTML comments (template hints)
|
|
51
|
+
.replace(/\[[ x]\]/g, '') // strip checkboxes
|
|
52
|
+
.trim();
|
|
53
|
+
if (stripped.length < 30) {
|
|
54
|
+
core.setFailed(
|
|
55
|
+
'PR description is too short. Please fill in the Summary and Changes sections of the PR template.'
|
|
56
|
+
);
|
|
57
|
+
} else {
|
|
58
|
+
core.info('PR description looks good ✓');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
size-label:
|
|
62
|
+
name: PR size label
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
if: github.event_name == 'pull_request'
|
|
65
|
+
steps:
|
|
66
|
+
- uses: codelytv/pr-size-labeler@v1
|
|
67
|
+
with:
|
|
68
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
69
|
+
xs_label: "size/XS"
|
|
70
|
+
xs_max_size: 9
|
|
71
|
+
s_label: "size/S"
|
|
72
|
+
s_max_size: 99
|
|
73
|
+
m_label: "size/M"
|
|
74
|
+
m_max_size: 499
|
|
75
|
+
l_label: "size/L"
|
|
76
|
+
l_max_size: 999
|
|
77
|
+
xl_label: "size/XL"
|
|
78
|
+
fail_if_xl: false
|
|
79
|
+
message_if_xl: |
|
|
80
|
+
This PR is very large. Consider splitting it into smaller PRs for easier review.
|
|
81
|
+
|
|
82
|
+
labeler:
|
|
83
|
+
name: Auto-label by changed paths
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
if: github.event_name == 'pull_request'
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/labeler@v5
|
|
88
|
+
with:
|
|
89
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
90
|
+
configuration-path: .github/labeler.yml
|
|
91
|
+
sync-labels: true
|
|
92
|
+
|
|
93
|
+
check-changelog:
|
|
94
|
+
name: Remind about CHANGELOG
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
if: "github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip-changelog')"
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v4
|
|
99
|
+
with:
|
|
100
|
+
fetch-depth: 0
|
|
101
|
+
|
|
102
|
+
- name: Check if CHANGELOG.md was updated
|
|
103
|
+
run: |
|
|
104
|
+
if git diff --name-only origin/main...HEAD | grep -q "CHANGELOG.md"; then
|
|
105
|
+
echo "✅ CHANGELOG.md updated"
|
|
106
|
+
else
|
|
107
|
+
echo "::warning::CHANGELOG.md was not updated. Add a 'skip-changelog' label if this PR doesn't need a changelog entry."
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
welcome-contributor:
|
|
111
|
+
name: Welcome first-time contributor
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
if: github.event_name == 'pull_request_target' && github.event.action == 'opened'
|
|
114
|
+
steps:
|
|
115
|
+
- name: Check contribution history
|
|
116
|
+
id: check
|
|
117
|
+
uses: actions/github-script@v7
|
|
118
|
+
with:
|
|
119
|
+
script: |
|
|
120
|
+
const { data: prs } = await github.rest.pulls.list({
|
|
121
|
+
owner: context.repo.owner,
|
|
122
|
+
repo: context.repo.repo,
|
|
123
|
+
state: 'all',
|
|
124
|
+
per_page: 10,
|
|
125
|
+
});
|
|
126
|
+
const author = context.payload.pull_request.user.login;
|
|
127
|
+
const previous = prs.filter(
|
|
128
|
+
pr => pr.user.login === author && pr.number !== context.payload.pull_request.number
|
|
129
|
+
);
|
|
130
|
+
return previous.length === 0;
|
|
131
|
+
result-encoding: string
|
|
132
|
+
|
|
133
|
+
- name: Post welcome comment
|
|
134
|
+
if: steps.check.outputs.result == 'true'
|
|
135
|
+
uses: actions/github-script@v7
|
|
136
|
+
with:
|
|
137
|
+
script: |
|
|
138
|
+
const author = context.payload.pull_request.user.login;
|
|
139
|
+
await github.rest.issues.createComment({
|
|
140
|
+
owner: context.repo.owner,
|
|
141
|
+
repo: context.repo.repo,
|
|
142
|
+
issue_number: context.payload.pull_request.number,
|
|
143
|
+
body: `👋 Welcome to FrostWatch, @${author}! Thanks for opening your first PR.
|
|
144
|
+
|
|
145
|
+
Here's what happens next:
|
|
146
|
+
1. **CI runs automatically** — lint, type check, unit tests (Python 3.11 + 3.13), frontend build, and Docker smoke test must all pass.
|
|
147
|
+
2. **A maintainer will review** your changes. Please make sure the PR template is filled in.
|
|
148
|
+
3. **Need help?** Check [CONTRIBUTING.md](../blob/main/CONTRIBUTING.md) or open a [Discussion](../../discussions).
|
|
149
|
+
|
|
150
|
+
Quick local checks before pushing:
|
|
151
|
+
\`\`\`bash
|
|
152
|
+
# Backend
|
|
153
|
+
ruff check frostwatch/ && mypy frostwatch/
|
|
154
|
+
pytest tests/unit/
|
|
155
|
+
|
|
156
|
+
# Frontend
|
|
157
|
+
cd frontend && npm run build
|
|
158
|
+
\`\`\`
|
|
159
|
+
`,
|
|
160
|
+
});
|