sftpwarden 1.0.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 (115) hide show
  1. sftpwarden-1.0.0/.dockerignore +20 -0
  2. sftpwarden-1.0.0/.env.example +2 -0
  3. sftpwarden-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
  4. sftpwarden-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  5. sftpwarden-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +20 -0
  6. sftpwarden-1.0.0/.github/dependabot.yml +77 -0
  7. sftpwarden-1.0.0/.github/workflows/ci.yml +94 -0
  8. sftpwarden-1.0.0/.github/workflows/docker.yml +145 -0
  9. sftpwarden-1.0.0/.github/workflows/docs.yml +60 -0
  10. sftpwarden-1.0.0/.github/workflows/release.yml +122 -0
  11. sftpwarden-1.0.0/.github/workflows/security.yml +118 -0
  12. sftpwarden-1.0.0/.gitignore +40 -0
  13. sftpwarden-1.0.0/CHANGELOG.md +37 -0
  14. sftpwarden-1.0.0/CODE_OF_CONDUCT.md +29 -0
  15. sftpwarden-1.0.0/CONTRIBUTING.md +177 -0
  16. sftpwarden-1.0.0/LICENSE +174 -0
  17. sftpwarden-1.0.0/PKG-INFO +452 -0
  18. sftpwarden-1.0.0/README.md +407 -0
  19. sftpwarden-1.0.0/SECURITY.md +55 -0
  20. sftpwarden-1.0.0/docker/runtime/Dockerfile +26 -0
  21. sftpwarden-1.0.0/docker/runtime/entrypoint.sh +20 -0
  22. sftpwarden-1.0.0/docker/runtime/sshd_config.template +33 -0
  23. sftpwarden-1.0.0/docker/watcher/Dockerfile +21 -0
  24. sftpwarden-1.0.0/docker/watcher/entrypoint.sh +5 -0
  25. sftpwarden-1.0.0/docs/_static/logo sftpwarden.png +0 -0
  26. sftpwarden-1.0.0/docs/_static/social sftpwarden.jpg +0 -0
  27. sftpwarden-1.0.0/docs/cli-reference.md +641 -0
  28. sftpwarden-1.0.0/docs/conf.py +32 -0
  29. sftpwarden-1.0.0/docs/configuration.md +207 -0
  30. sftpwarden-1.0.0/docs/contributing.md +183 -0
  31. sftpwarden-1.0.0/docs/index.md +17 -0
  32. sftpwarden-1.0.0/docs/operations.md +135 -0
  33. sftpwarden-1.0.0/docs/security.md +85 -0
  34. sftpwarden-1.0.0/examples/csv/docker-compose.yml +15 -0
  35. sftpwarden-1.0.0/examples/csv/sftpwarden.yaml +7 -0
  36. sftpwarden-1.0.0/examples/csv/users.csv +3 -0
  37. sftpwarden-1.0.0/examples/mysql/docker-compose.yml +7 -0
  38. sftpwarden-1.0.0/examples/mysql/schema.sql +10 -0
  39. sftpwarden-1.0.0/examples/mysql/sftpwarden.yaml +8 -0
  40. sftpwarden-1.0.0/examples/postgres/docker-compose.yml +7 -0
  41. sftpwarden-1.0.0/examples/postgres/schema.sql +10 -0
  42. sftpwarden-1.0.0/examples/postgres/sftpwarden.yaml +8 -0
  43. sftpwarden-1.0.0/examples/remote-local-sync/README.md +14 -0
  44. sftpwarden-1.0.0/examples/remote-only/README.md +12 -0
  45. sftpwarden-1.0.0/examples/watcher-docker/docker-compose.yml +10 -0
  46. sftpwarden-1.0.0/examples/yaml/docker-compose.yml +15 -0
  47. sftpwarden-1.0.0/examples/yaml/sftpwarden.yaml +7 -0
  48. sftpwarden-1.0.0/examples/yaml/users.yaml +5 -0
  49. sftpwarden-1.0.0/pyproject.toml +96 -0
  50. sftpwarden-1.0.0/sftpwarden/__init__.py +3 -0
  51. sftpwarden-1.0.0/sftpwarden/__main__.py +3 -0
  52. sftpwarden-1.0.0/sftpwarden/cli.py +13 -0
  53. sftpwarden-1.0.0/sftpwarden/cli_commands/__init__.py +0 -0
  54. sftpwarden-1.0.0/sftpwarden/cli_commands/common.py +209 -0
  55. sftpwarden-1.0.0/sftpwarden/cli_commands/config.py +268 -0
  56. sftpwarden-1.0.0/sftpwarden/cli_commands/context.py +674 -0
  57. sftpwarden-1.0.0/sftpwarden/cli_commands/core.py +384 -0
  58. sftpwarden-1.0.0/sftpwarden/cli_commands/init.py +437 -0
  59. sftpwarden-1.0.0/sftpwarden/cli_commands/runtime.py +85 -0
  60. sftpwarden-1.0.0/sftpwarden/cli_commands/users.py +270 -0
  61. sftpwarden-1.0.0/sftpwarden/cli_commands/watcher.py +111 -0
  62. sftpwarden-1.0.0/sftpwarden/config/__init__.py +595 -0
  63. sftpwarden-1.0.0/sftpwarden/config/global_config.py +142 -0
  64. sftpwarden-1.0.0/sftpwarden/contexts.py +526 -0
  65. sftpwarden-1.0.0/sftpwarden/providers/__init__.py +203 -0
  66. sftpwarden-1.0.0/sftpwarden/providers/base.py +138 -0
  67. sftpwarden-1.0.0/sftpwarden/providers/csv_provider.py +98 -0
  68. sftpwarden-1.0.0/sftpwarden/providers/mutations.py +3 -0
  69. sftpwarden-1.0.0/sftpwarden/providers/mysql_provider.py +248 -0
  70. sftpwarden-1.0.0/sftpwarden/providers/postgres_provider.py +198 -0
  71. sftpwarden-1.0.0/sftpwarden/providers/registry.py +118 -0
  72. sftpwarden-1.0.0/sftpwarden/providers/sql.py +305 -0
  73. sftpwarden-1.0.0/sftpwarden/providers/yaml_provider.py +61 -0
  74. sftpwarden-1.0.0/sftpwarden/refresh.py +137 -0
  75. sftpwarden-1.0.0/sftpwarden/remote/__init__.py +1 -0
  76. sftpwarden-1.0.0/sftpwarden/remote/checks.py +57 -0
  77. sftpwarden-1.0.0/sftpwarden/remote/deploy.py +329 -0
  78. sftpwarden-1.0.0/sftpwarden/remote/ssh.py +89 -0
  79. sftpwarden-1.0.0/sftpwarden/render/__init__.py +1 -0
  80. sftpwarden-1.0.0/sftpwarden/render/compose.py +92 -0
  81. sftpwarden-1.0.0/sftpwarden/runtime.py +933 -0
  82. sftpwarden-1.0.0/sftpwarden/security/__init__.py +1 -0
  83. sftpwarden-1.0.0/sftpwarden/security/passwords.py +71 -0
  84. sftpwarden-1.0.0/sftpwarden/services/__init__.py +0 -0
  85. sftpwarden-1.0.0/sftpwarden/services/cli_workflows.py +72 -0
  86. sftpwarden-1.0.0/sftpwarden/services/users.py +239 -0
  87. sftpwarden-1.0.0/sftpwarden/system/__init__.py +3 -0
  88. sftpwarden-1.0.0/sftpwarden/system/commands.py +158 -0
  89. sftpwarden-1.0.0/sftpwarden/users/__init__.py +11 -0
  90. sftpwarden-1.0.0/sftpwarden/users/models.py +133 -0
  91. sftpwarden-1.0.0/sftpwarden/users/service.py +107 -0
  92. sftpwarden-1.0.0/sftpwarden/utils/__init__.py +1 -0
  93. sftpwarden-1.0.0/sftpwarden/utils/console.py +5 -0
  94. sftpwarden-1.0.0/sftpwarden/utils/constants.py +14 -0
  95. sftpwarden-1.0.0/sftpwarden/utils/dotted.py +93 -0
  96. sftpwarden-1.0.0/sftpwarden/utils/errors.py +26 -0
  97. sftpwarden-1.0.0/sftpwarden/utils/files.py +33 -0
  98. sftpwarden-1.0.0/sftpwarden/utils/paths.py +82 -0
  99. sftpwarden-1.0.0/sftpwarden/watcher.py +613 -0
  100. sftpwarden-1.0.0/tests/test_cli.py +822 -0
  101. sftpwarden-1.0.0/tests/test_cli_adapters.py +1076 -0
  102. sftpwarden-1.0.0/tests/test_config.py +177 -0
  103. sftpwarden-1.0.0/tests/test_config_context_edges.py +263 -0
  104. sftpwarden-1.0.0/tests/test_contexts_and_watch.py +1132 -0
  105. sftpwarden-1.0.0/tests/test_dockerfile.py +54 -0
  106. sftpwarden-1.0.0/tests/test_packaging.py +38 -0
  107. sftpwarden-1.0.0/tests/test_providers.py +171 -0
  108. sftpwarden-1.0.0/tests/test_remote_checks.py +61 -0
  109. sftpwarden-1.0.0/tests/test_runtime.py +618 -0
  110. sftpwarden-1.0.0/tests/test_services_providers_utils.py +385 -0
  111. sftpwarden-1.0.0/tests/test_sql_providers.py +502 -0
  112. sftpwarden-1.0.0/tests/test_system_commands.py +36 -0
  113. sftpwarden-1.0.0/tests/test_user_service.py +58 -0
  114. sftpwarden-1.0.0/tests/test_workflows.py +76 -0
  115. sftpwarden-1.0.0/tox.ini +48 -0
@@ -0,0 +1,20 @@
1
+ *
2
+
3
+ !pyproject.toml
4
+ !README.md
5
+ !LICENSE
6
+
7
+ !sftpwarden
8
+ !sftpwarden/**
9
+
10
+ !docker
11
+ !docker/runtime
12
+ !docker/runtime/**
13
+ !docker/watcher
14
+ !docker/watcher/**
15
+
16
+ **/__pycache__
17
+ **/*.py[cod]
18
+ **/*.pyo
19
+ **/*.pyd
20
+ **/.DS_Store
@@ -0,0 +1,2 @@
1
+ SFTPWARDEN_CONFIG=/etc/sftpwarden/sftpwarden.yaml
2
+
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report something that is not working as expected
4
+ title: "Bug: "
5
+ labels: bug
6
+ assignees: ""
7
+ ---
8
+
9
+ ## What happened?
10
+
11
+ Describe the problem clearly.
12
+
13
+ ## What did you expect?
14
+
15
+ Describe the expected behavior.
16
+
17
+ ## Reproduction
18
+
19
+ ```bash
20
+ # commands or minimal steps
21
+ ```
22
+
23
+ ## Environment
24
+
25
+ - SFTPWarden version or commit:
26
+ - Python version:
27
+ - OS:
28
+ - Docker version:
29
+ - Provider: YAML / CSV / MySQL / PostgreSQL
30
+ - Context type: local / remote local-sync / remote-only
31
+
32
+ ## Logs
33
+
34
+ Paste relevant output here. Redact secrets, tokens, private keys, DSNs, usernames,
35
+ hostnames, and customer data when needed.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest a useful improvement
4
+ title: "Feature: "
5
+ labels: enhancement
6
+ assignees: ""
7
+ ---
8
+
9
+ ## Problem
10
+
11
+ What operational problem are you trying to solve?
12
+
13
+ ## Proposed behavior
14
+
15
+ What should SFTPWarden do?
16
+
17
+ ## Alternatives considered
18
+
19
+ What have you tried or considered?
20
+
21
+ ## Compatibility
22
+
23
+ Would this affect existing CLI commands, config files, provider schemas, runtime
24
+ state, Docker images, or remote deployment behavior?
@@ -0,0 +1,20 @@
1
+ ## Summary
2
+
3
+ Describe the user-facing change.
4
+
5
+ ## Target Branch
6
+
7
+ - [ ] This PR targets `dev`, not `main`
8
+
9
+ ## Validation
10
+
11
+ - [ ] Docs-only change: `tox -e docs`
12
+ - [ ] Code change: `tox`
13
+ - [ ] Docker/runtime change: local Docker build/smoke test
14
+ - [ ] Docs updated when behavior changed
15
+ - [ ] Examples updated when configuration changed
16
+ - [ ] No secrets, private keys, tokens, DSNs, or customer data included
17
+
18
+ ## Notes
19
+
20
+ Mention compatibility risks, follow-up work, or deployment considerations.
@@ -0,0 +1,77 @@
1
+ version: 2
2
+
3
+ updates:
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ target-branch: "dev"
7
+ schedule:
8
+ interval: "weekly"
9
+ day: "monday"
10
+ time: "09:00"
11
+ timezone: "Asia/Dubai"
12
+ open-pull-requests-limit: 5
13
+ commit-message:
14
+ prefix: "deps"
15
+ groups:
16
+ python-dependencies:
17
+ patterns:
18
+ - "*"
19
+ update-types:
20
+ - "minor"
21
+ - "patch"
22
+
23
+ - package-ecosystem: "github-actions"
24
+ directory: "/"
25
+ target-branch: "dev"
26
+ schedule:
27
+ interval: "weekly"
28
+ day: "monday"
29
+ time: "09:15"
30
+ timezone: "Asia/Dubai"
31
+ open-pull-requests-limit: 5
32
+ commit-message:
33
+ prefix: "deps"
34
+ groups:
35
+ github-actions:
36
+ patterns:
37
+ - "*"
38
+
39
+ - package-ecosystem: "docker"
40
+ directories:
41
+ - "/"
42
+ - "/docker/runtime"
43
+ - "/docker/watcher"
44
+ target-branch: "dev"
45
+ schedule:
46
+ interval: "weekly"
47
+ day: "monday"
48
+ time: "09:30"
49
+ timezone: "Asia/Dubai"
50
+ open-pull-requests-limit: 5
51
+ commit-message:
52
+ prefix: "deps"
53
+ groups:
54
+ docker-images:
55
+ patterns:
56
+ - "*"
57
+
58
+ - package-ecosystem: "docker-compose"
59
+ directories:
60
+ - "/examples/csv"
61
+ - "/examples/mysql"
62
+ - "/examples/postgres"
63
+ - "/examples/watcher-docker"
64
+ - "/examples/yaml"
65
+ target-branch: "dev"
66
+ schedule:
67
+ interval: "weekly"
68
+ day: "monday"
69
+ time: "09:45"
70
+ timezone: "Asia/Dubai"
71
+ open-pull-requests-limit: 5
72
+ commit-message:
73
+ prefix: "deps"
74
+ groups:
75
+ compose-images:
76
+ patterns:
77
+ - "*"
@@ -0,0 +1,94 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [dev]
6
+ paths:
7
+ - "sftpwarden/**"
8
+ - "tests/**"
9
+ - "examples/**"
10
+ - "docker/**"
11
+ - "pyproject.toml"
12
+ - "tox.ini"
13
+ - ".github/workflows/ci.yml"
14
+ pull_request:
15
+ branches: [dev]
16
+ paths:
17
+ - "sftpwarden/**"
18
+ - "tests/**"
19
+ - "examples/**"
20
+ - "docker/**"
21
+ - "pyproject.toml"
22
+ - "tox.ini"
23
+ - ".github/workflows/ci.yml"
24
+
25
+ permissions:
26
+ contents: read
27
+
28
+ jobs:
29
+ test:
30
+ name: Python ${{ matrix.python-version }}
31
+ runs-on: ubuntu-latest
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ include:
36
+ - python-version: "3.11"
37
+ tox-env: py311
38
+ - python-version: "3.12"
39
+ tox-env: py312
40
+ - python-version: "3.13"
41
+ tox-env: py313
42
+
43
+ steps:
44
+ - name: Check out repository
45
+ uses: actions/checkout@v7.0.0
46
+
47
+ - name: Set up Python
48
+ uses: actions/setup-python@v6.2.0
49
+ with:
50
+ python-version: ${{ matrix.python-version }}
51
+ cache: pip
52
+
53
+ - name: Install tox
54
+ run: |
55
+ python -m pip install --upgrade pip
56
+ python -m pip install tox
57
+
58
+ - name: Run tests
59
+ run: tox -e ${{ matrix.tox-env }}
60
+
61
+ quality:
62
+ name: Lint, package, and examples
63
+ runs-on: ubuntu-latest
64
+
65
+ steps:
66
+ - name: Check out repository
67
+ uses: actions/checkout@v7.0.0
68
+
69
+ - name: Set up Python
70
+ uses: actions/setup-python@v6.2.0
71
+ with:
72
+ python-version: "3.13"
73
+ cache: pip
74
+
75
+ - name: Install tox and package
76
+ run: |
77
+ python -m pip install --upgrade pip
78
+ python -m pip install tox
79
+ python -m pip install -e ".[watch,mysql,postgres]"
80
+
81
+ - name: Run lint and package checks
82
+ run: tox -e lint,package
83
+
84
+ - name: Validate examples
85
+ run: |
86
+ sftpwarden validate --config examples/yaml/sftpwarden.yaml
87
+ sftpwarden validate --config examples/csv/sftpwarden.yaml
88
+ SFTPWARDEN_MYSQL_DSN=mysql://user:pass@localhost/sftp sftpwarden validate --config examples/mysql/sftpwarden.yaml
89
+ SFTPWARDEN_POSTGRES_DSN=postgresql://user:pass@localhost/sftp sftpwarden validate --config examples/postgres/sftpwarden.yaml
90
+
91
+ - name: Validate compose generation
92
+ run: |
93
+ sftpwarden compose --config examples/yaml/sftpwarden.yaml > /tmp/sftpwarden-compose.yml
94
+ test -s /tmp/sftpwarden-compose.yml
@@ -0,0 +1,145 @@
1
+ name: Docker
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "docker/**"
8
+ - "sftpwarden/**"
9
+ - "pyproject.toml"
10
+ - ".dockerignore"
11
+ - ".github/workflows/docker.yml"
12
+
13
+ permissions:
14
+ contents: read
15
+ packages: write
16
+
17
+ env:
18
+ REGISTRY: ghcr.io
19
+ IMAGE_NAME: ${{ github.repository }}
20
+ WATCHER_IMAGE_NAME: ${{ github.repository }}-watcher
21
+
22
+ jobs:
23
+ version:
24
+ runs-on: ubuntu-latest
25
+ outputs:
26
+ changed: ${{ steps.version.outputs.changed }}
27
+ version: ${{ steps.version.outputs.version }}
28
+
29
+ steps:
30
+ - name: Check out repository
31
+ uses: actions/checkout@v7.0.0
32
+ with:
33
+ fetch-depth: 0
34
+
35
+ - name: Check package version change
36
+ id: version
37
+ env:
38
+ BEFORE_SHA: ${{ github.event.before }}
39
+ run: |
40
+ python - <<'PY' >> "$GITHUB_OUTPUT"
41
+ import os
42
+ import subprocess
43
+ import tomllib
44
+ from pathlib import Path
45
+
46
+ def read_version(text: str) -> str:
47
+ return tomllib.loads(text)["project"]["version"]
48
+
49
+ current = read_version(Path("pyproject.toml").read_text(encoding="utf-8"))
50
+ previous = ""
51
+ before = os.environ.get("BEFORE_SHA", "")
52
+ if before and before != "0" * 40:
53
+ result = subprocess.run(
54
+ ["git", "show", f"{before}:pyproject.toml"],
55
+ capture_output=True,
56
+ check=False,
57
+ text=True,
58
+ )
59
+ if result.returncode == 0:
60
+ previous = read_version(result.stdout)
61
+
62
+ changed = previous != current
63
+ print(f"version={current}")
64
+ print(f"previous_version={previous}")
65
+ print(f"changed={str(changed).lower()}")
66
+ PY
67
+
68
+ build:
69
+ needs: version
70
+ if: needs.version.outputs.changed == 'true'
71
+ runs-on: ubuntu-latest
72
+
73
+ steps:
74
+ - name: Check out repository
75
+ uses: actions/checkout@v7.0.0
76
+
77
+ - name: Set up Docker Buildx
78
+ uses: docker/setup-buildx-action@v4.1.0
79
+
80
+ - name: Log in to GHCR
81
+ uses: docker/login-action@v4.2.0
82
+ with:
83
+ registry: ${{ env.REGISTRY }}
84
+ username: ${{ github.actor }}
85
+ password: ${{ secrets.GITHUB_TOKEN }}
86
+
87
+ - name: Runtime metadata
88
+ id: runtime-meta
89
+ uses: docker/metadata-action@v6.1.0
90
+ with:
91
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
92
+ tags: |
93
+ type=raw,value=${{ needs.version.outputs.version }}
94
+ type=raw,value=latest
95
+
96
+ - name: Watcher metadata
97
+ id: watcher-meta
98
+ uses: docker/metadata-action@v6.1.0
99
+ with:
100
+ images: ${{ env.REGISTRY }}/${{ env.WATCHER_IMAGE_NAME }}
101
+ tags: |
102
+ type=raw,value=${{ needs.version.outputs.version }}
103
+ type=raw,value=latest
104
+
105
+ - name: Build runtime image
106
+ uses: docker/build-push-action@v7.2.0
107
+ with:
108
+ context: .
109
+ file: docker/runtime/Dockerfile
110
+ load: true
111
+ tags: sftpwarden:ci
112
+
113
+ - name: Runtime smoke test
114
+ run: |
115
+ docker run --rm --entrypoint sh sftpwarden:ci -c 'command -v sshd && command -v sftpwarden && sftpwarden --version && grep -q "^Port 22$" /etc/ssh/sshd_config'
116
+
117
+ - name: Build watcher image
118
+ uses: docker/build-push-action@v7.2.0
119
+ with:
120
+ context: .
121
+ file: docker/watcher/Dockerfile
122
+ load: true
123
+ tags: sftpwarden-watcher:ci
124
+
125
+ - name: Watcher smoke test
126
+ run: |
127
+ docker run --rm --entrypoint sh sftpwarden-watcher:ci -c 'command -v sftpwarden && sftpwarden --version && test ! -S /var/run/docker.sock'
128
+
129
+ - name: Publish runtime image
130
+ uses: docker/build-push-action@v7.2.0
131
+ with:
132
+ context: .
133
+ file: docker/runtime/Dockerfile
134
+ push: true
135
+ tags: ${{ steps.runtime-meta.outputs.tags }}
136
+ labels: ${{ steps.runtime-meta.outputs.labels }}
137
+
138
+ - name: Publish watcher image
139
+ uses: docker/build-push-action@v7.2.0
140
+ with:
141
+ context: .
142
+ file: docker/watcher/Dockerfile
143
+ push: true
144
+ tags: ${{ steps.watcher-meta.outputs.tags }}
145
+ labels: ${{ steps.watcher-meta.outputs.labels }}
@@ -0,0 +1,60 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "README.md"
8
+ - "CONTRIBUTING.md"
9
+ - "SECURITY.md"
10
+ - "CODE_OF_CONDUCT.md"
11
+ - "docs/**"
12
+ - ".github/workflows/docs.yml"
13
+
14
+ permissions:
15
+ contents: read
16
+ pages: write
17
+ id-token: write
18
+
19
+ concurrency:
20
+ group: pages
21
+ cancel-in-progress: false
22
+
23
+ jobs:
24
+ build:
25
+ runs-on: ubuntu-latest
26
+
27
+ steps:
28
+ - name: Check out repository
29
+ uses: actions/checkout@v7.0.0
30
+
31
+ - name: Set up Python
32
+ uses: actions/setup-python@v6.2.0
33
+ with:
34
+ python-version: "3.13"
35
+ cache: pip
36
+
37
+ - name: Install docs dependencies
38
+ run: |
39
+ python -m pip install --upgrade pip
40
+ python -m pip install -e ".[docs]"
41
+
42
+ - name: Build Sphinx site
43
+ run: sphinx-build -b html docs docs/_build/html
44
+
45
+ - name: Upload Pages artifact
46
+ uses: actions/upload-pages-artifact@v5.0.0
47
+ with:
48
+ path: docs/_build/html
49
+
50
+ deploy:
51
+ needs: build
52
+ runs-on: ubuntu-latest
53
+ environment:
54
+ name: github-pages
55
+ url: ${{ steps.deployment.outputs.page_url }}
56
+
57
+ steps:
58
+ - name: Deploy to GitHub Pages
59
+ id: deployment
60
+ uses: actions/deploy-pages@v5.0.0
@@ -0,0 +1,122 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "sftpwarden/**"
8
+ - "pyproject.toml"
9
+ - "README.md"
10
+ - "LICENSE"
11
+ - "CHANGELOG.md"
12
+ - ".github/workflows/release.yml"
13
+
14
+ permissions:
15
+ contents: write
16
+ id-token: write
17
+
18
+ jobs:
19
+ verify:
20
+ runs-on: ubuntu-latest
21
+ outputs:
22
+ changed: ${{ steps.version.outputs.changed }}
23
+ version: ${{ steps.version.outputs.version }}
24
+
25
+ steps:
26
+ - name: Check out repository
27
+ uses: actions/checkout@v7.0.0
28
+ with:
29
+ fetch-depth: 0
30
+
31
+ - name: Verify package versions and change
32
+ id: version
33
+ env:
34
+ BEFORE_SHA: ${{ github.event.before }}
35
+ run: |
36
+ python - <<'PY' >> "$GITHUB_OUTPUT"
37
+ import os
38
+ import subprocess
39
+ import tomllib
40
+ from pathlib import Path
41
+
42
+ import sftpwarden
43
+
44
+ def read_version(text: str) -> str:
45
+ return tomllib.loads(text)["project"]["version"]
46
+
47
+ package_version = read_version(Path("pyproject.toml").read_text(encoding="utf-8"))
48
+ module_version = sftpwarden.__version__
49
+ if package_version != module_version:
50
+ raise SystemExit(
51
+ f"pyproject={package_version} module={module_version}"
52
+ )
53
+
54
+ previous = ""
55
+ before = os.environ.get("BEFORE_SHA", "")
56
+ if before and before != "0" * 40:
57
+ result = subprocess.run(
58
+ ["git", "show", f"{before}:pyproject.toml"],
59
+ capture_output=True,
60
+ check=False,
61
+ text=True,
62
+ )
63
+ if result.returncode == 0:
64
+ previous = read_version(result.stdout)
65
+
66
+ changed = previous != package_version
67
+ print(f"version={package_version}")
68
+ print(f"previous_version={previous}")
69
+ print(f"changed={str(changed).lower()}")
70
+ PY
71
+
72
+ package:
73
+ needs: verify
74
+ if: needs.verify.outputs.changed == 'true'
75
+ runs-on: ubuntu-latest
76
+ environment:
77
+ name: pypi
78
+ url: https://pypi.org/p/sftpwarden
79
+
80
+ steps:
81
+ - name: Check out repository
82
+ uses: actions/checkout@v7.0.0
83
+
84
+ - name: Set up Python
85
+ uses: actions/setup-python@v6.2.0
86
+ with:
87
+ python-version: "3.13"
88
+ cache: pip
89
+
90
+ - name: Build distributions
91
+ run: |
92
+ python -m pip install --upgrade pip build
93
+ python -m build
94
+
95
+ - name: Upload package artifacts
96
+ uses: actions/upload-artifact@v7.0.1
97
+ with:
98
+ name: python-package
99
+ path: dist/*
100
+
101
+ - name: Publish to PyPI
102
+ uses: pypa/gh-action-pypi-publish@v1.14.0
103
+
104
+ github-release:
105
+ needs: [verify, package]
106
+ if: needs.verify.outputs.changed == 'true'
107
+ runs-on: ubuntu-latest
108
+
109
+ steps:
110
+ - name: Download package artifacts
111
+ uses: actions/download-artifact@v8.0.1
112
+ with:
113
+ name: python-package
114
+ path: dist
115
+
116
+ - name: Create GitHub Release
117
+ uses: softprops/action-gh-release@v3.0.1
118
+ with:
119
+ tag_name: v${{ needs.verify.outputs.version }}
120
+ target_commitish: ${{ github.sha }}
121
+ files: dist/*
122
+ generate_release_notes: true