diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec7c4b1a..14a069fa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,11 +20,17 @@ jobs: - name: Fetch all tags run: git fetch --force --tags - - name: Set up Go + - name: Setup Go uses: actions/setup-go@v5 with: go-version-file: go.mod + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: python -m pip install --upgrade pip twine wheel setuptools + - name: Install Snapcraft uses: samuelmeuli/action-snapcraft@v2 @@ -43,10 +49,11 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} - - name: Publish to NPM and Rubygems + - name: Publish to NPM, Rubygems and PyPI env: NPM_API_KEY: ${{ secrets.NPM_API_KEY }} RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} + PYPI_API_KEY: ${{ secrets.PYPI_API_KEY }} run: | cat << EOF > ~/.npmrc //registry.npmjs.org/:_authToken=${NPM_API_KEY} @@ -58,6 +65,17 @@ jobs: :rubygems_api_key: ${RUBYGEMS_API_KEY} EOF chmod 0600 ~/.gem/credentials + cat << EOF > ~/.pypirc + [distutils] + index-servers = + lefthook + + [lefthook] + repository = https://upload.pypi.org/legacy/ + username = __token__ + password = ${PYPI_API_KEY} + EOF + chmod 0600 ~/.pypirc cd packaging/ ruby pack.rb prepare ruby pack.rb publish diff --git a/.gitignore b/.gitignore index 9d02edbd..b5562bfd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ tmp/ dist/ # Packages +packaging/pypi/lefthook/__pycache__/ +packaging/pypi/lefthook/bin/ +packaging/pypi/lefthook.egg-info/ +packaging/pypi/build/ packaging/rubygems/pkg/ packaging/rubygems/libexec/ packaging/npm-bundled/bin/ diff --git a/packaging/pack.rb b/packaging/pack.rb index 5a29ef02..1579fb6f 100755 --- a/packaging/pack.rb +++ b/packaging/pack.rb @@ -24,7 +24,7 @@ def clean puts "Cleaning... " rm(Dir["npm/**/README.md"]) rm(Dir["npm/**/lefthook*"].filter(&File.method(:file?))) - system("git clean -fdX npm-installer/ npm-bundled/ npm-bundled/bin/ rubygems/libexec/ rubygems/pkg/", exception: true) + system("git clean -fdX npm-installer/ npm-bundled/ npm-bundled/bin/ rubygems/libexec/ rubygems/pkg/ pypi pypi/lefthook/", exception: true) puts "done" end @@ -37,6 +37,7 @@ def set_version replace_in_file("npm/lefthook/package.json", /"(lefthook-.+)": "[\d.]+"/, %{"\\1": "#{VERSION}"}) replace_in_file("rubygems/lefthook.gemspec", /(spec\.version\s+= ).*/, %{\\1"#{VERSION}"}) + replace_in_file("pypi/setup.py", /(version+=).*/, %{\\1'#{VERSION}',}) end def put_readme @@ -101,10 +102,31 @@ def put_binaries cp(source, dest, verbose: true) end + { + "#{DIST}/no_self_update_linux_amd64_v1/lefthook" => "pypi/lefthook/bin/lefthook-linux-x86_64/lefthook", + "#{DIST}/no_self_update_linux_arm64/lefthook" => "pypi/lefthook/bin/lefthook-linux-arm64/lefthook", + "#{DIST}/no_self_update_freebsd_amd64_v1/lefthook" => "pypi/lefthook/bin/lefthook-freebsd-x86_64/lefthook", + "#{DIST}/no_self_update_freebsd_arm64/lefthook" => "pypi/lefthook/bin/lefthook-freebsd-arm64/lefthook", + "#{DIST}/no_self_update_openbsd_amd64_v1/lefthook" => "pypi/lefthook/bin/lefthook-openbsd-x86_64/lefthook", + "#{DIST}/no_self_update_openbsd_arm64/lefthook" => "pypi/lefthook/bin/lefthook-openbsd-arm64/lefthook", + "#{DIST}/no_self_update_windows_amd64_v1/lefthook.exe" => "pypi/lefthook/bin/lefthook-windows-x86_64/lefthook.exe", + "#{DIST}/no_self_update_windows_arm64/lefthook.exe" => "pypi/lefthook/bin/lefthook-windows-arm64/lefthook.exe", + "#{DIST}/no_self_update_darwin_amd64_v1/lefthook" => "pypi/lefthook/bin/lefthook-darwin-x86_64/lefthook", + "#{DIST}/no_self_update_darwin_arm64/lefthook" => "pypi/lefthook/bin/lefthook-darwin-arm64/lefthook", + }.each do |(source, dest)| + mkdir_p(File.dirname(dest)) + cp(source, dest, verbose: true) + end + puts "done" end def publish + puts "Publishing to PyPI..." + cd(File.join(__dir__, "pypi")) + system("python setup.py sdist bdist_wheel", exception: true) + system("python -m twine upload --verbose --repository lefthook dist/*", exception: true) + puts "Publishing lefthook npm..." cd(File.join(__dir__, "npm")) Dir["lefthook*"].each do |package| @@ -122,7 +144,7 @@ def publish cd(File.join(__dir__, "npm-installer")) system("npm publish --access public", exception: true) - puts "Publishing lefthook gem..." + puts "Publishing to Rubygems..." cd(File.join(__dir__, "rubygems")) system("rake build", exception: true) system("gem push pkg/*.gem", exception: true) diff --git a/packaging/pypi/LICENSE b/packaging/pypi/LICENSE new file mode 100644 index 00000000..bf519ae2 --- /dev/null +++ b/packaging/pypi/LICENSE @@ -0,0 +1,22 @@ + +The MIT License (MIT) + +Copyright (c) 2019 Arkweid + +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/packaging/pypi/README.md b/packaging/pypi/README.md new file mode 100644 index 00000000..57153854 --- /dev/null +++ b/packaging/pypi/README.md @@ -0,0 +1,50 @@ +![Build Status](https://github.com/evilmartians/lefthook/actions/workflows/test.yml/badge.svg?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/evilmartians/lefthook/badge.svg?branch=master)](https://coveralls.io/github/evilmartians/lefthook?branch=master) + +# Lefthook + +> The fastest polyglot Git hooks manager out there + + + +A Git hooks manager for Node.js, Ruby and many other types of projects. + +* **Fast.** It is written in Go. Can run commands in parallel. +* **Powerful.** It allows to control execution and files you pass to your commands. +* **Simple.** It is single dependency-free binary which can work in any environment. + +📖 [Read the introduction post](https://evilmartians.com/chronicles/lefthook-knock-your-teams-code-back-into-shape?utm_source=lefthook) + + +Sponsored by Evil Martians + +## Install + +```bash +pip install lefthook +``` + +## Usage + +Configure your hooks, install them once and forget about it: rely on the magic underneath. + +#### TL;DR + +```bash +# Configure your hooks +vim lefthook.yml + +# Install them to the git project +lefthook install + +# Enjoy your work with git +git add -A && git commit -m '...' +``` + +#### More details + +- [**Configuration**](https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md) for `lefthook.yml` config options. +- [**Usage**](https://github.com/evilmartians/lefthook/blob/master/docs/usage.md) for **lefthook** CLI options, supported ENVs, and usage tips. +- [**Discussions**](https://github.com/evilmartians/lefthook/discussions) for questions, ideas, suggestions. + diff --git a/packaging/pypi/lefthook/__init__.py b/packaging/pypi/lefthook/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packaging/pypi/lefthook/__main__.py b/packaging/pypi/lefthook/__main__.py new file mode 100644 index 00000000..21eba355 --- /dev/null +++ b/packaging/pypi/lefthook/__main__.py @@ -0,0 +1,6 @@ +import sys + +from .main import main + +if __name__ == "__main__": + sys.exit(main()) diff --git a/packaging/pypi/lefthook/bin/.keep b/packaging/pypi/lefthook/bin/.keep new file mode 100644 index 00000000..e69de29b diff --git a/packaging/pypi/lefthook/main.py b/packaging/pypi/lefthook/main.py new file mode 100644 index 00000000..ccf869f1 --- /dev/null +++ b/packaging/pypi/lefthook/main.py @@ -0,0 +1,24 @@ +import os +import sys +import platform +import subprocess + +ISSUE_URL = "https://github.com/evilmartians/lefthook/issues/new/choose" +ARCH_MAPPING = { + 'amd64': 'x86_64', + 'aarch64': 'arm64', +} + +def main(): + os_name = platform.system().lower() + arch = platform.machine().lower() + arch = ARCH_MAPPING.get(arch, arch) + ext = os_name == "windows" and ".exe" or "" + subfolder = f"lefthook-{os_name}-{arch}" + executable = os.path.join(os.path.dirname(__file__), "bin", subfolder, "lefthook"+ext) + if not os.path.isfile(executable): + print(f"Couldn't find binary {executable}. Please create an issue: {ISSUE_URL}") + return 1 + + result = subprocess.run([executable] + sys.argv[1:]) + return result.returncode diff --git a/packaging/pypi/setup.py b/packaging/pypi/setup.py new file mode 100644 index 00000000..630e53ea --- /dev/null +++ b/packaging/pypi/setup.py @@ -0,0 +1,41 @@ +from setuptools import setup, find_packages + +with open("README.md", "r") as fh: + long_description = fh.read() + +setup( + name='lefthook', + version='1.7.18', + author='Evil Martians', + author_email='lefthook@evilmartians.com', + url='https://github.com/evilmartians/lefthook', + description='Git hooks manager. Fast, powerful, simple.', + long_description=long_description, + long_description_content_type="text/markdown", + packages=find_packages(), + entry_points={ + 'console_scripts': [ + 'lefthook=lefthook.main:main' + ], + }, + package_data={ + 'lefthook':[ + 'bin/lefthook-linux-x86_64/lefthook', + 'bin/lefthook-linux-arm64/lefthook', + 'bin/lefthook-freebsd-x86_64/lefthook', + 'bin/lefthook-freebsd-arm64/lefthook', + 'bin/lefthook-openbsd-x86_64/lefthook', + 'bin/lefthook-openbsd-arm64/lefthook', + 'bin/lefthook-windows-x86_64/lefthook.exe', + 'bin/lefthook-windows-arm64/lefthook.exe', + 'bin/lefthook-darwin-x86_64/lefthook', + 'bin/lefthook-darwin-arm64/lefthook', + ] + }, + classifiers=[ + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Topic :: Software Development :: Version Control :: Git' + ], + python_requires='>=3.6', +)