etlrelay 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.
Files changed (81) hide show
  1. etlrelay-0.1.0/.github/workflows/ci.yml +64 -0
  2. etlrelay-0.1.0/.github/workflows/publish-testpypi.yml +176 -0
  3. etlrelay-0.1.0/.github/workflows/release-pypi.yml +242 -0
  4. etlrelay-0.1.0/.gitignore +55 -0
  5. etlrelay-0.1.0/CHANGELOG.md +25 -0
  6. etlrelay-0.1.0/DOCS_SETUP.md +62 -0
  7. etlrelay-0.1.0/LICENSE +201 -0
  8. etlrelay-0.1.0/NOTICE +4 -0
  9. etlrelay-0.1.0/PKG-INFO +435 -0
  10. etlrelay-0.1.0/README.md +419 -0
  11. etlrelay-0.1.0/SECURITY.md +17 -0
  12. etlrelay-0.1.0/docs/api-reference.md +41 -0
  13. etlrelay-0.1.0/docs/class_diagrams/file_sink_class_diagram.md +265 -0
  14. etlrelay-0.1.0/docs/class_diagrams/file_source_class_diagram.md +251 -0
  15. etlrelay-0.1.0/docs/class_diagrams/local_filesystem_class_diagram.md +341 -0
  16. etlrelay-0.1.0/docs/class_diagrams/path_validator_class_diagram.md +171 -0
  17. etlrelay-0.1.0/docs/class_diagrams/pipeline_class_diagram.md +293 -0
  18. etlrelay-0.1.0/docs/class_diagrams/reader_and_writer_class_diagram.md +366 -0
  19. etlrelay-0.1.0/docs/concepts.md +32 -0
  20. etlrelay-0.1.0/docs/development/release-automation.md +99 -0
  21. etlrelay-0.1.0/docs/development.md +40 -0
  22. etlrelay-0.1.0/docs/etl_relay_v1_roadmap.md +266 -0
  23. etlrelay-0.1.0/docs/getting-started.md +73 -0
  24. etlrelay-0.1.0/docs/index.md +34 -0
  25. etlrelay-0.1.0/docs/security.md +15 -0
  26. etlrelay-0.1.0/examples/copy_csv.py +35 -0
  27. etlrelay-0.1.0/flake.lock +93 -0
  28. etlrelay-0.1.0/flake.nix +65 -0
  29. etlrelay-0.1.0/mkdocs.yml +62 -0
  30. etlrelay-0.1.0/pyproject.toml +75 -0
  31. etlrelay-0.1.0/release-automation.md +99 -0
  32. etlrelay-0.1.0/src/etlrelay/__init__.py +0 -0
  33. etlrelay-0.1.0/src/etlrelay/core/__init__.py +0 -0
  34. etlrelay-0.1.0/src/etlrelay/core/batch.py +30 -0
  35. etlrelay-0.1.0/src/etlrelay/core/processor.py +33 -0
  36. etlrelay-0.1.0/src/etlrelay/core/reader.py +36 -0
  37. etlrelay-0.1.0/src/etlrelay/core/sink.py +33 -0
  38. etlrelay-0.1.0/src/etlrelay/core/source.py +34 -0
  39. etlrelay-0.1.0/src/etlrelay/core/writer.py +34 -0
  40. etlrelay-0.1.0/src/etlrelay/pipeline/__init__.py +0 -0
  41. etlrelay-0.1.0/src/etlrelay/pipeline/pipeline.py +85 -0
  42. etlrelay-0.1.0/src/etlrelay/processors/__init__.py +0 -0
  43. etlrelay-0.1.0/src/etlrelay/readers/__init__.py +0 -0
  44. etlrelay-0.1.0/src/etlrelay/readers/csv.py +36 -0
  45. etlrelay-0.1.0/src/etlrelay/security/__init__.py +0 -0
  46. etlrelay-0.1.0/src/etlrelay/security/path.py +65 -0
  47. etlrelay-0.1.0/src/etlrelay/sinks/__init__.py +0 -0
  48. etlrelay-0.1.0/src/etlrelay/sinks/file.py +60 -0
  49. etlrelay-0.1.0/src/etlrelay/sources/__init__.py +0 -0
  50. etlrelay-0.1.0/src/etlrelay/sources/file.py +50 -0
  51. etlrelay-0.1.0/src/etlrelay/storage/__init__.py +0 -0
  52. etlrelay-0.1.0/src/etlrelay/storage/filesystem.py +55 -0
  53. etlrelay-0.1.0/src/etlrelay/storage/local.py +78 -0
  54. etlrelay-0.1.0/src/etlrelay/writers/__init__.py +0 -0
  55. etlrelay-0.1.0/src/etlrelay/writers/csv.py +37 -0
  56. etlrelay-0.1.0/tests/functional/test_csv_pipeline.py +44 -0
  57. etlrelay-0.1.0/tests/integration/sinks/__init__.py +0 -0
  58. etlrelay-0.1.0/tests/integration/sinks/test_file.py +53 -0
  59. etlrelay-0.1.0/tests/integration/sources/__init__.py +0 -0
  60. etlrelay-0.1.0/tests/integration/sources/test_file.py +37 -0
  61. etlrelay-0.1.0/tests/unit/__init__.py +0 -0
  62. etlrelay-0.1.0/tests/unit/core/__init__.py +0 -0
  63. etlrelay-0.1.0/tests/unit/core/test_batch.py +26 -0
  64. etlrelay-0.1.0/tests/unit/core/test_processor.py +30 -0
  65. etlrelay-0.1.0/tests/unit/core/test_sink.py +14 -0
  66. etlrelay-0.1.0/tests/unit/core/test_source.py +21 -0
  67. etlrelay-0.1.0/tests/unit/pipeline/__init__.py +0 -0
  68. etlrelay-0.1.0/tests/unit/pipeline/test_pipeline.py +205 -0
  69. etlrelay-0.1.0/tests/unit/readers/__init__.py +0 -0
  70. etlrelay-0.1.0/tests/unit/readers/test_csv.py +44 -0
  71. etlrelay-0.1.0/tests/unit/security/__init__.py +0 -0
  72. etlrelay-0.1.0/tests/unit/security/test_path.py +340 -0
  73. etlrelay-0.1.0/tests/unit/sinks/__init__.py +0 -0
  74. etlrelay-0.1.0/tests/unit/sinks/test_file.py +150 -0
  75. etlrelay-0.1.0/tests/unit/sources/__init__.py +0 -0
  76. etlrelay-0.1.0/tests/unit/sources/test_file.py +181 -0
  77. etlrelay-0.1.0/tests/unit/storage/__init__.py +0 -0
  78. etlrelay-0.1.0/tests/unit/storage/test_local.py +128 -0
  79. etlrelay-0.1.0/tests/unit/writers/__init__.py +0 -0
  80. etlrelay-0.1.0/tests/unit/writers/test_csv.py +71 -0
  81. etlrelay-0.1.0/uv.lock +1151 -0
@@ -0,0 +1,64 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - dev
7
+ - main
8
+ pull_request:
9
+ branches:
10
+ - dev
11
+ - main
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ concurrency:
17
+ group: ci-${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ quality:
22
+ name: quality
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Check out repository
26
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27
+
28
+ - name: Set up uv
29
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
30
+ with:
31
+ enable-cache: true
32
+
33
+ - name: Install Python
34
+ run: uv python install 3.12
35
+
36
+ - name: Install locked project and development dependencies
37
+ run: uv sync --locked --all-groups
38
+
39
+ - name: Run tests with branch coverage
40
+ run: >-
41
+ uv run pytest
42
+ --cov=etlrelay
43
+ --cov-branch
44
+ --cov-report=term-missing
45
+ --cov-report=xml
46
+ --cov-fail-under=90.1
47
+
48
+ - name: Check lint
49
+ run: uv run ruff check src tests
50
+
51
+ - name: Check formatting
52
+ run: uv run ruff format --check src tests
53
+
54
+ - name: Check types
55
+ run: uv run pyright
56
+
57
+ - name: Build documentation
58
+ run: uv run mkdocs build --strict
59
+
60
+ - name: Build source distribution and wheel
61
+ run: uv build
62
+
63
+ - name: Validate distribution metadata
64
+ run: uvx --from 'twine>=7,<8' twine check dist/*
@@ -0,0 +1,176 @@
1
+ name: Publish to TestPyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ build:
11
+ name: verify and build
12
+ runs-on: ubuntu-latest
13
+ outputs:
14
+ version: ${{ steps.metadata.outputs.version }}
15
+ distribution: ${{ steps.metadata.outputs.distribution }}
16
+ steps:
17
+ - name: Check out repository
18
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+
20
+ - name: Require the dev branch
21
+ shell: bash
22
+ run: |
23
+ if [[ "$GITHUB_REF_NAME" != "dev" ]]; then
24
+ echo "TestPyPI publishing must be run from the dev branch; selected: $GITHUB_REF_NAME" >&2
25
+ exit 1
26
+ fi
27
+
28
+ - name: Set up uv
29
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
30
+ with:
31
+ enable-cache: true
32
+
33
+ - name: Install Python
34
+ run: uv python install 3.12
35
+
36
+ - name: Read package metadata
37
+ id: metadata
38
+ shell: bash
39
+ run: |
40
+ python - <<'PY' >> "$GITHUB_OUTPUT"
41
+ import os
42
+ import re
43
+ import tomllib
44
+ from pathlib import Path
45
+
46
+ project = tomllib.loads(Path("pyproject.toml").read_text())["project"]
47
+ distribution = re.sub(r"[-_.]+", "-", project["name"]).lower()
48
+ if distribution != "etlrelay":
49
+ raise SystemExit(f"Expected distribution name 'etlrelay', got {project['name']!r}")
50
+ print(f"version={project['version']}")
51
+ print(f"distribution={distribution}")
52
+ PY
53
+
54
+ - name: Install locked project and development dependencies
55
+ run: uv sync --locked --all-groups
56
+
57
+ - name: Run tests with branch coverage
58
+ run: >-
59
+ uv run pytest
60
+ --cov=etlrelay
61
+ --cov-branch
62
+ --cov-report=term-missing
63
+ --cov-report=xml
64
+ --cov-fail-under=90.1
65
+
66
+ - name: Check lint
67
+ run: uv run ruff check src tests
68
+
69
+ - name: Check formatting
70
+ run: uv run ruff format --check src tests
71
+
72
+ - name: Check types
73
+ run: uv run pyright
74
+
75
+ - name: Build documentation
76
+ run: uv run mkdocs build --strict
77
+
78
+ - name: Build source distribution and wheel
79
+ run: uv build
80
+
81
+ - name: Validate distribution metadata
82
+ run: uvx --from 'twine>=7,<8' twine check dist/*
83
+
84
+ - name: Upload built distributions
85
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
86
+ with:
87
+ name: testpypi-distributions
88
+ path: dist/*
89
+ if-no-files-found: error
90
+ retention-days: 7
91
+
92
+ publish:
93
+ name: publish to TestPyPI
94
+ needs: build
95
+ runs-on: ubuntu-latest
96
+ environment:
97
+ name: testpypi
98
+ url: https://test.pypi.org/project/etlrelay/${{ needs.build.outputs.version }}/
99
+ permissions:
100
+ id-token: write
101
+ steps:
102
+ - name: Download built distributions
103
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
104
+ with:
105
+ name: testpypi-distributions
106
+ path: dist/
107
+
108
+ - name: Publish to TestPyPI
109
+ uses: pypa/gh-action-pypi-publish@release/v1
110
+ with:
111
+ repository-url: https://test.pypi.org/legacy/
112
+
113
+ smoke-test:
114
+ name: install and smoke-test TestPyPI package
115
+ needs: [build, publish]
116
+ runs-on: ubuntu-latest
117
+ steps:
118
+ - name: Check out source for runtime dependency metadata
119
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
120
+
121
+ - name: Set up uv
122
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
123
+ with:
124
+ enable-cache: true
125
+
126
+ - name: Install Python
127
+ run: uv python install 3.12
128
+
129
+ - name: Export runtime dependencies without the checkout package
130
+ run: >-
131
+ uv export
132
+ --no-dev
133
+ --no-default-groups
134
+ --no-emit-project
135
+ --format requirements.txt
136
+ --output-file /tmp/etlrelay-runtime-requirements.txt
137
+
138
+ - name: Create a clean environment and install runtime dependencies
139
+ run: |
140
+ uv venv --python 3.12 /tmp/etlrelay-smoke
141
+ uv pip install --python /tmp/etlrelay-smoke/bin/python \
142
+ -r /tmp/etlrelay-runtime-requirements.txt
143
+
144
+ - name: Wait for TestPyPI to index the release
145
+ env:
146
+ PACKAGE_VERSION: ${{ needs.build.outputs.version }}
147
+ shell: bash
148
+ run: |
149
+ for attempt in $(seq 1 24); do
150
+ if curl --fail --silent \
151
+ "https://test.pypi.org/pypi/etlrelay/${PACKAGE_VERSION}/json" \
152
+ >/dev/null; then
153
+ echo "TestPyPI has indexed etlrelay ${PACKAGE_VERSION}."
154
+ exit 0
155
+ fi
156
+ echo "Waiting for TestPyPI indexing (attempt ${attempt}/24)..."
157
+ sleep 5
158
+ done
159
+ echo "TestPyPI did not index etlrelay ${PACKAGE_VERSION} within two minutes." >&2
160
+ exit 1
161
+
162
+ - name: Install the published TestPyPI distribution
163
+ env:
164
+ PACKAGE_VERSION: ${{ needs.build.outputs.version }}
165
+ run: >-
166
+ uv pip install
167
+ --python /tmp/etlrelay-smoke/bin/python
168
+ --index-url https://test.pypi.org/simple/
169
+ --no-deps
170
+ "etlrelay==${PACKAGE_VERSION}"
171
+
172
+ - name: Smoke-test installed package outside the repository
173
+ run: |
174
+ cd /tmp
175
+ /tmp/etlrelay-smoke/bin/python -c \
176
+ "from etlrelay.core.batch import Batch; from etlrelay.pipeline.pipeline import Pipeline; print('ETLRelay installed-package imports succeeded')"
@@ -0,0 +1,242 @@
1
+ name: Publish release to PyPI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ verify-build:
14
+ # Keep false while bootstrapping TestPyPI; set the repository variable to true
15
+ # only after the TestPyPI candidate has passed its smoke test.
16
+ if: github.ref == 'refs/heads/main' && vars.PYPI_RELEASE_ENABLED == 'true'
17
+ name: verify and build release
18
+ runs-on: ubuntu-latest
19
+ outputs:
20
+ version: ${{ steps.metadata.outputs.version }}
21
+ distribution: ${{ steps.metadata.outputs.distribution }}
22
+ already_published: ${{ steps.pypi-check.outputs.already_published }}
23
+ steps:
24
+ - name: Check out repository and tags
25
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Set up uv
30
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
31
+ with:
32
+ enable-cache: true
33
+
34
+ - name: Install Python
35
+ run: uv python install 3.12
36
+
37
+ - name: Read package metadata
38
+ id: metadata
39
+ shell: bash
40
+ run: |
41
+ python - <<'PY' >> "$GITHUB_OUTPUT"
42
+ import re
43
+ import tomllib
44
+ from pathlib import Path
45
+
46
+ project = tomllib.loads(Path("pyproject.toml").read_text())["project"]
47
+ distribution = re.sub(r"[-_.]+", "-", project["name"]).lower()
48
+ if distribution != "etlrelay":
49
+ raise SystemExit(f"Expected distribution name 'etlrelay', got {project['name']!r}")
50
+ print(f"version={project['version']}")
51
+ print(f"distribution={distribution}")
52
+ PY
53
+
54
+ - name: Check whether this exact version is already published
55
+ id: pypi-check
56
+ env:
57
+ PACKAGE_VERSION: ${{ steps.metadata.outputs.version }}
58
+ DISTRIBUTION: ${{ steps.metadata.outputs.distribution }}
59
+ shell: bash
60
+ run: |
61
+ status=$(curl --silent --show-error --output /dev/null \
62
+ --write-out '%{http_code}' \
63
+ "https://pypi.org/pypi/${DISTRIBUTION}/${PACKAGE_VERSION}/json")
64
+
65
+ if [[ "$status" == "200" ]]; then
66
+ echo "already_published=true" >> "$GITHUB_OUTPUT"
67
+ echo "${DISTRIBUTION} ${PACKAGE_VERSION} already exists on PyPI; publication will be skipped."
68
+ exit 0
69
+ fi
70
+
71
+ if [[ "$status" != "404" ]]; then
72
+ echo "Unexpected PyPI response HTTP ${status}; refusing to publish." >&2
73
+ exit 1
74
+ fi
75
+
76
+ if git ls-remote --exit-code --tags origin "refs/tags/v${PACKAGE_VERSION}" >/dev/null 2>&1; then
77
+ echo "Release tag v${PACKAGE_VERSION} already exists, but that version was not found on PyPI." >&2
78
+ echo "Investigate this inconsistent release state before retrying." >&2
79
+ exit 1
80
+ fi
81
+
82
+ echo "already_published=false" >> "$GITHUB_OUTPUT"
83
+ echo "Version ${PACKAGE_VERSION} is not on PyPI; running release checks."
84
+
85
+ - name: Install locked project and development dependencies
86
+ if: steps.pypi-check.outputs.already_published == 'false'
87
+ run: uv sync --locked --all-groups
88
+
89
+ - name: Run tests with branch coverage
90
+ if: steps.pypi-check.outputs.already_published == 'false'
91
+ run: >-
92
+ uv run pytest
93
+ --cov=etlrelay
94
+ --cov-branch
95
+ --cov-report=term-missing
96
+ --cov-report=xml
97
+ --cov-fail-under=90.1
98
+
99
+ - name: Check lint
100
+ if: steps.pypi-check.outputs.already_published == 'false'
101
+ run: uv run ruff check src tests
102
+
103
+ - name: Check formatting
104
+ if: steps.pypi-check.outputs.already_published == 'false'
105
+ run: uv run ruff format --check src tests
106
+
107
+ - name: Check types
108
+ if: steps.pypi-check.outputs.already_published == 'false'
109
+ run: uv run pyright
110
+
111
+ - name: Build documentation
112
+ if: steps.pypi-check.outputs.already_published == 'false'
113
+ run: uv run mkdocs build --strict
114
+
115
+ - name: Build source distribution and wheel
116
+ if: steps.pypi-check.outputs.already_published == 'false'
117
+ run: uv build
118
+
119
+ - name: Validate distribution metadata
120
+ if: steps.pypi-check.outputs.already_published == 'false'
121
+ run: uvx --from 'twine>=7,<8' twine check dist/*
122
+
123
+ - name: Upload built distributions
124
+ if: steps.pypi-check.outputs.already_published == 'false'
125
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
126
+ with:
127
+ name: pypi-distributions
128
+ path: dist/*
129
+ if-no-files-found: error
130
+ retention-days: 7
131
+
132
+ publish:
133
+ name: publish to PyPI
134
+ needs: verify-build
135
+ if: needs.verify-build.outputs.already_published == 'false'
136
+ runs-on: ubuntu-latest
137
+ environment:
138
+ name: pypi
139
+ url: https://pypi.org/project/etlrelay/${{ needs.verify-build.outputs.version }}/
140
+ permissions:
141
+ id-token: write
142
+ steps:
143
+ - name: Download verified distributions
144
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
145
+ with:
146
+ name: pypi-distributions
147
+ path: dist/
148
+
149
+ - name: Publish to PyPI
150
+ uses: pypa/gh-action-pypi-publish@release/v1
151
+
152
+ publish-versioned-docs:
153
+ name: publish versioned documentation
154
+ needs: [verify-build, publish]
155
+ # Only make a docs snapshot after a new package version has actually reached PyPI.
156
+ if: ${{ needs.verify-build.outputs.already_published == 'false' && needs.publish.result == 'success' }}
157
+ runs-on: ubuntu-latest
158
+ permissions:
159
+ contents: write
160
+ steps:
161
+ - name: Check out the released source
162
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
163
+ with:
164
+ fetch-depth: 0
165
+
166
+ - name: Set up uv
167
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
168
+ with:
169
+ enable-cache: true
170
+
171
+ - name: Install Python
172
+ run: uv python install 3.12
173
+
174
+ - name: Install documentation and project dependencies
175
+ run: uv sync --locked --all-groups
176
+
177
+ - name: Configure Git identity for mike
178
+ run: |
179
+ git config user.name "github-actions[bot]"
180
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
181
+
182
+ - name: Publish the version and update the latest alias
183
+ env:
184
+ RELEASE_VERSION: ${{ needs.verify-build.outputs.version }}
185
+ run: |
186
+ uv run mike deploy --push --update-aliases "$RELEASE_VERSION" latest
187
+ uv run mike set-default --push latest
188
+
189
+ deploy-versioned-docs-to-github-pages:
190
+ name: deploy documentation to GitHub Pages
191
+ needs: publish-versioned-docs
192
+ runs-on: ubuntu-latest
193
+ permissions:
194
+ contents: read
195
+ pages: write
196
+ id-token: write
197
+ environment:
198
+ name: github-pages
199
+ url: ${{ steps.deployment.outputs.page_url }}
200
+ steps:
201
+ - name: Configure GitHub Pages
202
+ uses: actions/configure-pages@v5
203
+
204
+ - name: Check out the mike-generated site
205
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
206
+ with:
207
+ ref: gh-pages
208
+ path: gh-pages
209
+ persist-credentials: false
210
+
211
+ - name: Prepare Pages artifact without Git metadata
212
+ run: |
213
+ mkdir site-artifact
214
+ rsync -a --exclude='.git' gh-pages/ site-artifact/
215
+
216
+ - name: Upload Pages artifact
217
+ uses: actions/upload-pages-artifact@v4
218
+ with:
219
+ path: site-artifact/
220
+
221
+ - name: Deploy to GitHub Pages
222
+ id: deployment
223
+ uses: actions/deploy-pages@v4
224
+
225
+ create-github-release:
226
+ name: create GitHub release
227
+ needs: [verify-build, publish]
228
+ if: needs.verify-build.outputs.already_published == 'false' && needs.publish.result == 'success'
229
+ runs-on: ubuntu-latest
230
+ permissions:
231
+ contents: write
232
+ steps:
233
+ - name: Create tag and GitHub release
234
+ env:
235
+ GH_TOKEN: ${{ github.token }}
236
+ PACKAGE_VERSION: ${{ needs.verify-build.outputs.version }}
237
+ run: |
238
+ gh release create "v${PACKAGE_VERSION}" \
239
+ --repo "$GITHUB_REPOSITORY" \
240
+ --target "$GITHUB_SHA" \
241
+ --title "ETLRelay ${PACKAGE_VERSION}" \
242
+ --generate-notes
@@ -0,0 +1,55 @@
1
+ # Python bytecode and caches
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Virtual environments
7
+ .venv/
8
+ venv/
9
+ env/
10
+ ENV/
11
+
12
+ # Python packaging / build artifacts
13
+ build/
14
+ dist/
15
+ *.egg-info/
16
+ .eggs/
17
+
18
+ # Test and coverage artifacts
19
+ .pytest_cache/
20
+ .coverage
21
+ .coverage.*
22
+ htmlcov/
23
+ coverage.xml
24
+
25
+ # Type checking / linting caches
26
+ .pyright/
27
+ .ruff_cache/
28
+
29
+ # uv
30
+ .uv/
31
+
32
+ # IDEs and editors
33
+ .idea/
34
+ .vscode/
35
+ *.swp
36
+ *.swo
37
+ *~
38
+
39
+ # macOS
40
+ .DS_Store
41
+
42
+ # Nix
43
+ .direnv/
44
+ result
45
+ result-*
46
+
47
+ # Local environment / secrets
48
+ .env
49
+ .env.*
50
+ !.env.example
51
+
52
+ # Local ETLRelay test data
53
+ data/
54
+
55
+ site/
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ Notable changes to ETLRelay are documented here.
4
+
5
+ This project follows the principles of [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ Changes intended for the first public release are listed below. When preparing the release, move this content to a `0.1.0` section and add the actual release date.
10
+
11
+ ### Added
12
+
13
+ - Batch-oriented pipeline contracts for sources, processors, and sinks.
14
+ - Synchronous pipeline execution with processors applied in sequence.
15
+ - An Arrow-backed `Batch` representation.
16
+ - Local filesystem access through a stream-based `FileSystem` protocol and `LocalFileSystem` implementation.
17
+ - CSV reading and writing through separate reader and writer components.
18
+ - `FileSource` and `FileSink` composition of storage and format components.
19
+ - Path containment validation for local filesystem paths.
20
+ - Unit, integration, and functional tests for the initial local CSV pipeline.
21
+
22
+ ### Notes
23
+
24
+ - This is an experimental pre-1.0 release. Public APIs may change between minor releases.
25
+ - The initial implementation focuses on local filesystem and CSV workflows. SQL, declarative YAML, CLI, Parquet, S3/HDFS, and generic API integrations are not part of this release unless separately implemented and tested.
@@ -0,0 +1,62 @@
1
+ # MkDocs setup instructions for ETLRelay
2
+
3
+ The original ETLRelay technology plan selected MkDocs for documentation, `uv` for Python dependency management, GitHub Actions for CI, and PyPI for distribution. MkDocs was selected in the plan but is not yet configured in the current documentation set. This package adds a minimal setup using Material for MkDocs for the theme and `mkdocstrings[python]` for API reference generation from source docstrings.
4
+
5
+ ## 1. Add documentation dependencies
6
+
7
+ From the repository root, run:
8
+
9
+ ```bash
10
+ uv add --group docs "mkdocs>=1.6,<2" "mkdocs-material>=9,<10" "mkdocstrings[python]>=0.18,<1"
11
+ ```
12
+
13
+ This should add a `docs` dependency group to `pyproject.toml` and update `uv.lock`. Keep these packages out of runtime dependencies.
14
+
15
+ Install the group:
16
+
17
+ ```bash
18
+ uv sync --locked --group docs
19
+ ```
20
+
21
+ ## 2. Add the supplied files
22
+
23
+ Copy `mkdocs.yml` and the `docs/` directory from this package into the repository root. Add `CHANGELOG.md`, `NOTICE`, and `SECURITY.md` at the repository root if they do not already exist. Merge rather than overwrite any existing project configuration.
24
+
25
+ ## 3. Ignore generated output
26
+
27
+ Add this line to the repository `.gitignore` if it is not already present:
28
+
29
+ ```gitignore
30
+ site/
31
+ ```
32
+
33
+ ## 4. Build and preview
34
+
35
+ ```bash
36
+ uv run mkdocs serve
37
+ uv run mkdocs build --strict
38
+ ```
39
+
40
+ The API page references the expected `src/etlrelay` module layout. Review those import paths against the actual repository and fix any differences before considering the docs build complete.
41
+
42
+ ## 5. Integrate with existing CI
43
+
44
+ Add this command to the existing GitHub Actions quality-check workflow after installing the `docs` dependency group:
45
+
46
+ ```bash
47
+ uv run mkdocs build --strict
48
+ ```
49
+
50
+ Do not create a duplicate CI workflow if an existing one already performs quality checks. A green strict build should be required for documentation changes.
51
+
52
+ ## 6. Finish release documents
53
+
54
+ - `CHANGELOG.md`: move the initial-release entries under `[Unreleased]` to a `[0.1.0] - YYYY-MM-DD` heading with the actual release date when preparing the release tag.
55
+ - `NOTICE`: confirm the copyright holder and year, and ensure the notice is consistent with the existing `LICENSE` file.
56
+ - `SECURITY.md`: enable GitHub private vulnerability reporting before public release, or replace the reporting instructions with a verified private contact channel.
57
+ - Getting Started: run `examples/copy_csv.py` against the built and installed package. Correct the example if actual signatures differ.
58
+ - API reference: verify all paths listed in `docs/api-reference.md` exist in `src/etlrelay`.
59
+
60
+ ## Hosting
61
+
62
+ MkDocs builds a static site in `site/`, which can be hosted on GitHub Pages or another static host. Hosting/deployment is intentionally not configured by this setup package because the repository URL, default branch, and GitHub Pages settings need to be confirmed in the actual repository. Add deployment after the strict local build passes.