diff --git a/.github/release-drafter-python-client.yml b/.github/release-drafter-python-client.yml new file mode 100644 index 000000000..bef2932d1 --- /dev/null +++ b/.github/release-drafter-python-client.yml @@ -0,0 +1,9 @@ +_extends: kaskada:.github/release-drafter.yml + +name-template: Python $RESOLVED_VERSION +tag-template: python@v$RESOLVED_VERSION +tag-prefix: python@v + +# Only include PRs with one of these labels +include-labels: + - python \ No newline at end of file diff --git a/.github/release-drafter-python.yml b/.github/release-drafter-python.yml index bef2932d1..90a9014f3 100644 --- a/.github/release-drafter-python.yml +++ b/.github/release-drafter-python.yml @@ -1,9 +1,5 @@ _extends: kaskada:.github/release-drafter.yml -name-template: Python $RESOLVED_VERSION -tag-template: python@v$RESOLVED_VERSION -tag-prefix: python@v - -# Only include PRs with one of these labels -include-labels: - - python \ No newline at end of file +name-template: Kaskada $RESOLVED_VERSION-a.0 +tag-template: v$RESOLVED_VERSION-a.0 +tag-prefix: v \ No newline at end of file diff --git a/.github/workflows/ci_python.yml b/.github/workflows/ci_python.yml index 37204b13e..890de9abb 100644 --- a/.github/workflows/ci_python.yml +++ b/.github/workflows/ci_python.yml @@ -29,6 +29,9 @@ on: merge_group: branches: - main + release: + types: + - published defaults: run: @@ -43,6 +46,7 @@ jobs: # # Also, only do it on one machine. lint: + if: github.event_name == 'pull_request' || github.event_name == 'merge_group' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -75,6 +79,10 @@ jobs: poetry run pydocstyle pysrc debug: + if: | + github.event_name == 'pull_request' || + github.event_name == 'merge_group' || + (github.event_name == 'push' && github.ref == 'refs/heads/main') runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -135,11 +143,42 @@ jobs: # Automatically uploads an artifact from the './_site' directory by default path: ${{ github.workspace }}/python/docs/_build + version: + # Build wheels in the merge queue (to verify they build) and during release. + if: | + github.event_name == 'merge_group' || + github.event_name == 'release' + runs-on: ubuntu-latest + outputs: + version: ${{ steps.set-version.outputs.version }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Determine version (merge) + run: | + pip install tomlkit + VERSION=$(python ../scripts/get_version.py path_to_toml_file.toml path.within.toml) + echo "VERSION=$VERSION" >> $GITHUB_ENV + - name: Determine version (release) + run: | + VERSION=${GITHUB_REF#refs/tags/v} + echo "VERSION=$VERSION" >> $GITHUB_ENV + - name: Set version + id: set-version + run: | + echo VERSION=$VERSION + echo "::set-output name=version::$VERSION" + + build-wheel-macos: - # Build wheels in the merge queue. We can either duplicate this in `main` - # or retrieve the built wheels. - if: github.event_name == 'merge_group' + # Build wheels in the merge queue (to verify they build) and during release. + if: | + github.event_name == 'merge_group' || + github.event_name == 'release' runs-on: macos-latest + needs: [version] strategy: matrix: include: @@ -165,6 +204,14 @@ jobs: uses: arduino/setup-protoc@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Set Version (For Release) + if: github.event_name == 'release' + run: | + pip install tomlkit + python ../scripts/set_versions.py ${{ needs.version.outputs.version }} \ + pyproject.toml:project.version \ + pyproject.toml:tool.poetry.version \ + Cargo.toml:workspace.package.version - name: Build wheel uses: messense/maturin-action@v1 with: @@ -195,9 +242,11 @@ jobs: path: ${{ github.workspace }}/python/dist build-wheel-windows: - # Build wheels in the merge queue. We can either duplicate this in `main` - # or retrieve the built wheels. - if: github.event_name == 'merge_group' + # Build wheels in the merge queue (to verify they build) and during release. + if: | + github.event_name == 'merge_group' || + github.event_name == 'release' + needs: [version] runs-on: windows-latest steps: - uses: actions/checkout@v3 @@ -215,6 +264,14 @@ jobs: uses: arduino/setup-protoc@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Set Version (For Release) + if: github.event_name == 'release' + run: | + pip install tomlkit + python ../scripts/set_versions.py ${{ needs.version.outputs.version }} \ + pyproject.toml:project.version \ + pyproject.toml:tool.poetry.version \ + Cargo.toml:workspace.package.version - name: Build wheels uses: messense/maturin-action@v1 with: @@ -243,11 +300,11 @@ jobs: path: ${{ github.workspace }}/python/dist build-wheel-linux: - # Build wheels in the merge queue. We also do this on push to `main` - # because it builds the docs which we'll release. + # Build wheels in the merge queue (to verify they build) and during release. if: | github.event_name == 'merge_group' || - (github.event_name == 'push' && github.ref == 'refs/heads/main') + github.event_name == 'release' + needs: [version] runs-on: ubuntu-latest strategy: matrix: @@ -268,6 +325,14 @@ jobs: 3.10 3.11 cache: poetry + - name: Set Version (For Release) + if: github.event_name == 'release' + run: | + pip install tomlkit + python ../scripts/set_versions.py ${{ needs.version.outputs.version }} \ + pyproject.toml:project.version \ + pyproject.toml:tool.poetry.version \ + Cargo.toml:workspace.package.version - name: Build wheels uses: messense/maturin-action@v1 with: @@ -307,12 +372,22 @@ jobs: # Make the source distribution sdist: - # Build wheels in the merge queue. We can either duplicate this in `main` - # or retrieve the built wheels. - if: github.event_name == 'merge_group' + # Build wheels in the merge queue (to verify they build) and during release. + if: | + github.event_name == 'merge_group' || + github.event_name == 'release' + needs: [version] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Set Version (For Release) + if: github.event_name == 'release' + run: | + pip install tomlkit + python ../scripts/set_versions.py ${{ needs.version.outputs.version }} \ + pyproject.toml:project.version \ + pyproject.toml:tool.poetry.version \ + Cargo.toml:workspace.package.version - name: Build sdist uses: PyO3/maturin-action@v1 with: @@ -345,20 +420,23 @@ jobs: id: deployment uses: actions/deploy-pages@v2 - # release: - # name: Release - # runs-on: ubuntu-latest - # if: "startsWith(github.ref, 'refs/tags/')" - # needs: [linux, windows, macos, sdist] - # steps: - # - uses: actions/download-artifact@v3 - # with: - # name: wheels - # - name: Publish to PyPI - # uses: PyO3/maturin-action@v1 - # env: - # MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - # with: - # command: upload - # args: --skip-existing * - # working-directory: python + release: + name: Release + runs-on: ubuntu-latest + environment: pypi + needs: [build-wheel-linux, build-wheel-windows, build-wheel-macos, sdist] + permissions: + id-token: write + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - uses: actions/download-artifact@v3 + with: + # unpacks default artifact into dist/ + # if `name: artifact` is omitted, the action will create extra parent dir + name: artifact + path: dist + + # - uses: pypa/gh-action-pypi-publish@release/v1 + # To Test + #with: + # To test: repository_url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/release_drafter.yml b/.github/workflows/release_drafter.yml index 540fef909..1181f6150 100644 --- a/.github/workflows/release_drafter.yml +++ b/.github/workflows/release_drafter.yml @@ -25,12 +25,24 @@ jobs: disable-autolabeler: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + python_client_draft: + runs-on: ubuntu-latest + concurrency: + group: python-client-release + steps: + - name: Draft Python Client release + uses: release-drafter/release-drafter@v5 + with: + config-name: release-drafter-python-client.yml + disable-autolabeler: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} python_draft: runs-on: ubuntu-latest concurrency: group: python-release steps: - - name: Draft Python release + - name: Draft Release Notes uses: release-drafter/release-drafter@v5 with: config-name: release-drafter-python.yml diff --git a/python/docs/source/conf.py b/python/docs/source/conf.py index 5321bd7ea..28a265f77 100644 --- a/python/docs/source/conf.py +++ b/python/docs/source/conf.py @@ -69,7 +69,7 @@ "github_repo": "kaskada", "github_version": "main", "doc_path": "kaskada/docs/source", - "analytics":{ + "analytics": { "google_analytics_id": "G-HR9E2E6TG4", }, } diff --git a/python/pyproject.toml b/python/pyproject.toml index f83f81770..84d927572 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -105,7 +105,7 @@ xdoctest = {extras = ["colors"], version = ">=0.15.10"} optional = true [tool.poetry.group.release.dependencies] -python-semantic-release = "^8.0.6" +tomlkit = "^0.12.1" [build-system] requires = ["maturin>=1,<2"] @@ -151,18 +151,4 @@ show_error_context = true [tool.pytest.ini_options] testpaths = [ "pytests", -] - -[tool.semantic_release] -version_toml = [ - "pyproject.toml:project.version", - "pyproject.toml:tool.poetry.version", -] -tag_format = "v{version}" - -[tool.semantic_release.branches.main] -match = "main" -prerelease = true -prerelease_token = "a" - -[tool.semantic_release.remote] +] \ No newline at end of file diff --git a/scripts/get_version.py b/scripts/get_version.py new file mode 100644 index 000000000..b04b5d1b6 --- /dev/null +++ b/scripts/get_version.py @@ -0,0 +1,28 @@ +import tomlkit +import argparse +from typing import List + +def get_value_from_toml(file_path: str, toml_path: List[str]) -> str: + """Retrieve a value from a TOML file at the given path.""" + with open(file_path, 'r') as f: + data = tomlkit.parse(f.read()) + + temp = data + for key in toml_path: + temp = temp[key] + + return str(temp) # Convert value to string in case it's a number or boolean + +def main(): + parser = argparse.ArgumentParser(description='Retrieve value from a TOML file.') + parser.add_argument('file', type=str, help='Path to the TOML file.') + parser.add_argument('path', type=str, help='Path within the TOML file (e.g., package.version)') + + args = parser.parse_args() + + toml_path = args.path.split('.') + value = get_value_from_toml(args.file, toml_path) + print(f"Value at '{args.path}' in '{args.file}': {value}") + +if __name__ == "__main__": + main() diff --git a/scripts/set_versions.py b/scripts/set_versions.py new file mode 100644 index 000000000..2318c7ebc --- /dev/null +++ b/scripts/set_versions.py @@ -0,0 +1,48 @@ +import tomlkit +from tomlkit import dumps +import argparse +from collections import defaultdict +from typing import Dict, List + +def update_version_in_data(data: Dict, version: str, toml_paths: List[str]) -> None: + """Update the version number in a data dictionary (parsed TOML) at multiple paths.""" + for path in toml_paths: + temp = data + path = path.split('.') + for key in path[:-1]: + temp = temp[key] + temp[path[-1]] = version + +def main(): + parser = argparse.ArgumentParser(description='Update version in TOML files.') + parser.add_argument('version', type=str, help='The version number to set.') + parser.add_argument('entries', nargs='+', type=str, + help='TOML file and path, format: : (e.g., config.toml:package.version)') + + args = parser.parse_args() + + # Dictionary to hold the paths for each file + file_paths_dict = defaultdict(list) + + for entry in args.entries: + parts = entry.split(":") + if len(parts) != 2: + print(f"Invalid entry format: {entry}") + continue + + file_path, toml_path_str = parts + + file_paths_dict[file_path].append(toml_path_str) + + # Update the files using the stored paths + for file_path, paths in file_paths_dict.items(): + with open(file_path, 'r') as f: + data = tomlkit.parse(f.read()) + + update_version_in_data(data, args.version, paths) + + with open(file_path, 'w') as f: + f.write(dumps(data)) + +if __name__ == "__main__": + main()