diff --git a/.github/workflows/prep-release.yml b/.github/workflows/prep-release.yml new file mode 100644 index 00000000..df151882 --- /dev/null +++ b/.github/workflows/prep-release.yml @@ -0,0 +1,52 @@ +name: Prep Release + +on: + workflow_dispatch: + inputs: + version: + description: "Version number:" + required: true + type: string + build_number: + description: "Build number:" + required: true + type: string + +jobs: + prepare-release: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/heads/sdk-core/') # Only run on branches that start with sdk-core/ + steps: + - name: Checkout the code + uses: actions/checkout@v4 + + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: true + - name: Setup Git User + run: | + git config --global user.email "${{ steps.import-gpg.outputs.email }}" + git config --global user.name "${{ steps.import-gpg.outputs.name }}" + + - name: Parse and Validate Inputs + id: get_inputs + run: | + # Get inputs passed to the workflow + VERSION="${{ github.event.inputs.version }}" + BUILD_NUMBER="${{ github.event.inputs.build_number }}" + + # Save the parsed values for future steps + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_ENV + shell: bash + + - name: Run the Prep Release Script + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + make prep-release VERSION="$VERSION" BUILD_NUMBER="$BUILD_NUMBER" + shell: bash diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..deae2581 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: Release SDK + +on: + workflow_dispatch: + +jobs: + Release-SDK: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/heads/sdk-core/') # Only run on branches that start with sdk-core/ + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: true + - name: Setup Git User + run: | + git config --global user.email "${{ steps.import-gpg.outputs.email }}" + git config --global user.name "${{ steps.import-gpg.outputs.name }}" + + - name: Run the Release Script + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: make release + shell: bash diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml new file mode 100644 index 00000000..2f225c58 --- /dev/null +++ b/.github/workflows/wheels.yml @@ -0,0 +1,101 @@ +name: Wheels Builder and Publisher +on: + pull_request: + branches: + - main + types: + - closed + +jobs: + build_wheels: + name: Build wheels for Python SDK on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + if: github.event.pull_request.merged == true && contains(github.event.pull_request.head.ref, 'sdk-core/') + strategy: + fail-fast: false + matrix: + # macOS 13 is an Intel runner and macOS 14 is an Apple Silicon runner + os: [ubuntu-22.04, ubuntu-22.04-arm, windows-latest, macos-13, macos-14] + steps: + - uses: actions/checkout@v4 + - name: Upgrade build dependencies + run: python -m pip install --upgrade pip setuptools wheel + + + # Need to grab the SDK version for the wheel name + - name: Extract SDK Version + run: echo "SDK_VERSION=$(cat version.txt)" >> "$GITHUB_ENV" + shell: bash + + - name: Install cibuildwheel + run: | + python -m pip install cibuildwheel + + - name: Build wheels + env: + CIBW_SKIP: pp* *-musllinux_* + CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux_2_34_x86_64" + CIBW_MANYLINUX_AARCH64_IMAGE: "quay.io/pypa/manylinux_2_34_aarch64" + CIBW_ARCHS: "native" # Equivalent to python's platform.machine() + CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel" + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -w {dest_dir} {wheel}" + CIBW_TEST_REQUIRES: "pydantic pytest pytest-asyncio" + MACOSX_DEPLOYMENT_TARGET: "12.0" + CIBW_TEST_COMMAND: "python -m pytest {project}/src/onepassword/test_client.py" + OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TEST_SERVICE_ACCOUNT_TOKEN }} + CIBW_ENVIRONMENT_PASS_LINUX: OP_SERVICE_ACCOUNT_TOKEN # We have to specify this to pass the token to the test command + run: | + python -m cibuildwheel --output-dir dist + + - uses: actions/upload-artifact@v4 + with: + name: onepassword-sdk-${{ env.SDK_VERSION }}-${{ matrix.os }} + path: ./dist/*.whl + + build-sdist: + name: Build source distribution for Python SDK + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true && contains(github.event.pull_request.head.ref, 'sdk-core/') + steps: + - uses: actions/checkout@v4 + # Need to grab the SDK version for the wheel name + - name: Extract SDK Version + run: echo "SDK_VERSION=$(cat version.txt)" >> "$GITHUB_ENV" + shell: bash + + - name: Install dependencies + run: pip3 install build pydantic pytest pytest-asyncio + + - name: Build source distribution + run: python3 -m build --sdist + + - name: Test Source Distribution + env: + OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TEST_SERVICE_ACCOUNT_TOKEN }} + run: | + python3 -m pip install dist/*.tar.gz + python3 -m pytest src/onepassword/test_client.py + + - uses: actions/upload-artifact@v4 + with: + name: onepassword-sdk-${{ env.SDK_VERSION }} + path: ./dist/*.tar.gz + + publish-to-pypi: + name: Publish to PyPI + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true && contains(github.event.pull_request.head.ref, 'sdk-core/') + environment: + name: pypi + url: https://pypi.org/project/onepassword-sdk/ + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + needs: [build_wheels, build-sdist] + steps: + - uses: actions/download-artifact@v4 + with: + pattern: onepassword-sdk-* + path: ./dist + merge-multiple: true + - name: Publish package distributions to PyPi + uses: pypa/gh-action-pypi-publish@release/v1.12 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..0fccf23b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,33 @@ +[build-system] +requires = ["setuptools>=66", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "onepassword-sdk" +dynamic = ["version"] +description = "The 1Password Python SDK offers programmatic read access to your secrets in 1Password in an interface native to Python." +authors = [{ name = "1Password" }] +license = { file = "LICENSE" } +readme = "README.md" +requires-python = ">=3.9" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Operating System :: MacOS", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "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", + "License :: OSI Approved :: MIT License", +] +dependencies = [ + "pydantic>=2.5", +] + +[project.urls] +Homepage = "https://github.com/1Password/onepassword-sdk-python" + +[tool.setuptools.dynamic] +version = {file = "./version.txt"} diff --git a/setup.py b/setup.py index 9e4a7b7a..da45642b 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,5 @@ -from pathlib import Path -from setuptools import setup, find_packages +from setuptools import setup, find_packages, Distribution from sysconfig import get_platform -from version import SDK_VERSION import platform import os @@ -19,6 +17,9 @@ def finalize_options(self): except ImportError: bdist_wheel = None +class BinaryDistribution(Distribution): + def has_ext_modules(self): + return True def get_shared_library_data_to_include(): # Return the correct uniffi C shared library extension for the given platform @@ -46,35 +47,11 @@ def get_shared_library_data_to_include(): setup( - name="onepassword-sdk", - version=SDK_VERSION, - author="1Password", - long_description=(Path(__file__).parent / "README.md").read_text(), - long_description_content_type="text/markdown", - description="The 1Password Python SDK offers programmatic read access to your secrets in 1Password in an interface native to Python.", - url="https://github.com/1Password/onepassword-sdk-python", packages=find_packages( where="src", ), - license="MIT", - license_files="LICENSE", + distclass=BinaryDistribution, package_dir={"": "src"}, - python_requires=">=3.9", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Operating System :: MacOS", - "Operating System :: POSIX :: Linux", - "Operating System :: Microsoft :: Windows", - "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", - "License :: OSI Approved :: MIT License", - ], cmdclass={"bdist_wheel": bdist_wheel}, package_data={"": get_shared_library_data_to_include()}, - install_requires=[ - "pydantic>=2.5", # Minimum Pydantic version to run the Python SDK - ], ) diff --git a/src/release/scripts/build-wheels.sh b/src/release/scripts/build-wheels.sh index 484875d3..e11d0e89 100755 --- a/src/release/scripts/build-wheels.sh +++ b/src/release/scripts/build-wheels.sh @@ -2,8 +2,6 @@ # Helper script to build the required wheels for the Python SDK -output_version_file="version.py" - # The list of python verisons the SDKs release for python_versions=("$@") @@ -15,7 +13,7 @@ macOS_version_x86_64=10.9 macOS_version_arm64=11.0 # Extracts the current verison number for cleanup function -current_version=$(awk -F "['\"]" '/SDK_VERSION =/{print $2}' "$output_version_file") +current_version=$(cat version.txt) # Function to execute upon exit cleanup() { diff --git a/src/release/scripts/prep-release.sh b/src/release/scripts/prep-release.sh index 88e709d2..5318ed4f 100755 --- a/src/release/scripts/prep-release.sh +++ b/src/release/scripts/prep-release.sh @@ -2,21 +2,20 @@ # Helper script to prepare a release for the Python SDK. -output_version_file="version.py" +output_version_file="version.txt" output_build_file="src/onepassword/build_number.py" -version_template_file="src/release/templates/version.tpl.py" build_number_template_file="src/release/templates/build_number.tpl.py" # Extracts the current build/version number for comparison and backup -current_version=$(awk -F "['\"]" '/SDK_VERSION =/{print $2}' "$output_version_file") +current_version=$(cat "$output_version_file") current_build=$(awk -F "['\"]" '/SDK_BUILD_NUMBER =/{print $2}' "$output_build_file") # Function to execute upon exit cleanup() { echo "Performing cleanup tasks..." # Revert changes to file if any - sed -e "s/{{ version }}/$current_version/" "$version_template_file" > "$output_version_file" + echo -n "$current_version" > "$output_version_file" sed -e "s/{{ build }}/$current_build/" "$build_number_template_file" > "$output_build_file" exit 1 } @@ -86,8 +85,8 @@ update_and_validate_version # Update and validate the build number update_and_validate_build -# Update version & build number in version.py and build_number.py respectively -sed -e "s/{{ version }}/$version/" "$version_template_file" > "$output_version_file" +# Update version & build number in version.txt and build_number.py respectively +echo -n "$version" > "$output_version_file" sed -e "s/{{ build }}/$build/" "$build_number_template_file" > "$output_build_file" diff --git a/src/release/scripts/release.sh b/src/release/scripts/release.sh index 050c1489..688863b4 100755 --- a/src/release/scripts/release.sh +++ b/src/release/scripts/release.sh @@ -5,7 +5,7 @@ set -e # Read the contents of the files into variables -version=$(awk -F "['\"]" '/SDK_VERSION =/{print $2}' "version.py") +version=$(cat "version.txt") build=$(awk -F "['\"]" '/SDK_BUILD_NUMBER =/{print $2}' "src/onepassword/build_number.py") release_notes=$(< src/release/RELEASE-NOTES) @@ -27,10 +27,3 @@ git tag -a -s "v${version}" -m "${version}" git push origin tag "v${version}" gh release create "v${version}" --title "Release ${version}" --notes "${release_notes}" --repo github.com/1Password/onepassword-sdk-python - -# Release on PyPi -python3 -m twine upload dist/* - -# Delete the dist folder after published -rm -r dist src/*.egg-info - diff --git a/src/release/templates/version.tpl.py b/src/release/templates/version.tpl.py deleted file mode 100644 index 9c787be2..00000000 --- a/src/release/templates/version.tpl.py +++ /dev/null @@ -1 +0,0 @@ -SDK_VERSION = "{{ version }}" diff --git a/version.py b/version.py deleted file mode 100644 index 05a2fb11..00000000 --- a/version.py +++ /dev/null @@ -1 +0,0 @@ -SDK_VERSION = "0.2.1" diff --git a/version.txt b/version.txt new file mode 100644 index 00000000..341cf11f --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.2.0 \ No newline at end of file