From 09ca42d604a7a4678fdf2eeafe87a9cf3962235f Mon Sep 17 00:00:00 2001 From: Douglas Date: Sat, 23 Aug 2025 13:52:30 -0700 Subject: [PATCH] Adding deprecation notice (#41) * Adding deprecation notice * Version bump * Fixing version check in CI * Fixing version logic * Changed version string format * Switched pyproject.toml to hard coded version to be modified by pre commit hook * Fix version extraction --- .github/workflows/pr-preview.yml | 52 +++--- .github/workflows/release.yml | 45 +++-- .github/workflows/version-check.yml | 25 +-- .hooks/sync_version.py | 95 +++++++++++ LICENSE | 21 +++ README.rst | 10 ++ pyproject.toml | 253 ++++++++++++++-------------- socketdev/__init__.py | 11 ++ socketdev/version.py | 2 +- 9 files changed, 324 insertions(+), 190 deletions(-) create mode 100755 .hooks/sync_version.py create mode 100644 LICENSE diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index d1f8619..78ba038 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -1,69 +1,63 @@ name: PR Preview on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, ready_for_review] jobs: preview: runs-on: ubuntu-latest permissions: - pull-requests: write - issues: write id-token: write contents: read + pull-requests: write steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: '3.x' # Install all dependencies from pyproject.toml - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . + pip install hatchling==1.27.0 + pip install hatch==1.14.0 - - name: Set preview version - run: | - BASE_VERSION=$(python -c "from socketdev import __version__; print(__version__)") - PREVIEW_VERSION="${BASE_VERSION}.dev${{ github.event.pull_request.number }}${{ github.event.pull_request.commits }}" - echo "VERSION=${PREVIEW_VERSION}" >> $GITHUB_ENV - - # Update version in version.py instead of __init__.py - echo "__version__ = \"${PREVIEW_VERSION}\"" > socketdev/version.py - - # Verify the change - echo "Updated version in version.py:" - cat socketdev/version.py + - name: Inject full dynamic version + run: python .hooks/sync_version.py --dev - name: Check if version exists on Test PyPI id: version_check - env: - VERSION: ${{ env.VERSION }} run: | + VERSION=$(hatch version | cut -d+ -f1) + echo "VERSION=$VERSION" >> $GITHUB_ENV if curl -s -f https://test.pypi.org/pypi/socket-sdk-python/$VERSION/json > /dev/null; then echo "Version ${VERSION} already exists on Test PyPI" echo "exists=true" >> $GITHUB_OUTPUT else - echo "Version ${VERSION} not found on Test PyPI" + echo "Version ${VERSION} not found on Test PyPI - proceeding with test deployment" echo "exists=false" >> $GITHUB_OUTPUT fi - - name: Build package - if: steps.version_check.outputs.exists != 'true' + - name: Clean previous builds + run: rm -rf dist/ build/ *.egg-info + + - name: Get Hatch version + id: version run: | - pip install build - python -m build + VERSION=$(hatch version | cut -d+ -f1) + echo "VERSION=$VERSION" >> $GITHUB_ENV - - name: Restore original version - if: always() + - name: Build package + if: steps.version_check.outputs.exists != 'true' run: | - BASE_VERSION=$(echo $VERSION | cut -d'.' -f1-3) - echo "__version__ = \"${BASE_VERSION}\"" > socketdev/version.py + hatch build - name: Publish to Test PyPI if: steps.version_check.outputs.exists != 'true' - uses: pypa/gh-action-pypi-publish@v1.8.11 + uses: pypa/gh-action-pypi-publish@v1.12.4 with: repository-url: https://test.pypi.org/legacy/ verbose: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2793cc0..3ee1c49 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,7 @@ name: Release on: - push: - tags: - - 'v*' + release: + types: [published] jobs: release: @@ -10,27 +9,28 @@ jobs: permissions: id-token: write contents: read - pull-requests: write - issues: write steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: '3.x' # Install all dependencies from pyproject.toml - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . - + pip install hatchling==1.27.0 + pip install hatch==1.14.0 + - name: Get Version id: version run: | - RAW_VERSION=$(python -c "from socketdev.version import __version__; print(__version__)") + RAW_VERSION=$(hatch version) echo "VERSION=$RAW_VERSION" >> $GITHUB_ENV if [ "v$RAW_VERSION" != "${{ github.ref_name }}" ]; then - echo "Error: Git tag (${{ github.ref_name }}) does not match package version (v$RAW_VERSION)" + echo "Error: Git tag (${{ github.ref_name }}) does not match hatch version (v$RAW_VERSION)" exit 1 fi @@ -50,11 +50,26 @@ jobs: - name: Build package if: steps.version_check.outputs.pypi_exists != 'true' run: | - pip install build - python -m build + hatch build - name: Publish to PyPI if: steps.version_check.outputs.pypi_exists != 'true' - uses: pypa/gh-action-pypi-publish@v1.8.11 - with: - password: ${{ secrets.PYPI_TOKEN }} \ No newline at end of file + uses: pypa/gh-action-pypi-publish@v1.12.4 + + - name: Verify package is installable + id: verify_package + env: + VERSION: ${{ env.VERSION }} + run: | + for i in {1..30}; do + if pip install socket-sdk-python==${VERSION}; then + echo "Package ${VERSION} is now available and installable on PyPI" + pip uninstall -y socket-sdk-python + echo "success=true" >> $GITHUB_OUTPUT + exit 0 + fi + echo "Attempt $i: Package not yet installable, waiting 20s... (${i}/30)" + sleep 20 + done + echo "success=false" >> $GITHUB_OUTPUT + exit 1 \ No newline at end of file diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index 12bbae0..bd36127 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -1,7 +1,7 @@ name: Version Check on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, ready_for_review] paths: - 'socketdev/**' - 'setup.py' @@ -19,22 +19,13 @@ jobs: id: version_check run: | # Get version from current PR - PR_VERSION=$(grep -o '__version__ = "[^"]*"' socketdev/version.py | cut -d'"' -f2) - echo "Debug PR version: $PR_VERSION" - echo "PR_VERSION=${PR_VERSION}" >> $GITHUB_ENV + PR_VERSION=$(grep -o "__version__.*" socketdev/version.py | awk '{print $3}' | tr -d '"' | tr -d "'") + echo "PR_VERSION=$PR_VERSION" >> $GITHUB_ENV - # Get version from main branch - try both locations + # Get version from main branch git checkout origin/main - if [ -f socketdev/version.py ]; then - MAIN_VERSION=$(grep -o '__version__ = "[^"]*"' socketdev/version.py | cut -d'"' -f2) - else - # Fall back to old location in __init__.py - # Use more specific grep to avoid matching the imported version - MAIN_VERSION=$(grep -o '^__version__ = "[^"]*"' socketdev/__init__.py | cut -d'"' -f2) - fi - - echo "Debug main version: $MAIN_VERSION" - echo "MAIN_VERSION=${MAIN_VERSION}" >> $GITHUB_ENV + MAIN_VERSION=$(grep -o "__version__.*" socketdev/version.py | awk '{print $3}' | tr -d '"' | tr -d "'") + echo "MAIN_VERSION=$MAIN_VERSION" >> $GITHUB_ENV # Compare versions using Python python3 -c " @@ -85,7 +76,7 @@ jobs: owner: owner, repo: repo, comment_id: versionComment.id, - body: `❌ **Version Check Failed**\n\nPlease increment the version. Current version in main: ${process.env.MAIN_VERSION}, PR version: ${process.env.PR_VERSION}` + body: `❌ **Version Check Failed**\n\nPlease increment...` }); } } else if (!success) { @@ -94,6 +85,6 @@ jobs: owner: owner, repo: repo, issue_number: prNumber, - body: `❌ **Version Check Failed**\n\nPlease increment the version. Current version in main: ${process.env.MAIN_VERSION}, PR version: ${process.env.PR_VERSION}` + body: `❌ **Version Check Failed**\n\nPlease increment...` }); } \ No newline at end of file diff --git a/.hooks/sync_version.py b/.hooks/sync_version.py new file mode 100755 index 0000000..5c80703 --- /dev/null +++ b/.hooks/sync_version.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +import subprocess +import pathlib +import re +import sys +import urllib.request +import json + +VERSION_FILE = pathlib.Path("socketdev/version.py") +PYPROJECT_FILE = pathlib.Path("pyproject.toml") + +VERSION_PATTERN = re.compile(r"__version__\s*=\s*['\"]([^'\"]+)['\"]") +PYPROJECT_PATTERN = re.compile(r'^version\s*=\s*".*"$', re.MULTILINE) +PYPI_API = "https://test.pypi.org/pypi/socket-sdk-python/json" + +def read_version_from_version_file(path: pathlib.Path) -> str: + content = path.read_text() + match = VERSION_PATTERN.search(content) + if not match: + print(f"❌ Could not find __version__ in {path}") + sys.exit(1) + return match.group(1) + +def read_version_from_git(path: str) -> str: + try: + output = subprocess.check_output(["git", "show", f"HEAD:{path}"], text=True) + match = VERSION_PATTERN.search(output) + if not match: + return None + return match.group(1) + except subprocess.CalledProcessError: + return None + +def bump_patch_version(version: str) -> str: + if ".dev" in version: + version = version.split(".dev")[0] + parts = version.split(".") + parts[-1] = str(int(parts[-1]) + 1) + return ".".join(parts) + +def fetch_existing_versions() -> set: + try: + with urllib.request.urlopen(PYPI_API) as response: + data = json.load(response) + return set(data.get("releases", {}).keys()) + except Exception as e: + print(f"⚠️ Warning: Failed to fetch existing versions from Test PyPI: {e}") + return set() + +def find_next_available_dev_version(base_version: str) -> str: + existing_versions = fetch_existing_versions() + for i in range(1, 100): + candidate = f"{base_version}.dev{i}" + if candidate not in existing_versions: + return candidate + print("❌ Could not find available .devN slot after 100 attempts.") + sys.exit(1) + +def inject_version(version: str): + print(f"🔁 Updating version to: {version}") + + # Update version.py + VERSION_FILE.write_text(f'__version__ = "{version}"\n') + + # Update pyproject.toml if it has a version field (it shouldn't with hatch, but just in case) + pyproject = PYPROJECT_FILE.read_text() + if PYPROJECT_PATTERN.search(pyproject): + new_pyproject = PYPROJECT_PATTERN.sub(f'version = "{version}"', pyproject) + PYPROJECT_FILE.write_text(new_pyproject) + +def main(): + dev_mode = "--dev" in sys.argv + current_version = read_version_from_version_file(VERSION_FILE) + previous_version = read_version_from_git("socketdev/version.py") + + print(f"Current: {current_version}, Previous: {previous_version}") + + if current_version == previous_version: + if dev_mode: + base_version = current_version.split(".dev")[0] if ".dev" in current_version else current_version + new_version = find_next_available_dev_version(base_version) + inject_version(new_version) + print("⚠️ Version was unchanged — auto-bumped. Please git add + commit again.") + sys.exit(0) + else: + new_version = bump_patch_version(current_version) + inject_version(new_version) + print("⚠️ Version was unchanged — auto-bumped. Please git add + commit again.") + sys.exit(1) + else: + print("✅ Version already bumped — proceeding.") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94bff6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Socket Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.rst b/README.rst index b5a1595..f3e0756 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,16 @@ socket-python-sdk ################# +.. warning:: + **DEPRECATED**: This package is deprecated. Please migrate to the new ``socketdev`` package: + + .. code-block:: bash + + pip uninstall socket-sdk-python + pip install socketdev + + The API remains exactly the same, only the package name has changed. This package will no longer receive updates. + Purpose ------- diff --git a/pyproject.toml b/pyproject.toml index e16df1f..712ebab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,129 +1,126 @@ -[build-system] -requires = [ - "setuptools==68.2.2", - "wheel" -] -build-backend = "setuptools.build_meta" - -[project] -name = "socket-sdk-python" -dynamic = ["version"] -requires-python = ">= 3.9" -dependencies = [ - 'requests', - 'typing-extensions>=4.12.2' -] -readme = "README.rst" -license = {text = "MIT"} -description = "Socket Security Python SDK" -keywords = ["socketsecurity", "socket.dev", "sca", "oss", "security", "sdk"] -authors = [ - {name = "Douglas Coburn", email = "douglas@socket.dev"} -] -maintainers = [ - {name = "Douglas Coburn", email = "douglas@socket.dev"} -] -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14" -] - -# modern, faster linter and language server. install with `pip install -e ".[dev]"` -[project.optional-dependencies] -dev = [ - "ruff>=0.3.0", - "twine>=4.0.0", - "wheel>=0.40.0", - "build>=1.0.0" -] -test = [ - "pytest>=7.0.0", - "pytest-cov>=4.0.0" -] - -[project.urls] -Homepage = "https://github.com/socketdev/socket-sdk-python" - -[tool.setuptools.packages.find] -include = ["socketdev", "socketdev.*"] - -[tool.setuptools.dynamic] -version = {attr = "socketdev.version.__version__"} - -[tool.ruff] -# Exclude a variety of commonly ignored directories. -exclude = [ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".git-rewrite", - ".hg", - ".ipynb_checkpoints", - ".mypy_cache", - ".nox", - ".pants.d", - ".pyenv", - ".pytest_cache", - ".pytype", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - ".vscode", - "__pypackages__", - "_build", - "buck-out", - "build", - "dist", - "node_modules", - "site-packages", - "venv", -] - -[tool.ruff.lint] -# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. -# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or -# McCabe complexity (`C901`) by default. -select = ["E4", "E7", "E9", "F"] -ignore = [] - -# Allow fix for all enabled rules (when `--fix`) is provided. -fixable = ["ALL"] -unfixable = [] - -# Allow unused variables when underscore-prefixed. -dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" - -[tool.ruff.format] -# Like Black, use double quotes for strings. -quote-style = "double" - -# Like Black, indent with spaces, rather than tabs. -indent-style = "space" - -# Like Black, respect magic trailing commas. -skip-magic-trailing-comma = false - -# Like Black, automatically detect the appropriate line ending. -line-ending = "auto" - -# Enable auto-formatting of code examples in docstrings. Markdown, -# reStructuredText code/literal blocks and doctests are all supported. -# -# This is currently disabled by default, but it is planned for this -# to be opt-out in the future. -docstring-code-format = false - -# Set the line length limit used when formatting code snippets in -# docstrings. -# -# This only has an effect when the `docstring-code-format` setting is -# enabled. +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "socket-sdk-python" +version = "2.2.3" +requires-python = ">= 3.9" +dependencies = [ + 'requests', + 'typing-extensions>=4.12.2' +] +readme = "README.rst" +license = {file = "LICENSE"} +description = "Socket Security Python SDK [DEPRECATED: Please use 'socketdev' package instead]" +keywords = ["socketsecurity", "socket.dev", "sca", "oss", "security", "sdk"] +authors = [ + {name = "Douglas Coburn", email = "douglas@socket.dev"} +] +maintainers = [ + {name = "Douglas Coburn", email = "douglas@socket.dev"} +] +classifiers = [ + "Development Status :: 7 - Inactive", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14" +] + +[tool.hatch.version] +path = "socketdev/version.py" + +[tool.hatch.build.targets.wheel] +packages = ["socketdev"] + +# modern, faster linter and language server. install with `pip install -e ".[dev]"` +[project.optional-dependencies] +dev = [ + "ruff>=0.3.0", + "hatch>=1.14.0", + "hatchling>=1.27.0", + "twine>=4.0.0" +] +test = [ + "pytest>=7.0.0", + "pytest-cov>=4.0.0" +] + +[project.urls] +Homepage = "https://github.com/socketdev/socket-sdk-python" + +[tool.ruff] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +[tool.ruff.lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +select = ["E4", "E7", "E9", "F"] +ignore = [] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +# Enable auto-formatting of code examples in docstrings. Markdown, +# reStructuredText code/literal blocks and doctests are all supported. +# +# This is currently disabled by default, but it is planned for this +# to be opt-out in the future. +docstring-code-format = false + +# Set the line length limit used when formatting code snippets in +# docstrings. +# +# This only has an effect when the `docstring-code-format` setting is +# enabled. docstring-code-line-length = "dynamic" \ No newline at end of file diff --git a/socketdev/__init__.py b/socketdev/__init__.py index e52e642..473fbcf 100644 --- a/socketdev/__init__.py +++ b/socketdev/__init__.py @@ -20,8 +20,19 @@ from socketdev.labels import Labels from socketdev.licensemetadata import LicenseMetadata from socketdev.log import log +import warnings +# Deprecation warning for socket-sdk-python package +warnings.warn( + "The 'socket-sdk-python' package is deprecated and will no longer receive updates. " + "Please migrate to the new 'socketdev' package: pip install socketdev. " + "The API remains the same, only the package name has changed. " + "For more information, see: https://github.com/SocketDev/socket-sdk-python", + DeprecationWarning, + stacklevel=2 +) + __author__ = "socket.dev" __version__ = __version__ __all__ = ["socketdev", "Utils", "IntegrationType", "INTEGRATION_TYPES"] diff --git a/socketdev/version.py b/socketdev/version.py index c377db3..f394e69 100644 --- a/socketdev/version.py +++ b/socketdev/version.py @@ -1 +1 @@ -__version__ = "2.1.8" +__version__ = "2.2.3"