From 2f92c1319dbef180584e9737fcd387c5d02843c6 Mon Sep 17 00:00:00 2001 From: Shohei KAMON Date: Sat, 12 Apr 2025 14:30:15 +0800 Subject: [PATCH 1/3] Add copyright,author,license Signed-off-by: Shohei KAMON --- .bump-my-version.cfg | 8 + .github/workflows/release.yml | 1 - .gitignore | 585 ++++++++++++++------------- .pre-commit-config.yaml | 29 ++ CONTRIBUTORS.md | 7 + Makefile | 21 + README.md | 7 +- REUSE.toml | 5 + build.sh | 49 ++- fireblocks_cli/__init__.py | 12 + fireblocks_cli/commands/configure.py | 7 + fireblocks_cli/config.py | 6 + fireblocks_cli/crypto.py | 35 +- fireblocks_cli/main.py | 6 + pyproject.toml | 5 +- requirements-dev.txt | 4 + scripts/__init__.py | 5 + scripts/add_author.py | 97 +++++ scripts/generate_contributors.sh | 17 + 19 files changed, 586 insertions(+), 320 deletions(-) create mode 100644 .bump-my-version.cfg create mode 100644 .pre-commit-config.yaml create mode 100644 CONTRIBUTORS.md create mode 100644 Makefile create mode 100644 REUSE.toml create mode 100644 scripts/__init__.py create mode 100644 scripts/add_author.py create mode 100644 scripts/generate_contributors.sh diff --git a/.bump-my-version.cfg b/.bump-my-version.cfg new file mode 100644 index 0000000..5fb2dbd --- /dev/null +++ b/.bump-my-version.cfg @@ -0,0 +1,8 @@ +[bumpversion] +current_version = 0.1.1 +commit = True +tag = True + +[bumpversion:file:pyproject.toml] +search = version = "{current_version}" +replace = version = "{new_version}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a70c24..f1ca074 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,4 +50,3 @@ jobs: files: release/fireblocks-cli-* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.gitignore b/.gitignore index 16cbc1d..f87f37e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,292 +1,293 @@ -# Created by https://www.toptal.com/developers/gitignore/api/vim,linux,macos,python,emacs -# Edit at https://www.toptal.com/developers/gitignore?templates=vim,linux,macos,python,emacs - -### Emacs ### -# -*- mode: gitignore; -*- -*~ -\#*\# -/.emacs.desktop -/.emacs.desktop.lock -*.elc -auto-save-list -tramp -.\#* - -# Org-mode -.org-id-locations -*_archive - -# flymake-mode -*_flymake.* - -# eshell files -/eshell/history -/eshell/lastdir - -# elpa packages -/elpa/ - -# reftex files -*.rel - -# AUCTeX auto folder -/auto/ - -# cask packages -.cask/ -dist/ - -# Flycheck -flycheck_*.el - -# server auth directory -/server/ - -# projectiles files -.projectile - -# directory configuration -.dir-locals.el - -# network security -/network-security.data - - -### Linux ### - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### macOS Patch ### -# iCloud generated files -*.icloud - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -### Python Patch ### -# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration -poetry.toml - -# ruff -.ruff_cache/ - -# LSP config files -pyrightconfig.json - -### Vim ### -# Swap -[._]*.s[a-v][a-z] -!*.svg # comment out if you don't need vector files -[._]*.sw[a-p] -[._]s[a-rt-v][a-z] -[._]ss[a-gi-z] -[._]sw[a-p] - -# Session -Session.vim -Sessionx.vim - -# Temporary -.netrwhist -# Auto-generated tag files -tags -# Persistent undo -[._]*.un~ - -# End of https://www.toptal.com/developers/gitignore/api/vim,linux,macos,python,emacs +# Created by https://www.toptal.com/developers/gitignore/api/vim,linux,macos,python,emacs +# Edit at https://www.toptal.com/developers/gitignore?templates=vim,linux,macos,python,emacs + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Linux ### + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class +.python-version + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# End of https://www.toptal.com/developers/gitignore/api/vim,linux,macos,python,emacs diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..8575eda --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + + - repo: local + hooks: + - id: update-contributors + name: Update CONTRIBUTORS.md + entry: bash ./scripts/generate_contributors.sh + language: system + files: ^CONTRIBUTORS\.md$ + - repo: local + hooks: + - id: add-spdx + name: Add spdx + entry: make annotate-SPD + language: system + pass_filenames: false + files: \.(py|sh)$ + - repo: local + hooks: + - id: add-author + name: Add Author from git config + entry: python ./scripts/add_author.py + language: python + files: \.(py|sh)$ diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..41fd788 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +# Contributors + +This project is developed with contributions from the following individuals: + + + +Shohei KAMON diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3e5bb5e --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +install-dev: + pip install -e .[dev] + +test: + pytest + +lint-license: + reuse lint + +annotate-SPD: + @echo "πŸ“Ž Annotating files..." + reuse annotate --license MPL-2.0 --copyright "Ethersecurity" $(shell git ls-files '*.py' '*.sh') +pre-commit-refresh: + @echo "🧹 Cleaning pre-commit cache..." + pre-commit clean + @echo "πŸ”„ Installing pre-commit hooks..." + pre-commit install --hook-type pre-commit + @echo "⬆️ Updating pre-commit hooks..." + pre-commit autoupdate + @echo "πŸš€ Running all pre-commit hooks..." + pre-commit run --all-files diff --git a/README.md b/README.md index affa340..0f61dfa 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # fireblocks-cli -> **Disclaimer:** This project is an independent, unofficial command-line interface (CLI) for interacting with the Fireblocks API. -> It is not affiliated with or endorsed by Fireblocks Ltd. -> "Fireblocks" is a registered trademark of Fireblocks Ltd. +> **Disclaimer:** This project is an independent, unofficial command-line interface (CLI) for interacting with the Fireblocks API. +> It is not affiliated with or endorsed by Fireblocks Ltd. +> "Fireblocks" is a registered trademark of Fireblocks Ltd. > > This project is inspired by the design philosophy and usability of the AWS CLI. - diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 0000000..fecebff --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,5 @@ +version = 1 +[reuse] +license = "MPL-2.0" +copyright = "Ethersecurity" +year = "2025" diff --git a/build.sh b/build.sh index 76ef7eb..fc6b5c7 100644 --- a/build.sh +++ b/build.sh @@ -1,7 +1,13 @@ #!/bin/bash -# Build script for fireblocks-cli using PyInstaller + git describe + upx -# Usage: ./build.sh +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + +# Build script for fireblocks-cli using PyInstaller + bump-my-version + upx +# Usage: ./build.sh [major|minor|patch] set -e @@ -10,32 +16,49 @@ ENTRYPOINT="fireblocks_cli/main.py" DIST_DIR="dist" BUILD_DIR="build" -# Get version from git -echo "πŸ“¦ Extracting version..." -VERSION=$(git describe --tags --always) -echo "$VERSION" > VERSION.txt -echo "πŸ”– Version: $VERSION" +# Handle version bump +BUMP_PART="$1" +if [[ "$BUMP_PART" =~ ^(major|minor|patch)$ ]]; then + echo "πŸ”§ Bumping version: $BUMP_PART" + + case "$BUMP_PART" in + major) + if [[ -n "$(git status --porcelain)" ]]; then + echo "🚫 Cannot bump major version in a dirty working directory." + echo "πŸ’‘ Please commit or stash your changes first." + exit 1 + fi + ;; + minor|patch) + echo "⚠️ Allowing dirty working tree for $BUMP_PART bump" + ;; + esac + + bump-my-version bump $BUMP_PART --allow-dirty +else + echo "⚠️ No valid bump type provided. Skipping version bump." +fi + +# Read version from fireblocks_cli/__init__.py +VERSION=$(grep -oE '__version__ = "[^"]+"' fireblocks_cli/__init__.py | cut -d '"' -f2) +echo "πŸ”– Using version: $VERSION" # Cleanup old builds echo "πŸ”„ Cleaning previous builds..." rm -rf $DIST_DIR $BUILD_DIR __pycache__ -# Build with PyInstaller (embed version) +# Build with PyInstaller echo "πŸ”§ Building $APP_NAME for $(uname)..." pyinstaller \ --onefile \ --name $APP_NAME \ --hidden-import=fireblocks_cli.commands.configure \ - --add-data "VERSION.txt:." \ --clean \ $ENTRYPOINT -# Add version file manually (for reference or embedding) -echo "$VERSION" > VERSION.txt - # Rename output binary PLATFORM=$(uname | tr '[:upper:]' '[:lower:]') -OUTPUT="$DIST_DIR/${APP_NAME}-$PLATFORM" +OUTPUT="$DIST_DIR/${APP_NAME}-${PLATFORM}-v${VERSION}" mv $DIST_DIR/$APP_NAME $OUTPUT # Optional UPX compression diff --git a/fireblocks_cli/__init__.py b/fireblocks_cli/__init__.py index e69de29..299cc5a 100644 --- a/fireblocks_cli/__init__.py +++ b/fireblocks_cli/__init__.py @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + +try: + from importlib.metadata import version +except ImportError: + from importlib_metadata import version # Python <3.8 fallback + +__version__ = version(__name__) diff --git a/fireblocks_cli/commands/configure.py b/fireblocks_cli/commands/configure.py index f956cdc..db5bb98 100644 --- a/fireblocks_cli/commands/configure.py +++ b/fireblocks_cli/commands/configure.py @@ -1,8 +1,15 @@ +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + import typer from fireblocks_cli.crypto import generate_key_and_csr configure_app = typer.Typer() + @configure_app.command("gen-keys") def gen_keys(): """η§˜ε―†ι΅γ¨CSRγ‚’ ~/.fireblocks/keys γ«η”Ÿζˆγ—γΎγ™""" diff --git a/fireblocks_cli/config.py b/fireblocks_cli/config.py index e805ad5..97c1c5d 100644 --- a/fireblocks_cli/config.py +++ b/fireblocks_cli/config.py @@ -1,3 +1,9 @@ +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + from fireblocks_cli.commands.configure import configure_app import typer diff --git a/fireblocks_cli/crypto.py b/fireblocks_cli/crypto.py index a53d506..8fe35f1 100644 --- a/fireblocks_cli/crypto.py +++ b/fireblocks_cli/crypto.py @@ -1,17 +1,25 @@ +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + import random import string from pathlib import Path import subprocess import typer + def generate_unique_basename(base_dir: Path) -> tuple[str, Path, Path]: while True: - basename = ''.join(random.choices(string.ascii_lowercase + string.digits, k=12)) + basename = "".join(random.choices(string.ascii_lowercase + string.digits, k=12)) key_path = base_dir / f"{basename}.key" csr_path = base_dir / f"{basename}.csr" if not key_path.exists() and not csr_path.exists(): return basename, key_path, csr_path + def generate_key_and_csr(org_name: str) -> tuple[Path, Path]: base_dir = Path.home() / ".fireblocks" / "keys" base_dir.mkdir(parents=True, exist_ok=True) @@ -19,12 +27,25 @@ def generate_key_and_csr(org_name: str) -> tuple[Path, Path]: basename, key_path, csr_path = generate_unique_basename(base_dir) subj = f"/O={org_name}" - result = subprocess.run([ - "openssl", "req", "-new", "-newkey", "ed25519", - "-nodes", "-keyout", str(key_path), - "-out", str(csr_path), - "-subj", subj - ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + result = subprocess.run( + [ + "openssl", + "req", + "-new", + "-newkey", + "ed25519", + "-nodes", + "-keyout", + str(key_path), + "-out", + str(csr_path), + "-subj", + subj, + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) if result.returncode != 0: typer.secho("❌ OpenSSLエラー:", fg=typer.colors.RED) diff --git a/fireblocks_cli/main.py b/fireblocks_cli/main.py index 4813946..2ca7e62 100644 --- a/fireblocks_cli/main.py +++ b/fireblocks_cli/main.py @@ -1,5 +1,11 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + from fireblocks_cli.commands.configure import configure_app import typer diff --git a/pyproject.toml b/pyproject.toml index 9fac4e1..58fd6ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "fireblocks-cli" -version = "0.1.0" -description = "A CLI tool for managing Fireblocks API keys and profiles" +version = "0.1.1" +description = "An unofficial CLI for managing Fireblocks services." authors = [{ name = "Kamon Shohei" }] readme = "README.md" requires-python = ">=3.8" @@ -12,4 +12,3 @@ dependencies = [ [project.scripts] fireblocks-cli = "fireblocks_cli.main:app" - diff --git a/requirements-dev.txt b/requirements-dev.txt index ef376ca..4a49f9a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1 +1,5 @@ pyinstaller +bump-my-version +black +reuse +pre-commit diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..018852d --- /dev/null +++ b/scripts/__init__.py @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON diff --git a/scripts/add_author.py b/scripts/add_author.py new file mode 100644 index 0000000..14348f0 --- /dev/null +++ b/scripts/add_author.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + +""" +add_author.py + +This script automatically inserts an Author line into source files based on the current git user's configuration. + +Usage: + python add_author.py file1.py file2.sh ... # Inserts Author line if missing + python add_author.py --append file1.py # Appends your Author line after existing Author(s) + +Behavior: +- Extracts user.name and user.email from git config. +- Inserts `# Author: Name ` after the SPDX-License-Identifier line. +- If no SPDX line exists, and a shebang is present, inserts Author line after shebang. +- Otherwise inserts Author line at the top. +- Adds a blank line above the inserted Author line when newly added. +- In append mode, adds Author line directly below existing Author lines. +- Avoids duplicate Author lines. +- Skips processing if git config is missing or incomplete. + +Intended for use in compliance with REUSE and SPDX standards, especially for projects requiring traceable authorship (e.g. financial institutions). +""" + +import sys +import os +import subprocess + + +def get_git_author(): + try: + name = subprocess.check_output( + ["git", "config", "user.name"], text=True + ).strip() + email = subprocess.check_output( + ["git", "config", "user.email"], text=True + ).strip() + if not name or not email: + raise ValueError("Git user.name or user.email is not set") + return f"# Author: {name} <{email}>" + except (subprocess.CalledProcessError, ValueError): + return None + + +AUTHOR_LINE = get_git_author() + + +def insert_or_append_author(filepath, append=False): + if not os.path.isfile(filepath) or AUTHOR_LINE is None: + return + + with open(filepath, "r", encoding="utf-8") as f: + lines = f.readlines() + + if any(AUTHOR_LINE.strip() == line.strip() for line in lines): + return # already present + + has_author_line = any(line.startswith("# Author:") for line in lines) + + if append and has_author_line: + last_author_index = max( + i for i, line in enumerate(lines) if line.startswith("# Author:") + ) + lines.insert(last_author_index + 1, AUTHOR_LINE + "\n") + else: + inserted = False + for i, line in enumerate(lines): + if line.startswith("# SPDX-License-Identifier:"): + lines.insert(i + 1, "\n" + AUTHOR_LINE + "\n") + inserted = True + break + if not inserted: + if lines and lines[0].startswith("#!"): + lines.insert(1, "\n" + AUTHOR_LINE + "\n") + else: + lines.insert(0, AUTHOR_LINE + "\n\n") + + with open(filepath, "w", encoding="utf-8") as f: + f.writelines(lines) + + +if __name__ == "__main__": + if AUTHOR_LINE is None: + print("❌ Skipping: Git user.name and user.email are not set.") + sys.exit(1) + + append_mode = "--append" in sys.argv + files = [arg for arg in sys.argv[1:] if not arg.startswith("--")] + + for path in files: + insert_or_append_author(path, append=append_mode) diff --git a/scripts/generate_contributors.sh b/scripts/generate_contributors.sh new file mode 100644 index 0000000..bb83803 --- /dev/null +++ b/scripts/generate_contributors.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + +echo '# Contributors' > CONTRIBUTORS.md +echo "" >> CONTRIBUTORS.md +echo "This project is developed with contributions from the following individuals:" >> CONTRIBUTORS.md +echo "" >> CONTRIBUTORS.md +echo "" >> CONTRIBUTORS.md +echo "" >> CONTRIBUTORS.md + +# Get unique contributors in the format: Name +git log --format='%aN <%aE>' | sort -u >> CONTRIBUTORS.md From 9514360301b3ccb67d65ab2d8c4b99adcdfcf26b Mon Sep 17 00:00:00 2001 From: Shohei KAMON Date: Sat, 12 Apr 2025 15:02:40 +0800 Subject: [PATCH 2/3] Update scripts/generate_contributors.sh\nAdd Sign-off check when pre-commit Signed-off-by: Shohei KAMON --- .bump-my-version.cfg => .bumpversion.cfg | 0 .pre-commit-config.yaml | 15 +++++++++++++++ CONTRIBUTORS.md | 1 + requirements-dev.txt | 1 + scripts/check_signoff.sh | 17 +++++++++++++++++ scripts/generate_contributors.sh | 2 +- 6 files changed, 35 insertions(+), 1 deletion(-) rename .bump-my-version.cfg => .bumpversion.cfg (100%) create mode 100755 scripts/check_signoff.sh diff --git a/.bump-my-version.cfg b/.bumpversion.cfg similarity index 100% rename from .bump-my-version.cfg rename to .bumpversion.cfg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8575eda..97fa3d2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,4 @@ +--- repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 @@ -27,3 +28,17 @@ repos: entry: python ./scripts/add_author.py language: python files: \.(py|sh)$ + - repo: local + hooks: + - id: lint-python + name: Exec linter for python + entry: black . + language: python + files: \.py$ + - repo: local + hooks: + - id: check-signoff + name: Enforce Signed-off-by line + entry: ./scripts/check_signoff.sh + language: script + stages: [commit-msg] diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 41fd788..034b39b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -5,3 +5,4 @@ This project is developed with contributions from the following individuals: Shohei KAMON +Shohei KAMON diff --git a/requirements-dev.txt b/requirements-dev.txt index 4a49f9a..52f0674 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,3 +3,4 @@ bump-my-version black reuse pre-commit +yamllint diff --git a/scripts/check_signoff.sh b/scripts/check_signoff.sh new file mode 100755 index 0000000..bb2378a --- /dev/null +++ b/scripts/check_signoff.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# SPDX-FileCopyrightText: 2025 Ethersecurity +# +# SPDX-License-Identifier: MPL-2.0 + +# Author: Shohei KAMON + +set -euo pipefail + +COMMIT_MSG_FILE="$1" + +if ! grep -qi '^Signed-off-by: ' "$COMMIT_MSG_FILE"; then + echo "❌ Commit message is missing a 'Signed-off-by' line." + echo "πŸ’‘ Please use: git commit -sm \"your message\"" + exit 1 +fi diff --git a/scripts/generate_contributors.sh b/scripts/generate_contributors.sh index bb83803..d2d4655 100644 --- a/scripts/generate_contributors.sh +++ b/scripts/generate_contributors.sh @@ -14,4 +14,4 @@ echo "" echo "" >> CONTRIBUTORS.md # Get unique contributors in the format: Name -git log --format='%aN <%aE>' | sort -u >> CONTRIBUTORS.md +git log --format='%aN <%aE>' | tac | awk '!seen[$0]++' >> CONTRIBUTORS.md From e9e5fff0b92c6da6aa221606b8ce5a6138dc4779 Mon Sep 17 00:00:00 2001 From: Shohei KAMON Date: Sat, 12 Apr 2025 15:16:52 +0800 Subject: [PATCH 3/3] Setup bumpversion Signed-off-by: Shohei KAMON --- .bumpversion.cfg | 8 -------- .bumpversion.toml | 9 +++++++++ pyproject.toml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 .bumpversion.cfg create mode 100644 .bumpversion.toml diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 5fb2dbd..0000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[bumpversion] -current_version = 0.1.1 -commit = True -tag = True - -[bumpversion:file:pyproject.toml] -search = version = "{current_version}" -replace = version = "{new_version}" diff --git a/.bumpversion.toml b/.bumpversion.toml new file mode 100644 index 0000000..33a8a72 --- /dev/null +++ b/.bumpversion.toml @@ -0,0 +1,9 @@ +[bumpversion] +current_version = "0.1.3" +commit = false +tag = false + +[[bumpversion.files]] +filename = "pyproject.toml" +search = 'version = "{current_version}"' +replace = 'version = "{new_version}"' diff --git a/pyproject.toml b/pyproject.toml index 58fd6ab..67fc597 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "fireblocks-cli" -version = "0.1.1" +version = "0.1.3" description = "An unofficial CLI for managing Fireblocks services." authors = [{ name = "Kamon Shohei" }] readme = "README.md"