filedge 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.
- filedge-0.1.0/.coverage +0 -0
- filedge-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +66 -0
- filedge-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- filedge-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +32 -0
- filedge-0.1.0/.github/dependabot.yml +25 -0
- filedge-0.1.0/.github/pull_request_template.md +25 -0
- filedge-0.1.0/.github/workflows/bigquery-integration.yml +35 -0
- filedge-0.1.0/.github/workflows/ci.yml +77 -0
- filedge-0.1.0/.github/workflows/docs.yml +44 -0
- filedge-0.1.0/.github/workflows/release.yml +50 -0
- filedge-0.1.0/.gitignore +10 -0
- filedge-0.1.0/AGENTS.md +17 -0
- filedge-0.1.0/CLAUDE.md +17 -0
- filedge-0.1.0/CONTEXT.md +145 -0
- filedge-0.1.0/CONTRIBUTING.md +101 -0
- filedge-0.1.0/LICENSE +201 -0
- filedge-0.1.0/PKG-INFO +40 -0
- filedge-0.1.0/README.md +127 -0
- filedge-0.1.0/SECURITY.md +47 -0
- filedge-0.1.0/docs/PRD.md +139 -0
- filedge-0.1.0/docs/adr/0001-single-transaction-commit.md +3 -0
- filedge-0.1.0/docs/adr/0002-content-hash-as-idempotency-key.md +3 -0
- filedge-0.1.0/docs/adr/0003-strict-mode-validation.md +3 -0
- filedge-0.1.0/docs/adr/0004-audit-connector-split.md +38 -0
- filedge-0.1.0/docs/adr/0005-sftp-out-of-scope.md +22 -0
- filedge-0.1.0/docs/adr/0006-api-sources-fetched-to-files.md +16 -0
- filedge-0.1.0/docs/adr/0007-queue-source-ingestion-model.md +16 -0
- filedge-0.1.0/docs/adr/0008-schema-inference-confidence-tiers.md +7 -0
- filedge-0.1.0/docs/adr/0009-warehouse-cdc-applied-file-markers.md +34 -0
- filedge-0.1.0/docs/agents/domain.md +44 -0
- filedge-0.1.0/docs/agents/issue-tracker.md +22 -0
- filedge-0.1.0/docs/agents/triage-labels.md +15 -0
- filedge-0.1.0/docs/architecture/decisions.md +97 -0
- filedge-0.1.0/docs/architecture/index.md +76 -0
- filedge-0.1.0/docs/getting-started.md +196 -0
- filedge-0.1.0/docs/guides/api-sources.md +190 -0
- filedge-0.1.0/docs/guides/cdc-files.md +131 -0
- filedge-0.1.0/docs/guides/compact.md +106 -0
- filedge-0.1.0/docs/guides/crash-retry.md +124 -0
- filedge-0.1.0/docs/guides/healthcheck.md +71 -0
- filedge-0.1.0/docs/guides/inspect.md +138 -0
- filedge-0.1.0/docs/guides/observability.md +109 -0
- filedge-0.1.0/docs/guides/preview.md +106 -0
- filedge-0.1.0/docs/guides/queue-sources.md +140 -0
- filedge-0.1.0/docs/guides/requeue.md +123 -0
- filedge-0.1.0/docs/guides/run.md +229 -0
- filedge-0.1.0/docs/guides/scale.md +223 -0
- filedge-0.1.0/docs/guides/validate.md +101 -0
- filedge-0.1.0/docs/index.md +63 -0
- filedge-0.1.0/docs/reference/cli.md +207 -0
- filedge-0.1.0/docs/reference/column-types.md +43 -0
- filedge-0.1.0/docs/reference/connectors.md +158 -0
- filedge-0.1.0/docs/reference/pipeline-yaml.md +180 -0
- filedge-0.1.0/docs/release-checklist.md +102 -0
- filedge-0.1.0/example/pipeline.yaml +26 -0
- filedge-0.1.0/filedge/__init__.py +0 -0
- filedge-0.1.0/filedge/cdc.py +49 -0
- filedge-0.1.0/filedge/cli.py +526 -0
- filedge-0.1.0/filedge/column_types.py +79 -0
- filedge-0.1.0/filedge/compactor.py +158 -0
- filedge-0.1.0/filedge/config.py +102 -0
- filedge-0.1.0/filedge/connectors/__init__.py +110 -0
- filedge-0.1.0/filedge/connectors/bigquery.py +309 -0
- filedge-0.1.0/filedge/connectors/databricks.py +527 -0
- filedge-0.1.0/filedge/connectors/duckdb.py +181 -0
- filedge-0.1.0/filedge/connectors/postgres.py +163 -0
- filedge-0.1.0/filedge/connectors/sqlite.py +149 -0
- filedge-0.1.0/filedge/db.py +297 -0
- filedge-0.1.0/filedge/filesystem.py +73 -0
- filedge-0.1.0/filedge/hashing.py +11 -0
- filedge-0.1.0/filedge/health.py +104 -0
- filedge-0.1.0/filedge/inferrer.py +135 -0
- filedge-0.1.0/filedge/inspect_formatter.py +43 -0
- filedge-0.1.0/filedge/loader.py +66 -0
- filedge-0.1.0/filedge/log.py +84 -0
- filedge-0.1.0/filedge/parser.py +69 -0
- filedge-0.1.0/filedge/pipeline.py +151 -0
- filedge-0.1.0/filedge/preview_formatter.py +63 -0
- filedge-0.1.0/filedge/progress.py +232 -0
- filedge-0.1.0/filedge/schema.py +84 -0
- filedge-0.1.0/filedge/tracing.py +131 -0
- filedge-0.1.0/filedge/transform.py +31 -0
- filedge-0.1.0/filedge/validate_formatter.py +33 -0
- filedge-0.1.0/filedge/validator.py +51 -0
- filedge-0.1.0/mkdocs.yml +66 -0
- filedge-0.1.0/pyproject.toml +44 -0
- filedge-0.1.0/tests/__init__.py +0 -0
- filedge-0.1.0/tests/conftest.py +10 -0
- filedge-0.1.0/tests/fixtures/sample.csv +5 -0
- filedge-0.1.0/tests/fixtures/sample.ndjson +3 -0
- filedge-0.1.0/tests/test_cli.py +419 -0
- filedge-0.1.0/tests/test_cli_inspect.py +111 -0
- filedge-0.1.0/tests/test_cli_inspect_remote.py +96 -0
- filedge-0.1.0/tests/test_cli_parquet.py +66 -0
- filedge-0.1.0/tests/test_cli_preview.py +110 -0
- filedge-0.1.0/tests/test_cli_validate.py +147 -0
- filedge-0.1.0/tests/test_compactor.py +234 -0
- filedge-0.1.0/tests/test_config.py +197 -0
- filedge-0.1.0/tests/test_connector_bigquery.py +237 -0
- filedge-0.1.0/tests/test_connector_bigquery_unit.py +214 -0
- filedge-0.1.0/tests/test_connector_databricks.py +330 -0
- filedge-0.1.0/tests/test_connector_databricks_integration.py +231 -0
- filedge-0.1.0/tests/test_connector_duckdb.py +382 -0
- filedge-0.1.0/tests/test_connector_health.py +157 -0
- filedge-0.1.0/tests/test_connector_postgres.py +265 -0
- filedge-0.1.0/tests/test_connector_sqlite.py +284 -0
- filedge-0.1.0/tests/test_connectors.py +58 -0
- filedge-0.1.0/tests/test_crash_retry.py +127 -0
- filedge-0.1.0/tests/test_db.py +259 -0
- filedge-0.1.0/tests/test_encoding.py +76 -0
- filedge-0.1.0/tests/test_filesystem.py +113 -0
- filedge-0.1.0/tests/test_hashing.py +31 -0
- filedge-0.1.0/tests/test_health.py +310 -0
- filedge-0.1.0/tests/test_inferrer.py +161 -0
- filedge-0.1.0/tests/test_inspect_formatter.py +75 -0
- filedge-0.1.0/tests/test_loader.py +213 -0
- filedge-0.1.0/tests/test_log.py +89 -0
- filedge-0.1.0/tests/test_otel_logs.py +134 -0
- filedge-0.1.0/tests/test_parquet_inferrer.py +89 -0
- filedge-0.1.0/tests/test_parquet_parser.py +72 -0
- filedge-0.1.0/tests/test_parser.py +57 -0
- filedge-0.1.0/tests/test_pipeline.py +248 -0
- filedge-0.1.0/tests/test_pipeline_progress.py +134 -0
- filedge-0.1.0/tests/test_preview_formatter.py +86 -0
- filedge-0.1.0/tests/test_schema.py +60 -0
- filedge-0.1.0/tests/test_tracing.py +225 -0
- filedge-0.1.0/tests/test_tracing_optional_imports.py +164 -0
- filedge-0.1.0/tests/test_transform.py +100 -0
- filedge-0.1.0/tests/test_validate_formatter.py +76 -0
- filedge-0.1.0/tests/test_validator.py +89 -0
- filedge-0.1.0/uv.lock +2610 -0
filedge-0.1.0/.coverage
ADDED
|
Binary file
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: A reproducible bug in filedge
|
|
3
|
+
title: "[bug]: "
|
|
4
|
+
labels: ["bug", "needs-triage"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for taking the time to file a bug. The more reproducible the
|
|
10
|
+
report, the faster it can be fixed.
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: what-happened
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happened?
|
|
16
|
+
description: What did you expect, and what actually occurred?
|
|
17
|
+
placeholder: |
|
|
18
|
+
Expected: ...
|
|
19
|
+
Actual: ...
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: reproduce
|
|
25
|
+
attributes:
|
|
26
|
+
label: Steps to reproduce
|
|
27
|
+
description: Minimal `pipeline.yaml`, sample input file, and CLI invocation.
|
|
28
|
+
render: shell
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: input
|
|
33
|
+
id: version
|
|
34
|
+
attributes:
|
|
35
|
+
label: Filedge version / commit SHA
|
|
36
|
+
placeholder: "0.1.0 or abc1234"
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
|
|
40
|
+
- type: dropdown
|
|
41
|
+
id: connector
|
|
42
|
+
attributes:
|
|
43
|
+
label: Connector
|
|
44
|
+
options:
|
|
45
|
+
- sqlite
|
|
46
|
+
- postgres
|
|
47
|
+
- bigquery
|
|
48
|
+
- databricks
|
|
49
|
+
- other / not applicable
|
|
50
|
+
validations:
|
|
51
|
+
required: true
|
|
52
|
+
|
|
53
|
+
- type: input
|
|
54
|
+
id: python
|
|
55
|
+
attributes:
|
|
56
|
+
label: Python version
|
|
57
|
+
placeholder: "3.13"
|
|
58
|
+
validations:
|
|
59
|
+
required: true
|
|
60
|
+
|
|
61
|
+
- type: textarea
|
|
62
|
+
id: logs
|
|
63
|
+
attributes:
|
|
64
|
+
label: Logs / traceback
|
|
65
|
+
description: Full traceback if there was one. Audit DB state (`filedge status --json`) helps too.
|
|
66
|
+
render: shell
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new capability or enhancement
|
|
3
|
+
title: "[feat]: "
|
|
4
|
+
labels: ["enhancement", "needs-triage"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: problem
|
|
8
|
+
attributes:
|
|
9
|
+
label: What problem would this solve?
|
|
10
|
+
description: Describe the use case or pain point. Avoid jumping to a solution.
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: proposal
|
|
16
|
+
attributes:
|
|
17
|
+
label: Proposed change
|
|
18
|
+
description: Optional. What would the API / CLI / config look like?
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: alternatives
|
|
22
|
+
attributes:
|
|
23
|
+
label: Alternatives considered
|
|
24
|
+
description: Workarounds you have tried or other approaches you considered.
|
|
25
|
+
|
|
26
|
+
- type: checkboxes
|
|
27
|
+
id: scope
|
|
28
|
+
attributes:
|
|
29
|
+
label: Scope
|
|
30
|
+
options:
|
|
31
|
+
- label: This is a breaking change to config or CLI surface
|
|
32
|
+
- label: I would be willing to send a PR for this
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
day: "monday"
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
labels:
|
|
10
|
+
- "dependencies"
|
|
11
|
+
groups:
|
|
12
|
+
python-minor-and-patch:
|
|
13
|
+
update-types:
|
|
14
|
+
- "minor"
|
|
15
|
+
- "patch"
|
|
16
|
+
|
|
17
|
+
- package-ecosystem: "github-actions"
|
|
18
|
+
directory: "/"
|
|
19
|
+
schedule:
|
|
20
|
+
interval: "weekly"
|
|
21
|
+
day: "monday"
|
|
22
|
+
open-pull-requests-limit: 5
|
|
23
|
+
labels:
|
|
24
|
+
- "dependencies"
|
|
25
|
+
- "github-actions"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR do, and why? Link the issue it closes. -->
|
|
4
|
+
|
|
5
|
+
Closes #
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
<!-- High-level bullets. The diff covers the detail. -->
|
|
10
|
+
|
|
11
|
+
-
|
|
12
|
+
-
|
|
13
|
+
|
|
14
|
+
## Test plan
|
|
15
|
+
|
|
16
|
+
<!-- How did you verify this works? -->
|
|
17
|
+
|
|
18
|
+
- [ ] `uv run ruff check .` passes
|
|
19
|
+
- [ ] `uv run pytest --cov=filedge` passes
|
|
20
|
+
- [ ] New tests added for new behaviour (or n/a)
|
|
21
|
+
- [ ] Docs / README / ADR updated (or n/a)
|
|
22
|
+
|
|
23
|
+
## Notes for reviewer
|
|
24
|
+
|
|
25
|
+
<!-- Anything reviewers should pay particular attention to: tricky bits, follow-ups, alternatives considered. -->
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: BigQuery Integration
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
bigquery-integration:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
|
|
18
|
+
- uses: google-github-actions/auth@v3
|
|
19
|
+
with:
|
|
20
|
+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
|
21
|
+
service_account: ${{ secrets.GCP_BIGQUERY_TEST_SERVICE_ACCOUNT }}
|
|
22
|
+
|
|
23
|
+
- uses: astral-sh/setup-uv@v7
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.13"
|
|
26
|
+
enable-caching: true
|
|
27
|
+
|
|
28
|
+
- run: uv sync --extra dev --extra bigquery
|
|
29
|
+
|
|
30
|
+
- name: Test BigQuery connector
|
|
31
|
+
env:
|
|
32
|
+
FILEDGE_BIGQUERY_INTEGRATION: "1"
|
|
33
|
+
BIGQUERY_PROJECT: ${{ vars.BIGQUERY_PROJECT }}
|
|
34
|
+
BIGQUERY_DATASET: ${{ vars.BIGQUERY_DATASET }}
|
|
35
|
+
run: uv run pytest tests/test_connector_bigquery.py
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
dependency-resolution:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
|
|
15
|
+
- uses: astral-sh/setup-uv@v7
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
enable-caching: true
|
|
19
|
+
|
|
20
|
+
- run: uv lock --check
|
|
21
|
+
- run: uv sync --extra s3 --extra gcs
|
|
22
|
+
|
|
23
|
+
lint:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v6
|
|
27
|
+
|
|
28
|
+
- uses: astral-sh/setup-uv@v7
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.13"
|
|
31
|
+
enable-caching: true
|
|
32
|
+
|
|
33
|
+
- run: uv sync --extra dev
|
|
34
|
+
- run: uv run ruff check .
|
|
35
|
+
|
|
36
|
+
test:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
strategy:
|
|
39
|
+
matrix:
|
|
40
|
+
python-version: ["3.11", "3.13"]
|
|
41
|
+
|
|
42
|
+
services:
|
|
43
|
+
postgres:
|
|
44
|
+
image: postgres:16
|
|
45
|
+
env:
|
|
46
|
+
POSTGRES_PASSWORD: etl
|
|
47
|
+
POSTGRES_DB: etldb
|
|
48
|
+
ports:
|
|
49
|
+
- 5432:5432
|
|
50
|
+
options: >-
|
|
51
|
+
--health-cmd pg_isready
|
|
52
|
+
--health-interval 10s
|
|
53
|
+
--health-timeout 5s
|
|
54
|
+
--health-retries 5
|
|
55
|
+
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v6
|
|
58
|
+
|
|
59
|
+
- uses: astral-sh/setup-uv@v7
|
|
60
|
+
with:
|
|
61
|
+
python-version: ${{ matrix.python-version }}
|
|
62
|
+
enable-caching: true
|
|
63
|
+
|
|
64
|
+
- run: uv sync --extra dev --extra postgres --extra duckdb
|
|
65
|
+
|
|
66
|
+
- name: Test
|
|
67
|
+
env:
|
|
68
|
+
DATABASE_URL: postgresql://postgres:etl@localhost/etldb
|
|
69
|
+
run: uv run pytest --cov=filedge --cov-report=term-missing --cov-report=xml
|
|
70
|
+
|
|
71
|
+
- name: Upload coverage to Codecov
|
|
72
|
+
if: matrix.python-version == '3.13'
|
|
73
|
+
uses: codecov/codecov-action@v6
|
|
74
|
+
with:
|
|
75
|
+
files: ./coverage.xml
|
|
76
|
+
fail_ci_if_error: false
|
|
77
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
pages: write
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: "pages"
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
|
|
24
|
+
- uses: astral-sh/setup-uv@v7
|
|
25
|
+
|
|
26
|
+
- name: Install docs dependencies
|
|
27
|
+
run: uv sync --extra docs
|
|
28
|
+
|
|
29
|
+
- name: Build site
|
|
30
|
+
run: uv run mkdocs build --strict
|
|
31
|
+
|
|
32
|
+
- uses: actions/upload-pages-artifact@v5
|
|
33
|
+
with:
|
|
34
|
+
path: site/
|
|
35
|
+
|
|
36
|
+
deploy:
|
|
37
|
+
environment:
|
|
38
|
+
name: github-pages
|
|
39
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
needs: build
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/deploy-pages@v5
|
|
44
|
+
id: deployment
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
|
|
17
|
+
- uses: astral-sh/setup-uv@v7
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.13"
|
|
20
|
+
enable-caching: true
|
|
21
|
+
|
|
22
|
+
- run: uv sync --extra dev
|
|
23
|
+
- run: uv run ruff check .
|
|
24
|
+
- run: uv run pytest --cov=filedge
|
|
25
|
+
|
|
26
|
+
- run: uv build
|
|
27
|
+
|
|
28
|
+
- uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: dist
|
|
31
|
+
path: dist/
|
|
32
|
+
|
|
33
|
+
publish:
|
|
34
|
+
needs: build
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
environment: pypi
|
|
37
|
+
permissions:
|
|
38
|
+
id-token: write # required for OIDC trusted publishing
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/download-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: dist
|
|
44
|
+
path: dist/
|
|
45
|
+
|
|
46
|
+
- uses: astral-sh/setup-uv@v7
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.13"
|
|
49
|
+
|
|
50
|
+
- run: uv publish
|
filedge-0.1.0/.gitignore
ADDED
filedge-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Filedge
|
|
2
|
+
|
|
3
|
+
A batch ETL system designed for reliable file ingestion.
|
|
4
|
+
|
|
5
|
+
## Agent skills
|
|
6
|
+
|
|
7
|
+
### Issue tracker
|
|
8
|
+
|
|
9
|
+
Issues live in GitHub Issues for this repo. See `docs/agents/issue-tracker.md`.
|
|
10
|
+
|
|
11
|
+
### Triage labels
|
|
12
|
+
|
|
13
|
+
Default label vocabulary (needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix). See `docs/agents/triage-labels.md`.
|
|
14
|
+
|
|
15
|
+
### Domain docs
|
|
16
|
+
|
|
17
|
+
Single-context repo — one `CONTEXT.md` at root and `docs/adr/`. See `docs/agents/domain.md`.
|
filedge-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Filedge
|
|
2
|
+
|
|
3
|
+
A batch ETL system designed for reliable file ingestion.
|
|
4
|
+
|
|
5
|
+
## Agent skills
|
|
6
|
+
|
|
7
|
+
### Issue tracker
|
|
8
|
+
|
|
9
|
+
Issues live in GitHub Issues for this repo. See `docs/agents/issue-tracker.md`.
|
|
10
|
+
|
|
11
|
+
### Triage labels
|
|
12
|
+
|
|
13
|
+
Default label vocabulary (needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix). See `docs/agents/triage-labels.md`.
|
|
14
|
+
|
|
15
|
+
### Domain docs
|
|
16
|
+
|
|
17
|
+
Single-context repo — one `CONTEXT.md` at root and `docs/adr/`. See `docs/agents/domain.md`.
|
filedge-0.1.0/CONTEXT.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Context: Filedge
|
|
2
|
+
|
|
3
|
+
A batch ETL system designed for reliable data ingestion from files, APIs, and message queues, targeting the failure modes that Airflow + Spark + data warehouse stacks handle poorly.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Glossary
|
|
8
|
+
|
|
9
|
+
### File
|
|
10
|
+
The atomic unit of work. A single raw input file must either be fully loaded into the destination or not at all — partial states are not permitted.
|
|
11
|
+
|
|
12
|
+
### Content Hash
|
|
13
|
+
The primary idempotency key for a File. Computed as SHA-256 of the file's bytes. Two files with the same Content Hash are treated as identical data regardless of filename. Stored alongside the filename in the audit record.
|
|
14
|
+
|
|
15
|
+
### Partial Load Corruption
|
|
16
|
+
The #1 failure mode this system is designed to prevent. Occurs when a pipeline job fails mid-run and leaves the destination in a half-written state, causing subsequent retries to produce duplicates or skip records.
|
|
17
|
+
|
|
18
|
+
### Commit
|
|
19
|
+
The act of successfully applying one File to the Destination and then marking that File `COMMITTED` in the Audit DB. Because the Audit DB and Destination may be separate systems, retry safety comes from Connector-level idempotency keyed by Content Hash rather than one shared transaction.
|
|
20
|
+
|
|
21
|
+
### Run
|
|
22
|
+
A single execution of `filedge run` — a short-lived process that scans the Watched Directory, enqueues new Files as PENDING, processes them through the pipeline, and exits. Triggered by an external scheduler (cron, Airflow, Kubernetes CronJob). Stale PROCESSING locks older than a configured timeout are reclaimed at the start of each Run.
|
|
23
|
+
|
|
24
|
+
### Streaming Load
|
|
25
|
+
Files are processed in row batches (configurable size, default 1,000) rather than loaded entirely into memory. The Connector writes the File as one idempotent unit and commits only when the full File is processed, keeping memory bounded by `batch_size`.
|
|
26
|
+
|
|
27
|
+
### Append-Only Load
|
|
28
|
+
The default Write Mode (`write_mode: append`): records from each File are inserted into the destination table without replacing prior records. The ETL layer does not resolve whether a re-dropped file is a correction or a supplement — that is downstream responsibility, resolvable via provenance columns. Two Files with the same filename but different content hashes produce two distinct sets of rows in the destination. See also: Write Mode.
|
|
29
|
+
|
|
30
|
+
### Column Tolerance
|
|
31
|
+
Extra columns in a source file (not declared in Pipeline Config) are silently ignored. Missing columns declared as required in Pipeline Config cause the File to fail in Strict Mode. This asymmetry makes the pipeline tolerant of upstream additions while strict about data contract violations.
|
|
32
|
+
|
|
33
|
+
### Column Type
|
|
34
|
+
The executable meaning of a Pipeline Config column's `type:` value. Supported values are `string`, `integer`, `float`, `date`, `timestamp`, and `boolean`. `date` means ISO `YYYY-MM-DD`; Schema Inference must not suggest `date` for non-ISO date-like values that Transform cannot load.
|
|
35
|
+
|
|
36
|
+
### Table Initialization
|
|
37
|
+
On first Run against a new destination table, the system creates the table from the Pipeline Config schema (including provenance columns). After the table exists, any mismatch between the YAML and the live table causes the Run to fail loudly with a clear diff — no auto-migration. Schema changes require explicit operator action.
|
|
38
|
+
|
|
39
|
+
### Runtime
|
|
40
|
+
Python. The implementation language for the ingestion system, CLI, and all pipeline components.
|
|
41
|
+
|
|
42
|
+
### Operator CLI
|
|
43
|
+
A command-line interface for system observation and control. `filedge status` prints file counts by state, recent failures, and retry counts. Supports `--json` for machine-readable output. `filedge inspect <file>` runs Schema Inference on a file and prints a suggested `columns:` block. The stable interface over audit DB queries — future web UI would use the same backing queries.
|
|
44
|
+
|
|
45
|
+
### Schema Inference
|
|
46
|
+
The process of sampling the first N rows of a File (default 1,000, configurable via `--sample-rows`) and producing a suggested `columns:` block ready to paste into a Pipeline Config, alongside a human-readable summary. Each inferred column carries a Confidence Tier. Invoked via `filedge inspect <file>`. Format is auto-detected from file extension with a `--format` override. The YAML block goes to stdout; the summary goes to stderr, keeping them composable with shell redirection. NDJSON nested objects are surfaced as top-level `string` columns with a warning listing the nested keys — the pipeline has no flattening Transform, so suggesting dot-notation paths would produce a config that cannot be executed.
|
|
47
|
+
_Avoid_: schema detection, type inference, column discovery.
|
|
48
|
+
|
|
49
|
+
### Confidence Tier
|
|
50
|
+
An annotation attached to each column in Schema Inference output, expressing how strongly the evidence supports the inferred type and `required:` value. Three tiers: **high** (all sampled values parse cleanly, no nulls); **low** (most values parse but exceptions found — null count or unparseable values shown); **ambiguous** (evidence is genuinely conflicting — e.g. two date formats detected, or values that could be boolean or integer). Operators are expected to review low and ambiguous columns before committing the config to production.
|
|
51
|
+
_Avoid_: confidence score, inference quality, certainty level.
|
|
52
|
+
|
|
53
|
+
### Pipeline Config
|
|
54
|
+
A `pipeline.yaml` file that declares how a single ingestion pipeline behaves. Contains the file format, column mappings (source name → destination name + type), destination table name, connector settings, write mode, and retry cap. The operator interface for configuring ingestion — no code changes required for schema mapping updates.
|
|
55
|
+
|
|
56
|
+
### Audit Record
|
|
57
|
+
Two-level audit: (1) file-level — captures filename, content hash, state, attempt count, timestamps, and worker identity; (2) row-level provenance — every destination row carries `_source_file_hash` and `_ingested_at` columns linking it back to the File that produced or last changed the current row. Row-level provenance is non-negotiable: it is the basis for data lineage, debugging, and compliance.
|
|
58
|
+
|
|
59
|
+
### Audit DB
|
|
60
|
+
The relational database (SQLite for development, PostgreSQL for production) that holds the file-level audit records and drives the state machine (PENDING → PROCESSING → COMMITTED/FAILED). This is the control plane — it is always a SQL database with full transaction support, separate from the Destination.
|
|
61
|
+
|
|
62
|
+
### Connector
|
|
63
|
+
A pluggable adapter that owns all interactions with a specific Destination backend: creating or validating the destination table, writing rows, and enforcing write-mode semantics. The Connector is the only component that knows about the Destination's SDK, DDL dialect, and bulk-load API. Adding a new Destination means writing a new Connector — no changes to the pipeline or audit logic. Built-in Connectors: `sqlite`, `postgres`, `bigquery`, `databricks`, `duckdb`.
|
|
64
|
+
|
|
65
|
+
### BigQuery Connector
|
|
66
|
+
A Connector that writes rows to a BigQuery table via NDJSON staging and a bulk load job. Idempotency in append mode is achieved by encoding the destination table and `file_hash` in the BigQuery job ID: if a job with the same ID already exists and succeeded, the retry is a no-op. **Known limitation**: BigQuery only retains job metadata for 7 days. A retry of the same file more than 7 days after the original ingestion will submit a new job and produce duplicate rows. For pipelines where files may be re-ingested after this window, use `write_mode: truncate` or implement a pre-load DML DELETE.
|
|
67
|
+
|
|
68
|
+
### DuckDB Connector
|
|
69
|
+
A Connector that writes rows to a `.duckdb` file on disk. Targeted at local analytics and lightweight deployments where a full OLAP warehouse (BigQuery, Databricks) is overkill. DuckDB is file-based and supports only one writer at a time — the Connector fails fast with a clear error if the file is locked by another process rather than retrying. DuckDB is a destination only; the audit DB always remains SQLite or PostgreSQL. Rows are written via standard batched `executemany`; bulk Parquet loading is a future optimization.
|
|
70
|
+
|
|
71
|
+
### Destination
|
|
72
|
+
The system where ingested rows land. Decoupled from the Audit DB — each has its own connection and transaction scope. Because rows and the audit COMMITTED marker can no longer be written in a single transaction, the Connector is responsible for making `write_rows` idempotent per `file_hash`, so retries produce the same destination state as a first write.
|
|
73
|
+
|
|
74
|
+
### Write Mode
|
|
75
|
+
The strategy a Connector uses when writing a File's rows to the Destination table. Declared as `write_mode` in `pipeline.yaml`. Supported modes: `append` (default) — rows are added alongside prior records; `truncate` — the table is wiped then replaced with this File's rows; `cdc` — a CDC File is applied as SCD Type 1 changes by business key. Write Modes must preserve retry safety for a File identified by Content Hash.
|
|
76
|
+
|
|
77
|
+
### CDC File
|
|
78
|
+
A File containing change data capture records that describe inserts, updates, and deletes from an upstream system. A CDC File is still a File: it is complete before it reaches the Watched Directory, identified by Content Hash, processed under Strict Mode, and visible in the Audit DB. Filedge applies CDC Files as SCD Type 1 current-state changes; when multiple changes for the same business key appear in one File, the configured sequence column identifies the final change. Ties for the same key and sequence are invalid because row order is not a portable contract. SCD Type 2 history is not part of this term.
|
|
79
|
+
_Avoid_: CDC source, replication stream.
|
|
80
|
+
|
|
81
|
+
### CDC File Order
|
|
82
|
+
The order in which CDC Files are applied when more than one File changes the same business key. Filedge processes Files in sorted path order during a Run, so upstream materializers must name or partition CDC Files so that sorted path order matches the intended change order. Filedge does not infer cross-File ordering from row-level sequence values in the current SCD Type 1 model.
|
|
83
|
+
_Avoid_: CDC checkpoint, global sequence.
|
|
84
|
+
|
|
85
|
+
### Applied File Marker
|
|
86
|
+
A Destination-side record that a Connector writes after successfully applying a File whose retry safety cannot rely on row-level `_source_file_hash` alone. Used for CDC Files in warehouse Destinations where replaying the same File would otherwise re-apply business-key mutations. Complements the Audit DB; it does not replace the Audit Record.
|
|
87
|
+
_Avoid_: checkpoint, CDC ledger.
|
|
88
|
+
|
|
89
|
+
### Connector Registry
|
|
90
|
+
The internal mapping from a `connector.type` string (e.g. `bigquery`) to a Connector implementation class. Resolved lazily at instantiation time so that missing optional SDK dependencies surface as a clear error only when the Connector is actually used. Declared in `pipeline.yaml` under a `connector:` block; secrets (API tokens, service account credentials) come from environment variables, never from YAML.
|
|
91
|
+
|
|
92
|
+
### Retry
|
|
93
|
+
Automatic re-attempt of a FAILED File with exponential backoff, up to a configured max attempt count (default: 3). After the cap is reached, the File enters terminal FAILED state requiring explicit human re-queue (resetting state to PENDING). Prevents bad files from burning retries indefinitely.
|
|
94
|
+
|
|
95
|
+
### Strict Mode
|
|
96
|
+
The validation policy for a File load: if any row fails schema validation, the entire File fails — no records are committed. This preserves the ability to reason about completeness. Lenient partial commits are not supported; a dead-letter quarantine is a future addition.
|
|
97
|
+
|
|
98
|
+
### Transform
|
|
99
|
+
A declarative, configuration-driven step that maps source column names to destination column names and coerces types (e.g. string → integer, ISO string → timestamp). Rejects rows that don't conform to the declared schema. No business logic — that belongs in the application layer consuming the destination.
|
|
100
|
+
|
|
101
|
+
### Compaction
|
|
102
|
+
A pre-processing step that merges many small Files in a source prefix into fewer, larger NDJSON files in a separate output prefix before ingestion. Solves the small-files problem common with event streams and cloud object stores — reducing object-store listing cost and enabling bulk loads into cloud warehouses. Invoked via `filedge compact` as a separate CLI command, scheduled before `filedge run`. Compaction reads via fsspec (no extra dependencies), groups files by count (`--max-files`), writes NDJSON with optional gzip compression (`--compress`), and names output files by timestamp and batch index. Originals in the source prefix are never modified. The output prefix becomes the Watched Directory for the subsequent `filedge run`.
|
|
103
|
+
|
|
104
|
+
### Parser
|
|
105
|
+
A pluggable component that takes a File path and yields rows. Implementations exist for CSV and newline-delimited JSON. Format is detected by file extension or per-directory configuration. Adding new formats (Parquet, Avro) is a new Parser implementation, not a system redesign.
|
|
106
|
+
|
|
107
|
+
### Watched Directory
|
|
108
|
+
The landing zone polled on a schedule to discover new Files. Accepts a local path or a cloud URI (`gs://`, `s3://`). The system scans the location on every Run, computes content hashes, filters out already-COMMITTED files, and enqueues new ones as PENDING. The Watched Directory is assumed to contain only complete, transfer-ready files — partial transfers and in-flight writes are the responsibility of whatever process deposits files there. SFTP is not a supported source; see ADR-0005.
|
|
109
|
+
|
|
110
|
+
For large-scale deployments where object-store listing cost or latency becomes a concern, operators should use time-partitioned prefixes — e.g. `s3://bucket/landing/2026-05-23/` — and update the `filedge run --dir` argument daily. This keeps each Run's listing bounded to that day's files without requiring the pipeline to move or delete objects after ingestion.
|
|
111
|
+
|
|
112
|
+
### File States
|
|
113
|
+
The four states a File passes through: `PENDING` (discovered, not yet claimed), `PROCESSING` (claimed by a worker — acts as a distributed lock via content hash), `COMMITTED` (fully loaded, transaction complete), `FAILED` (load attempt failed, eligible for retry or human review). A file whose content hash is already `COMMITTED` is never admitted to the pipeline — it is silently deduplicated at the entry point.
|
|
114
|
+
|
|
115
|
+
### Target User
|
|
116
|
+
Data engineering teams at fintech companies where file ingestion is business-critical and high-visibility auditability is a compliance requirement. Every file must be traceable from source to destination row, and the audit trail must be uniform across all data sources — whether data starts as file drops, API exports, or queue messages materialized as files.
|
|
117
|
+
_Avoid_: General data engineering teams, analytics teams.
|
|
118
|
+
|
|
119
|
+
### API Source
|
|
120
|
+
A data source that delivers records via HTTP API rather than file drops. Examples: Stripe, Salesforce, HubSpot, Jira, GitHub. API Sources are not polled directly by Filedge. They must be materialized by an upstream Fetcher as complete Files in a Watched Directory before `filedge run` ingests them.
|
|
121
|
+
_Avoid_: API connector, API pipeline.
|
|
122
|
+
|
|
123
|
+
### Fetcher
|
|
124
|
+
A component or external job that pulls data from an API Source on a schedule, handles pagination, authentication, rate limiting, and incremental cursor management, and writes complete NDJSON files to the Watched Directory. The Fetcher is the API-source equivalent of the rclone sync layer for SFTP (ADR-0005): useful upstream plumbing, not Filedge's core ingestion layer. dlt, Airbyte, Meltano, vendor exports, and custom scripts can all be Fetchers. Only complete files should reach the Watched Directory; partial fetches must remain in staging or be deleted.
|
|
125
|
+
_Avoid_: API connector, extractor, source connector.
|
|
126
|
+
|
|
127
|
+
### Fetch Lock
|
|
128
|
+
A Fetcher-owned concurrency guard that prevents two fetches for the same API Source from racing to promote partial files to the Watched Directory. It may be a filesystem lock, scheduler-level mutual exclusion, or a lock in the Fetcher's own state store. It is not an Audit DB record and is not part of the `filedge run` state machine.
|
|
129
|
+
_Avoid_: fetch mutex, distributed lock.
|
|
130
|
+
|
|
131
|
+
### Queue Source
|
|
132
|
+
A data source that delivers records through a message broker such as Kafka, SQS, or Kinesis. Queue Sources are not consumed directly by Filedge. They must be materialized by an upstream Queue Materializer as complete Files in a Watched Directory before `filedge run` ingests them.
|
|
133
|
+
_Avoid_: streaming source, event source, message queue connector.
|
|
134
|
+
|
|
135
|
+
### Queue Materializer
|
|
136
|
+
A component or external job that consumes records from a Queue Source, groups them into complete files, writes them to a staging area, and promotes them into the Watched Directory only after the file is complete. Examples include Kafka Connect S3 Sink, Kafka Connect GCS Sink, Flink, Spark Structured Streaming, Vector, Benthos, cloud-native delivery services, and custom consumers. The Queue Materializer owns consumer groups, offsets, rebalances, decoding, schema registry integration, poison-message handling, and delivery cadence. Filedge starts at the File boundary.
|
|
137
|
+
_Avoid_: queue connector, streaming ingestion engine, `filedge consume`.
|
|
138
|
+
|
|
139
|
+
### Offset Range Metadata
|
|
140
|
+
Optional provenance metadata recorded by a Queue Materializer in the filename, object metadata, or sidecar manifest. For Kafka, a useful convention is `{topic}.{partition}.{start_offset}-{end_offset}.ndjson`. Offset Range Metadata helps operators trace a File back to queue positions, but it is not Filedge's idempotency key. Filedge still deduplicates by Content Hash.
|
|
141
|
+
_Avoid_: offset range key, consumer checkpoint.
|
|
142
|
+
|
|
143
|
+
### Sources Config
|
|
144
|
+
A Fetcher-specific config file that declares how an API Source is pulled: which endpoints to fetch, the incremental key or cursor, credentials lookup, and the staging/landing paths. This is outside Filedge's core config surface. `pipeline.yaml` remains the Filedge config for ingesting the resulting Files.
|
|
145
|
+
_Avoid_: fetch config, source pipeline.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Contributing to Filedge
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! This guide covers how to set up a
|
|
4
|
+
development environment, run the test suite, and submit a change.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
Filedge uses [uv](https://docs.astral.sh/uv/) for environment and dependency
|
|
9
|
+
management. Install uv first, then:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git clone https://github.com/tongqqiu/filedge.git
|
|
13
|
+
cd filedge
|
|
14
|
+
uv sync --extra dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For connector-specific work, add the matching extra:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv sync --extra dev --extra postgres # Postgres connector
|
|
21
|
+
uv sync --extra dev --extra bigquery # BigQuery connector
|
|
22
|
+
uv sync --extra dev --extra databricks # Databricks connector
|
|
23
|
+
uv sync --extra dev --extra duckdb # DuckDB / Parquet
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Running checks locally
|
|
27
|
+
|
|
28
|
+
Before opening a PR, run the same checks CI does:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv run ruff check . # lint
|
|
32
|
+
uv run pytest --cov=filedge --cov-report=term-missing # tests + coverage
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The Postgres test suite requires a running Postgres instance. Either start one
|
|
36
|
+
locally and export `DATABASE_URL`, or rely on CI to cover that path.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
export DATABASE_URL=postgresql://postgres:etl@localhost/etldb
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Live BigQuery / Databricks integration tests are opt-in via env flags — see
|
|
43
|
+
[README.md](README.md#bigquery) for the variables.
|
|
44
|
+
|
|
45
|
+
## Submitting a change
|
|
46
|
+
|
|
47
|
+
1. **Open an issue first** for anything beyond a small fix. It's faster to align
|
|
48
|
+
on approach in an issue than to redo a PR.
|
|
49
|
+
2. **Branch from `main`** — name branches like `fix/...`, `feat/...`,
|
|
50
|
+
`docs/...`, `chore/...`.
|
|
51
|
+
3. **Write or update tests** alongside the change. We expect new code paths to
|
|
52
|
+
have coverage; the suite runs `--cov` in CI.
|
|
53
|
+
4. **Keep PRs focused.** One concern per PR. Mechanical refactors should be
|
|
54
|
+
separate from behavioural changes.
|
|
55
|
+
5. **Update docs.** If you change CLI flags, config keys, or connector
|
|
56
|
+
behaviour, update the relevant page in `docs/` and the README.
|
|
57
|
+
6. **Add an ADR** for architectural decisions. See `docs/adr/` for the format —
|
|
58
|
+
each ADR is a short markdown file with Context / Decision / Consequences.
|
|
59
|
+
7. **Run the full check suite locally** (lint + pytest) before pushing.
|
|
60
|
+
|
|
61
|
+
All changes go through pull request review — no direct pushes to `main`.
|
|
62
|
+
|
|
63
|
+
## Commit messages
|
|
64
|
+
|
|
65
|
+
Short, imperative subject lines (`Add ...`, `Fix ...`, `Refactor ...`), wrapped
|
|
66
|
+
at ~72 chars. The body explains *why*, not *what* — the diff already shows the
|
|
67
|
+
what.
|
|
68
|
+
|
|
69
|
+
## Code style
|
|
70
|
+
|
|
71
|
+
- Python 3.11+. Type hints on public functions.
|
|
72
|
+
- `ruff` for lint and format. Default ruleset; do not disable rules without
|
|
73
|
+
justification.
|
|
74
|
+
- Prefer explicit over clever. This is a reliability-focused codebase — clarity
|
|
75
|
+
beats brevity.
|
|
76
|
+
- No new top-level dependencies without discussion in an issue. Optional
|
|
77
|
+
features go behind an extra in `pyproject.toml`.
|
|
78
|
+
|
|
79
|
+
## Releasing
|
|
80
|
+
|
|
81
|
+
See [docs/release-checklist.md](docs/release-checklist.md) for the step-by-step process — build verification, docs build, CLI smoke test, PyPI publish, and post-publish install-doc update.
|
|
82
|
+
|
|
83
|
+
## Reporting bugs
|
|
84
|
+
|
|
85
|
+
Use the bug issue template. Include:
|
|
86
|
+
|
|
87
|
+
- Filedge version / commit SHA
|
|
88
|
+
- Python version
|
|
89
|
+
- Connector type (sqlite / postgres / bigquery / databricks)
|
|
90
|
+
- Minimal `pipeline.yaml` and sample input that reproduces the issue
|
|
91
|
+
- Full traceback or audit-DB state if relevant
|
|
92
|
+
|
|
93
|
+
## Security issues
|
|
94
|
+
|
|
95
|
+
**Do not file security issues in the public tracker.** See
|
|
96
|
+
[SECURITY.md](SECURITY.md) for the private reporting process.
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
By contributing, you agree that your contributions will be licensed under the
|
|
101
|
+
Apache License 2.0 — the same license as the rest of the project.
|