puba 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.
puba-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: puba
3
+ Version: 0.1.0
4
+ Summary: Safe Python package release CLI
5
+ Author: Griffin McManus
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: keyring>=23.0
9
+
10
+ # puba
11
+
12
+ **Safe Python Package Release CLI**
13
+
14
+ A minimal, dependency-free CLI to safely check, build, and publish Python packages without risking secrets.
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - Ensure git working directory is clean before releasing
21
+ - Scan for secrets in the repo before publishing
22
+ - Run tests automatically (via `pytest` if installed)
23
+ - Build the package (`python -m build`)
24
+ - Safely upload to PyPI or TestPyPI
25
+ - Store your PyPI token securely in **macOS Keychain**, **Windows Credential Manager**, or Linux keyring
26
+ - Dry run mode for testing builds without uploading
27
+ - `checks` command to validate the repo without publishing
28
+ - No external dependencies required for CLI parsing
29
+
30
+ ---
31
+
32
+ ## Usage
33
+
34
+ ### 1️⃣ Store PyPI token securely
35
+
36
+ ```bash
37
+ puba auth
38
+ ```
39
+
40
+ - On macOS → stored in Keychain
41
+ - On Windows → stored in Credential Manager
42
+ - On Linux → stored in system keyring if available
43
+ - Fallback → prompts you for input each time
44
+
45
+ ---
46
+
47
+ ### 2️⃣ Install optional dev tools (for tests, builds, and publishing)
48
+
49
+ If you want to run tests, build packages, or publish safely, install optional dependencies:
50
+
51
+ ```bash
52
+ # zsh users: quote the extras to avoid glob errors
53
+ pip install ".[dev]"
54
+ ```
55
+
56
+ - Installs: `pytest`, `build`, `twine`
57
+ - You can also install subsets:
58
+ ```bash
59
+ pip install ".[test]" # only pytest
60
+ pip install ".[build]" # only build and twine
61
+ ```
62
+
63
+ ---
64
+
65
+ ### 3️⃣ Run safety checks only
66
+
67
+ ```bash
68
+ puba checks
69
+ ```
70
+
71
+ Checks performed:
72
+
73
+ - Git working directory is clean
74
+ - Secret scan (requires `gitleaks`)
75
+ - Runs tests (`pytest`)
76
+ - Builds the package
77
+
78
+ > No upload occurs in this step.
79
+
80
+ ---
81
+
82
+ ### 4️⃣ Publish package
83
+
84
+ ```bash
85
+ puba publish
86
+ ```
87
+
88
+ **Options:**
89
+
90
+ - `--test` → Upload to **TestPyPI** instead of PyPI
91
+ - `--dry` → Run all checks and build without uploading
92
+
93
+ **Examples:**
94
+
95
+ ```bash
96
+ # Standard release
97
+ puba publish
98
+
99
+ # Upload to TestPyPI
100
+ puba publish --test
101
+
102
+ # Dry run (check + build only)
103
+ puba publish --dry
104
+ ```
105
+
106
+ ---
107
+
108
+ ### 5️⃣ Help
109
+
110
+ ```bash
111
+ puba help
112
+ ```
113
+
114
+ Displays usage instructions and available commands.
115
+
116
+ ---
117
+
118
+ ## Example Workflow
119
+
120
+ ```
121
+ +----------------+
122
+ | puba auth |
123
+ +----------------+
124
+ |
125
+ v
126
+ +------------------+
127
+ | puba checks |
128
+ +------------------+
129
+ |
130
+ v
131
+ +-------------------+
132
+ | puba publish |
133
+ +-------------------+
134
+ ```
135
+
136
+ 1. Store token (one-time)
137
+ 2. Check repo before release
138
+ 3. Publish safely
139
+
140
+ Optional: test PyPI or dry-run:
141
+ ```bash
142
+ puba publish --test
143
+ puba publish --dry
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Notes
149
+
150
+ - **Secrets are never committed** — always stored in system keyring or provided via environment variable `PYPI_TOKEN`.
151
+ - Works on **macOS, Windows, and Linux**.
152
+ - Can be integrated into **CI/CD pipelines** with environment variables:
153
+
154
+ ```bash
155
+ export PYPI_TOKEN=pypi-xxxxxxxxxxxx
156
+ puba publish --dry
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Recommended Tools (Optional)
162
+
163
+ - `pytest` → for running tests automatically
164
+ - `gitleaks` → for scanning secrets before publishing
165
+ - `build` → Python build system (`pip install build`)
166
+ - `twine` → for uploading packages (`pip install twine`)
167
+
puba-0.1.0/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # puba
2
+
3
+ **Safe Python Package Release CLI**
4
+
5
+ A minimal, dependency-free CLI to safely check, build, and publish Python packages without risking secrets.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - Ensure git working directory is clean before releasing
12
+ - Scan for secrets in the repo before publishing
13
+ - Run tests automatically (via `pytest` if installed)
14
+ - Build the package (`python -m build`)
15
+ - Safely upload to PyPI or TestPyPI
16
+ - Store your PyPI token securely in **macOS Keychain**, **Windows Credential Manager**, or Linux keyring
17
+ - Dry run mode for testing builds without uploading
18
+ - `checks` command to validate the repo without publishing
19
+ - No external dependencies required for CLI parsing
20
+
21
+ ---
22
+
23
+ ## Usage
24
+
25
+ ### 1️⃣ Store PyPI token securely
26
+
27
+ ```bash
28
+ puba auth
29
+ ```
30
+
31
+ - On macOS → stored in Keychain
32
+ - On Windows → stored in Credential Manager
33
+ - On Linux → stored in system keyring if available
34
+ - Fallback → prompts you for input each time
35
+
36
+ ---
37
+
38
+ ### 2️⃣ Install optional dev tools (for tests, builds, and publishing)
39
+
40
+ If you want to run tests, build packages, or publish safely, install optional dependencies:
41
+
42
+ ```bash
43
+ # zsh users: quote the extras to avoid glob errors
44
+ pip install ".[dev]"
45
+ ```
46
+
47
+ - Installs: `pytest`, `build`, `twine`
48
+ - You can also install subsets:
49
+ ```bash
50
+ pip install ".[test]" # only pytest
51
+ pip install ".[build]" # only build and twine
52
+ ```
53
+
54
+ ---
55
+
56
+ ### 3️⃣ Run safety checks only
57
+
58
+ ```bash
59
+ puba checks
60
+ ```
61
+
62
+ Checks performed:
63
+
64
+ - Git working directory is clean
65
+ - Secret scan (requires `gitleaks`)
66
+ - Runs tests (`pytest`)
67
+ - Builds the package
68
+
69
+ > No upload occurs in this step.
70
+
71
+ ---
72
+
73
+ ### 4️⃣ Publish package
74
+
75
+ ```bash
76
+ puba publish
77
+ ```
78
+
79
+ **Options:**
80
+
81
+ - `--test` → Upload to **TestPyPI** instead of PyPI
82
+ - `--dry` → Run all checks and build without uploading
83
+
84
+ **Examples:**
85
+
86
+ ```bash
87
+ # Standard release
88
+ puba publish
89
+
90
+ # Upload to TestPyPI
91
+ puba publish --test
92
+
93
+ # Dry run (check + build only)
94
+ puba publish --dry
95
+ ```
96
+
97
+ ---
98
+
99
+ ### 5️⃣ Help
100
+
101
+ ```bash
102
+ puba help
103
+ ```
104
+
105
+ Displays usage instructions and available commands.
106
+
107
+ ---
108
+
109
+ ## Example Workflow
110
+
111
+ ```
112
+ +----------------+
113
+ | puba auth |
114
+ +----------------+
115
+ |
116
+ v
117
+ +------------------+
118
+ | puba checks |
119
+ +------------------+
120
+ |
121
+ v
122
+ +-------------------+
123
+ | puba publish |
124
+ +-------------------+
125
+ ```
126
+
127
+ 1. Store token (one-time)
128
+ 2. Check repo before release
129
+ 3. Publish safely
130
+
131
+ Optional: test PyPI or dry-run:
132
+ ```bash
133
+ puba publish --test
134
+ puba publish --dry
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Notes
140
+
141
+ - **Secrets are never committed** — always stored in system keyring or provided via environment variable `PYPI_TOKEN`.
142
+ - Works on **macOS, Windows, and Linux**.
143
+ - Can be integrated into **CI/CD pipelines** with environment variables:
144
+
145
+ ```bash
146
+ export PYPI_TOKEN=pypi-xxxxxxxxxxxx
147
+ puba publish --dry
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Recommended Tools (Optional)
153
+
154
+ - `pytest` → for running tests automatically
155
+ - `gitleaks` → for scanning secrets before publishing
156
+ - `build` → Python build system (`pip install build`)
157
+ - `twine` → for uploading packages (`pip install twine`)
158
+
File without changes
@@ -0,0 +1,32 @@
1
+ import subprocess
2
+ import shutil
3
+
4
+
5
+ def build_package():
6
+
7
+ shutil.rmtree("dist", ignore_errors=True)
8
+ shutil.rmtree("build", ignore_errors=True)
9
+
10
+ subprocess.run(["python", "-m", "build"], check=True)
11
+
12
+
13
+ def upload_package(token, test=False):
14
+
15
+ repo = "testpypi" if test else "pypi"
16
+
17
+ subprocess.run(
18
+ [
19
+ "python",
20
+ "-m",
21
+ "twine",
22
+ "upload",
23
+ "--repository",
24
+ repo,
25
+ "dist/*",
26
+ "-u",
27
+ "__token__",
28
+ "-p",
29
+ token,
30
+ ],
31
+ check=True,
32
+ )
@@ -0,0 +1,63 @@
1
+ import subprocess
2
+ import importlib.util
3
+ import sys
4
+
5
+ DEV_DEPS = ["build", "twine"]
6
+
7
+
8
+ def check_installs():
9
+ missing = []
10
+
11
+ for tool in DEV_DEPS:
12
+ if importlib.util.find_spec(tool) is None:
13
+ missing.append(tool)
14
+
15
+ if not missing:
16
+ return
17
+
18
+ print(f"⚠️ Missing required tools: {', '.join(missing)}")
19
+
20
+ response = input("Install them now? [y/N]: ").strip().lower()
21
+
22
+ if response != "y":
23
+ print("Install manually with: pip install build twine")
24
+ sys.exit(1)
25
+
26
+ try:
27
+ subprocess.check_call([sys.executable, "-m", "pip", "install", *missing])
28
+ print("✅ Dev tools installed.")
29
+ except subprocess.CalledProcessError:
30
+ print("❌ Failed to install dev tools.")
31
+ sys.exit(1)
32
+
33
+
34
+ def run_secret_scan():
35
+
36
+ try:
37
+ subprocess.run(["gitleaks", "detect", "--no-git"], check=True)
38
+ except FileNotFoundError:
39
+ print("gitleaks not installed — skipping secret scan")
40
+
41
+
42
+ import subprocess
43
+
44
+
45
+ def run_secret_scan():
46
+ try:
47
+ subprocess.run(["gitleaks", "detect", "--no-git"], check=True)
48
+ except FileNotFoundError:
49
+ print("gitleaks not installed — skipping secret scan")
50
+
51
+
52
+ def run_tests():
53
+ """Run pytest if available. Skip if no tests are found."""
54
+ try:
55
+ result = subprocess.run(["pytest"], capture_output=True, text=True)
56
+ if result.returncode == 5:
57
+ print("No tests found — skipping test step.")
58
+ elif result.returncode != 0:
59
+ raise RuntimeError(f"Tests failed with exit code {result.returncode}")
60
+ else:
61
+ print("Tests passed successfully.")
62
+ except FileNotFoundError:
63
+ print("pytest not installed — skipping tests.")
puba-0.1.0/puba/cli.py ADDED
@@ -0,0 +1,48 @@
1
+ import sys
2
+ from .pipeline import release, run_checks_only
3
+ from .secrets import store_token
4
+
5
+ HELP_TEXT = """
6
+ pyrelease - Safe Python package release tool
7
+
8
+ Commands:
9
+ auth Store PyPI token securely
10
+ checks Run safety checks only (git, secrets, tests)
11
+ publish Build and upload your package safely
12
+ Options:
13
+ --test Upload to TestPyPI
14
+ --dry Run checks and build without uploading
15
+ help Show this help message
16
+ """
17
+
18
+
19
+ def main():
20
+ if len(sys.argv) < 2:
21
+ print(HELP_TEXT)
22
+ sys.exit(0)
23
+
24
+ cmd = sys.argv[1].lower()
25
+ options = sys.argv[2:]
26
+
27
+ if cmd == "auth":
28
+ store_token()
29
+
30
+ elif cmd == "checks":
31
+ run_checks_only()
32
+
33
+ elif cmd == "publish":
34
+ test = "--test" in options
35
+ dry = "--dry" in options
36
+ release(test=test, dry=dry)
37
+
38
+ elif cmd == "help":
39
+ print(HELP_TEXT)
40
+
41
+ else:
42
+ print(f"Unknown command: {cmd}\n")
43
+ print(HELP_TEXT)
44
+ sys.exit(1)
45
+
46
+
47
+ if __name__ == "__main__":
48
+ main()
puba-0.1.0/puba/git.py ADDED
@@ -0,0 +1,11 @@
1
+ import subprocess
2
+ import sys
3
+
4
+
5
+ def ensure_clean_repo():
6
+
7
+ result = subprocess.check_output(["git", "status", "--porcelain"]).decode()
8
+
9
+ if result.strip():
10
+ print("Git working directory not clean.")
11
+ sys.exit(1)
@@ -0,0 +1,55 @@
1
+ from .git import ensure_clean_repo
2
+ from .checks import run_secret_scan, run_tests, check_installs
3
+ from .build import build_package, upload_package
4
+ from .secrets import get_pypi_token
5
+
6
+
7
+ def release(test=False, dry=False):
8
+ print(f"Checking installs...")
9
+ check_installs()
10
+
11
+ print("Checking git state...")
12
+ ensure_clean_repo()
13
+
14
+ print("Scanning for secrets...")
15
+ run_secret_scan()
16
+
17
+ print("Running tests...")
18
+ run_tests()
19
+
20
+ print("Building package...")
21
+ build_package()
22
+
23
+ if dry:
24
+ print("Dry run complete")
25
+ return
26
+
27
+ token = get_pypi_token()
28
+
29
+ print("Uploading package...")
30
+ upload_package(token, test)
31
+
32
+ print("Release complete")
33
+
34
+
35
+ def run_checks_only():
36
+ """
37
+ Run safety checks without uploading package.
38
+ Useful for CI or pre-release verification.
39
+ """
40
+ print(f"Checking installs...")
41
+ check_installs()
42
+
43
+ print("Checking git state...")
44
+ ensure_clean_repo()
45
+
46
+ print("Scanning for secrets...")
47
+ run_secret_scan()
48
+
49
+ print("Running tests...")
50
+ run_tests()
51
+
52
+ print("Building package...")
53
+ build_package()
54
+
55
+ print("All checks passed. Package is ready for release.")
@@ -0,0 +1,56 @@
1
+ import os
2
+ import keyring
3
+ import getpass
4
+ import platform
5
+
6
+ SERVICE = "puba"
7
+
8
+
9
+ def get_pypi_token():
10
+ """
11
+ Retrieve the PyPI token safely.
12
+ Order:
13
+ 1. Environment variable
14
+ 2. Keyring
15
+ 3. Prompt user
16
+ """
17
+ # 1. Env var
18
+ token = os.getenv("PYPI_TOKEN")
19
+ if token:
20
+ print("Using PyPI token from environment variable.")
21
+ return token
22
+
23
+ # 2. Keyring
24
+ token = keyring.get_password(SERVICE, "puba")
25
+ if token:
26
+ backend = keyring.get_keyring()
27
+ print(f"Using PyPI token stored in {backend}.")
28
+ return token
29
+
30
+ # 3. Prompt
31
+ token = getpass.getpass("Enter PyPI token: ")
32
+ return token
33
+
34
+
35
+ def store_token():
36
+ """
37
+ Prompt the user for PyPI token and store it securely.
38
+ """
39
+ token = getpass.getpass("Enter PyPI token: ")
40
+
41
+ keyring.set_password(SERVICE, "puba", token)
42
+
43
+ system = platform.system()
44
+
45
+ if system == "Darwin":
46
+ location = "macOS Keychain"
47
+ elif system == "Windows":
48
+ location = "Windows Credential Manager"
49
+ elif system == "Linux":
50
+ location = "Linux Keyring backend (may vary)"
51
+ else:
52
+ location = "Unknown secure store"
53
+
54
+ print(
55
+ f"PyPI token stored securely in {location}. You can now run 'pyrelease publish' without re-entering it."
56
+ )
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: puba
3
+ Version: 0.1.0
4
+ Summary: Safe Python package release CLI
5
+ Author: Griffin McManus
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: keyring>=23.0
9
+
10
+ # puba
11
+
12
+ **Safe Python Package Release CLI**
13
+
14
+ A minimal, dependency-free CLI to safely check, build, and publish Python packages without risking secrets.
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - Ensure git working directory is clean before releasing
21
+ - Scan for secrets in the repo before publishing
22
+ - Run tests automatically (via `pytest` if installed)
23
+ - Build the package (`python -m build`)
24
+ - Safely upload to PyPI or TestPyPI
25
+ - Store your PyPI token securely in **macOS Keychain**, **Windows Credential Manager**, or Linux keyring
26
+ - Dry run mode for testing builds without uploading
27
+ - `checks` command to validate the repo without publishing
28
+ - No external dependencies required for CLI parsing
29
+
30
+ ---
31
+
32
+ ## Usage
33
+
34
+ ### 1️⃣ Store PyPI token securely
35
+
36
+ ```bash
37
+ puba auth
38
+ ```
39
+
40
+ - On macOS → stored in Keychain
41
+ - On Windows → stored in Credential Manager
42
+ - On Linux → stored in system keyring if available
43
+ - Fallback → prompts you for input each time
44
+
45
+ ---
46
+
47
+ ### 2️⃣ Install optional dev tools (for tests, builds, and publishing)
48
+
49
+ If you want to run tests, build packages, or publish safely, install optional dependencies:
50
+
51
+ ```bash
52
+ # zsh users: quote the extras to avoid glob errors
53
+ pip install ".[dev]"
54
+ ```
55
+
56
+ - Installs: `pytest`, `build`, `twine`
57
+ - You can also install subsets:
58
+ ```bash
59
+ pip install ".[test]" # only pytest
60
+ pip install ".[build]" # only build and twine
61
+ ```
62
+
63
+ ---
64
+
65
+ ### 3️⃣ Run safety checks only
66
+
67
+ ```bash
68
+ puba checks
69
+ ```
70
+
71
+ Checks performed:
72
+
73
+ - Git working directory is clean
74
+ - Secret scan (requires `gitleaks`)
75
+ - Runs tests (`pytest`)
76
+ - Builds the package
77
+
78
+ > No upload occurs in this step.
79
+
80
+ ---
81
+
82
+ ### 4️⃣ Publish package
83
+
84
+ ```bash
85
+ puba publish
86
+ ```
87
+
88
+ **Options:**
89
+
90
+ - `--test` → Upload to **TestPyPI** instead of PyPI
91
+ - `--dry` → Run all checks and build without uploading
92
+
93
+ **Examples:**
94
+
95
+ ```bash
96
+ # Standard release
97
+ puba publish
98
+
99
+ # Upload to TestPyPI
100
+ puba publish --test
101
+
102
+ # Dry run (check + build only)
103
+ puba publish --dry
104
+ ```
105
+
106
+ ---
107
+
108
+ ### 5️⃣ Help
109
+
110
+ ```bash
111
+ puba help
112
+ ```
113
+
114
+ Displays usage instructions and available commands.
115
+
116
+ ---
117
+
118
+ ## Example Workflow
119
+
120
+ ```
121
+ +----------------+
122
+ | puba auth |
123
+ +----------------+
124
+ |
125
+ v
126
+ +------------------+
127
+ | puba checks |
128
+ +------------------+
129
+ |
130
+ v
131
+ +-------------------+
132
+ | puba publish |
133
+ +-------------------+
134
+ ```
135
+
136
+ 1. Store token (one-time)
137
+ 2. Check repo before release
138
+ 3. Publish safely
139
+
140
+ Optional: test PyPI or dry-run:
141
+ ```bash
142
+ puba publish --test
143
+ puba publish --dry
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Notes
149
+
150
+ - **Secrets are never committed** — always stored in system keyring or provided via environment variable `PYPI_TOKEN`.
151
+ - Works on **macOS, Windows, and Linux**.
152
+ - Can be integrated into **CI/CD pipelines** with environment variables:
153
+
154
+ ```bash
155
+ export PYPI_TOKEN=pypi-xxxxxxxxxxxx
156
+ puba publish --dry
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Recommended Tools (Optional)
162
+
163
+ - `pytest` → for running tests automatically
164
+ - `gitleaks` → for scanning secrets before publishing
165
+ - `build` → Python build system (`pip install build`)
166
+ - `twine` → for uploading packages (`pip install twine`)
167
+
@@ -0,0 +1,15 @@
1
+ README.md
2
+ pyproject.toml
3
+ puba/__init__.py
4
+ puba/build.py
5
+ puba/checks.py
6
+ puba/cli.py
7
+ puba/git.py
8
+ puba/pipeline.py
9
+ puba/secrets.py
10
+ puba.egg-info/PKG-INFO
11
+ puba.egg-info/SOURCES.txt
12
+ puba.egg-info/dependency_links.txt
13
+ puba.egg-info/entry_points.txt
14
+ puba.egg-info/requires.txt
15
+ puba.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ puba = puba.cli:main
@@ -0,0 +1 @@
1
+ keyring>=23.0
@@ -0,0 +1 @@
1
+ puba
@@ -0,0 +1,23 @@
1
+ [project]
2
+ name = "puba"
3
+ version = "0.1.0"
4
+ description = "Safe Python package release CLI"
5
+ readme = "README.md"
6
+ authors = [{name = "Griffin McManus"}]
7
+ requires-python = ">=3.9"
8
+ dependencies = [
9
+ "keyring>=23.0" # secure token storage (runtime dependency)
10
+ ]
11
+
12
+ [project.scripts]
13
+ puba = "puba.cli:main"
14
+
15
+ # Optional dependencies for development, testing, and publishing
16
+ [project.optional-dependencies]
17
+
18
+ [build-system]
19
+ requires = [
20
+ "setuptools>=61.0",
21
+ "wheel>=0.37"
22
+ ]
23
+ build-backend = "setuptools.build_meta"
puba-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+