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)
+
+
+
+
+## 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',
+)