From 2ff40cfe3a19af28e4c86eee66777854e04f511d Mon Sep 17 00:00:00 2001 From: Yuki Sawa Date: Sat, 4 Nov 2023 18:23:00 -0700 Subject: [PATCH] add workflow for release + release v0.0.1 (#1) * add workflow for release * add ci * fix release * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * clean * readme * clean * clean * clean * clean * add example * clean * clean * clean * clean * clean --- .cpa/flake8.cfg | 13 +- .github/workflows/ci.yaml | 45 +++++++ .github/workflows/release.yaml | 57 +++++++++ .pre-commit-config.yaml | 10 +- README.md | 39 +++--- cpa.png | Bin 0 -> 71468 bytes example/.cpa/flake8.cfg | 49 ++++++++ example/.cpa/prettier.json | 7 ++ example/.gitignore | 189 +++++++++++++++++++++++++++++ example/.pre-commit-config.yaml | 112 +++++++++++++++++ example/Dockerfile | 12 ++ example/Makefile | 25 ++++ example/main.py | 1 + example/pyproject.toml | 62 ++++++++++ install.sh | 66 ++++++++++ pypropoject.toml => pyproject.toml | 0 src/main.rs | 4 +- src/python.rs | 121 +++++++++++++----- templates/.pre-commit-config.yaml | 4 +- templates/Dockerfile | 12 ++ templates/Makefile | 25 ++++ templates/main.py | 1 + 22 files changed, 791 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 cpa.png create mode 100644 example/.cpa/flake8.cfg create mode 100644 example/.cpa/prettier.json create mode 100644 example/.gitignore create mode 100644 example/.pre-commit-config.yaml create mode 100644 example/Dockerfile create mode 100644 example/Makefile create mode 100644 example/main.py create mode 100644 example/pyproject.toml create mode 100644 install.sh rename pypropoject.toml => pyproject.toml (100%) create mode 100644 templates/Dockerfile create mode 100644 templates/Makefile create mode 100644 templates/main.py diff --git a/.cpa/flake8.cfg b/.cpa/flake8.cfg index b03d221..426aebc 100644 --- a/.cpa/flake8.cfg +++ b/.cpa/flake8.cfg @@ -41,9 +41,12 @@ exclude = build, dist, htmlcov.*, - -application-import-names = flake8 # List of application-specific import names. -import-order-style = google # Import statement format style. -max-complexity = 18 # The maximum McCabe complexity allowed. -max-line-length = 120 # The maximum allowed line length. +# List of application-specific import names. +application-import-names = flake8 +# Import statement format style. +import-order-style = google +# The maximum McCabe complexity allowed. +max-complexity = 18 +# The maximum allowed line length. +max-line-length = 120 # per-file-ignores = # Per-file-ignores setting can be used to ignore specific errors in specific files. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..1937ccd --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,45 @@ +name: CI + +#################################### +# Start the job on all push and PR # +#################################### +on: + pull_request: + branches: [master, main] + types: [synchronize, opened, reopened, ready_for_review] + # push: + # branches: [master, main] + +jobs: + precommits: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install pre-commit + pre-commit install + + - name: Install shfmt + run: | + SHFMT_VERSION="v3.7.0" + SHFMT_BIN="shfmt_${SHFMT_VERSION}_linux_amd64" + wget -O shfmt "https://github.com/mvdan/sh/releases/download/${SHFMT_VERSION}/${SHFMT_BIN}" + chmod +x shfmt + sudo mv shfmt /usr/local/bin/ + + - name: Run pre-commits + run: | + pre-commit run --all-files + # pre-commit run --from-ref origin/main --to-ref HEAD + # run: | + # BASE_COMMIT_ID=$(git rev-parse origin/main) + # pre-commit run --from-ref ${{ env.BASE_COMMIT_ID }} --to-ref HEAD diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..e658db9 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,57 @@ +name: Release + +on: + push: + tags: + - "v*" + # pull_request: + # branches: [master, main] + # types: [synchronize, opened, reopened, ready_for_review] + +jobs: + create-release: + name: Create Release + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release create ${{ github.ref_name }} --generate-notes --title "Version ${{ github.ref_name }}" + + upload-release: + name: Build and Release + permissions: + contents: write + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Install Rust Toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Print Runner OS + run: echo "Runner OS is ${{ runner.os }}" + + - name: Build Release + run: cargo build --release + + - name: Archive Release Binary (Windows) + if: runner.os == 'Windows' + run: Compress-Archive -Path ./target/release/cpa.exe -DestinationPath cpa-Windows.zip + shell: pwsh + + - name: Archive Release Binary (MacOS, Linux) + if: runner.os != 'Windows' + run: zip -j cpa-${{ runner.os }}.zip ./target/release/cpa + + - name: Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release upload ${{ github.ref_name }} "cpa-${{ runner.os }}.zip" --clobber diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7fb2a4f..1002cf1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,10 +13,10 @@ repos: - id: check-merge-conflict # Searches for merge conflict markers within files. - id: check-symlinks # Detects broken symlinks. - id: check-added-large-files # Blocks commits that add large files. Default limit is 500kB. + args: ["--maxkb=1300"] # Can be configured with args, e.g., '--maxkb=1000' to change the limit. # Files in 'your_dir/' can be excluded. # exclude: 'your_dir/.*' - # args: ['--maxkb=5000'] - id: end-of-file-fixer # Ensures files end with a single newline or are empty. - id: trailing-whitespace # Removes any trailing whitespace at the end of lines. @@ -59,7 +59,7 @@ repos: - id: isort # Sorts Python imports into sections and by alphabetical order args: - --settings-path - - .cpa/pyproject.toml + - pyproject.toml types: - python @@ -69,7 +69,7 @@ repos: - id: black # Formats Python code to conform to the Black code style args: - --config - - .cpa/pyproject.toml + - pyproject.toml types: - python @@ -116,9 +116,9 @@ repos: - markdown exclude: templates/.pre-commit-config.yaml - ## + ############################################################################# # Rust - ## + ############################################################################# - repo: https://github.com/doublify/pre-commit-rust rev: v1.0 hooks: diff --git a/README.md b/README.md index c304a13..3a9eeee 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,26 @@ # CPA: Create-Python-App -## Overview - -`cpa` is a cli tool designed to streamline the setup of new Python projects. It automates the creation of Python projects with commonly used configs and boilerplate. - -## Goals - -- **Speed up Project Creation**: Reduce the time spent on repetitive setup tasks -- **Best Practices**: Encourage best practices for code quality, formatting, and style by including configs for tools like `black`, `isort`, and `flake8`. -- **Automation**: Automate tasks such as generating `.gitignore` files, setting up pre-commit hooks, and configuring code linters and formatters. +![CPA Logo](cpa.png) -## Features +## Overview -- Provides pre-commit hook setup with hooks for checking merge conflicts, large files, and code styling. +`cpa` is a cli tool for ultra fast setup of new Python projects. It automates the creation of config files for style & lint checks, gitignore, a basic Dockerfile and dependency management configuration. An opinionated set of pre-commit hooks are included for enforcing best practices and reducing setup time. ## Installation -Download binary from Github +### MacOS, Linux -```bash +Download latest binary and install via provided `install.sh` script or get it from [Releases](https://github.com/ysawa0/create-python-app/releases) ``` +sh install.sh +``` + +### Windows + +Download latest binary from [Releases](https://github.com/ysawa0/create-python-app/releases) page -Building from source +### Building from source ```bash # cd to project @@ -34,19 +32,26 @@ cargo install --path . To create a new project: ```bash -cpa create --name +cpa create --name myproject ``` Optional params: -- `--preset`: Specifies a Python version for the project. Defaults to "python" which is mapped internally to "python3.10". +- `--preset`: Specifies a Python version for the project. Defaults to "python3.10" Example: ```bash -cpa create --name my_project --preset python3.10 +cpa create --name myproject --preset python3.10 ``` +## Goals + +- **Speed up Project Creation**: Reduce the time spent on repetitive setup tasks +- **Best Practices**: Encourage best practices for code quality, formatting, and style by including configs for tools like `black`, `isort`, and `flake8`. +- **Automation**: Automate tasks such as generating `.gitignore` files, setting up pre-commit hooks, and configuring code linters and formatters. +- Golang, Rust support planned + ## Contributions and Feedback Users are welcome to contribute to the project by submitting pull requests or opening issues for bugs and feature requests. Feedback is also greatly appreciated to help improve the tool. diff --git a/cpa.png b/cpa.png new file mode 100644 index 0000000000000000000000000000000000000000..34bd624cdbfd58ac77f5c6c3f479adeb55d2771a GIT binary patch literal 71468 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 z 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 79 characters). Ignored because max-line-length is set. + F841, # local variable is assigned to but never used. + I100, # Import statements are in the wrong order. + I201, # Missing newline between import groups. + I202, # Additional newline in a group of imports. + W503 # line break before binary operator. This is no longer PEP 8 compliant. + +exclude = + .cache, + .coverage.*, + .env, # Environment directory used by some tools + .git, # Version control directory + .github, # GitHub metadata directory + .gradle, + .hg, # Mercurial directory + .mypy_cache, # MyPy cache directory + .pytest_cache, # PyTest cache directory + .svn, # Subversion directory + .tox, + .venv, # Common virtual environment directory + .vscode, # VS Code configuration directory + *__pycache__, # Python cache directory + *.egg-info, + *.pyc, + build, + dist, + htmlcov.*, + +application-import-names = flake8 # List of application-specific import names. +import-order-style = google # Import statement format style. +max-complexity = 18 # The maximum McCabe complexity allowed. +max-line-length = 120 # The maximum allowed line length. +# per-file-ignores = # Per-file-ignores setting can be used to ignore specific errors in specific files. diff --git a/example/.cpa/prettier.json b/example/.cpa/prettier.json new file mode 100644 index 0000000..64f80e2 --- /dev/null +++ b/example/.cpa/prettier.json @@ -0,0 +1,7 @@ +{ + "bracketSpacing": true, + "singleQuote": false, + "useTabs": false, + "tabWidth": 2, + "trailingComma": "all" +} diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..ea1aea1 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,189 @@ +########################################################################################## +# Python +# From: https://github.com/github/gitignore/blob/main/Python.gitignore +########################################################################################## +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +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/ + +########################################################################################## +# Rust +# From: https://github.com/github/gitignore/blob/main/Rust.gitignore +########################################################################################## +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + + +########################################################################################## +# Misc +########################################################################################## +tmp* diff --git a/example/.pre-commit-config.yaml b/example/.pre-commit-config.yaml new file mode 100644 index 0000000..2984965 --- /dev/null +++ b/example/.pre-commit-config.yaml @@ -0,0 +1,112 @@ +default_language_version: + python: python3 + +repos: + ############################################################################# + # Misc + ############################################################################# + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-merge-conflict # Searches for merge conflict markers within files. + - id: check-added-large-files # Blocks commits that add large files. Default limit is 500kB. + # Can be configured with args, e.g., '--maxkb=1000' to change the limit. + # exclude: 'your_dir/.*' + # args: ['--maxkb=5000'] + - id: check-case-conflict # Identifies potential case-insensitive file name conflicts. + - id: check-ast # Validates the syntax of Python files. + - id: check-symlinks # Detects broken symlinks. + - id: trailing-whitespace # Removes any trailing whitespace at the end of lines. + - id: end-of-file-fixer # Ensures files end with a single newline or are empty. + + ############################################################################# + # JSON, TOML + ############################################################################# + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-json # Validates JSON files to ensure they are properly formatted and syntactically correct. + types: [json] + - id: check-toml # Checks TOML files for errors and format issues to ensure valid syntax. + types: [toml] + + ############################################################################# + # Shell + ############################################################################# + - repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shfmt # Formats shell scripts to a standard convention using shfmt. + - id: shellcheck # Lints shell scripts to identify syntax and usage errors, with a specified severity of 'warning'. + args: + - --severity=warning + + ############################################################################# + # Python + ############################################################################# + - repo: https://github.com/PyCQA/autoflake + rev: v2.2.1 + hooks: + - id: autoflake # Removes unused imports and unused variables from Python code. + args: + - --in-place + - --remove-all-unused-imports + + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort # Sorts Python imports into sections and by alphabetical order. + args: + - --settings-path + - pyproject.toml + types: + - python + + - repo: https://github.com/psf/black + rev: 23.10.1 + hooks: + - id: black # Formats Python code to conform to the Black code style. + args: + - --config + - pyproject.toml + types: + - python + + - repo: https://github.com/pycqa/flake8 + rev: 6.1.0 + hooks: + - id: flake8 # Lints Python code for errors and code style issues based on PEP8. + args: + - --config=.cpa/flake8.cfg + types: + - python + + # - repo: https://github.com/astral-sh/ruff-pre-commit + # rev: v0.0.270 + # hooks: + # - id: ruff + + # - repo: https://github.com/python-poetry/poetry + # rev: '1.4.0' + # hooks: + # - id: poetry-check # Makes sure the poetry configuration does not get committed in a broken state. + # - id: poetry-lock # Ensures the poetry.lock file is up-to-date with the pyproject.toml changes. + + ############################################################################# + # CSS, Markdown, JavaScript, TypeScript, YAML style formatter + ############################################################################# + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.0.3 + hooks: + - id: prettier # An opinionated code formatter supporting multiple languages. + name: prettier + entry: prettier + args: [--config, .cpa/prettier.json, --write] + types_or: + - javascript + - ts + - tsx + - scss + - css + - yaml + - markdown diff --git a/example/Dockerfile b/example/Dockerfile new file mode 100644 index 0000000..1b4b414 --- /dev/null +++ b/example/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.10-slim + +# Set the working directory in the container to /app +WORKDIR /app + +# Copy the current directory contents into the container at /app +COPY . . + +# Install any needed packages specified in requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +CMD ["python", "./main.py"] diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..5c2a614 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,25 @@ +.PHONY: setuppc +setuppc: + @echo "Setting up pre-commit and hooks..." + python3 -m pip install pre-commit + pre-commit install + +ifeq ($(shell uname),Darwin) + @echo "Setting up shfmt (macOS)..." + brew install shfmt + + @echo "Setting up shellcheck (macOS)..." + brew install shellcheck +else + @echo "Setting up shfmt (Linux)..." + wget -qO shfmt "https://github.com/mvdan/sh/releases/download/v3.7.0/shfmt_v3.7.0_$(shell uname -m)" + chmod +x shfmt + sudo mv shfmt /usr/local/bin/shfmt + + @echo "Setting up shellcheck (Linux)..." + sudo apt-get install shellcheck || sudo yum install shellcheck || sudo dnf install shellcheck +endif + +.PHONY: reqtxt +reqtxt: + poetry export -f requirements.txt --output requirements.txt --without-hashes diff --git a/example/main.py b/example/main.py new file mode 100644 index 0000000..ad35e5a --- /dev/null +++ b/example/main.py @@ -0,0 +1 @@ +print("Hello World") diff --git a/example/pyproject.toml b/example/pyproject.toml new file mode 100644 index 0000000..65d53b1 --- /dev/null +++ b/example/pyproject.toml @@ -0,0 +1,62 @@ +[tool.poetry] +name = "example" +version = "0.0.1" +description = "" +authors = [ + "My Name " +] +license = "" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.black] +line-length = 120 +skip-string-normalization = false +target-version = ['py310'] +include = '\.pyi?$' +exclude = ''' +/( + \.eggs + | \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist +)/ +''' +color = true + +[tool.isort] +balanced_wrapping = true +include_trailing_comma = true +known_first_party = "example" +known_third_party = [ + "boto3", # Common for AWS + "django", # Common web framework, if used + "flask", # Common web framework, if used + "jinja2", # Common templating engine + "matplotlib", # Common for plotting + "numpy", # Common for numerical operations + "pandas", # Common for data manipulation + "pendulum", # Common for date time + "pytest", # Common for testing + "requests", # Common for HTTP requests + "sqlalchemy", # Common ORM for databases +] +multi_line_output = 3 +profile = "black" +line_length = 120 + +[tool.poetry.dependencies] +python = "^3.10" + +[tool.poetry.group.dev.dependencies] +pre-commit = "^3.5.0" +pytest = "^7.3.1" +pytest-cov = "^4.1.0" diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..8b5dd49 --- /dev/null +++ b/install.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +USER_REPO="ysawa0/create-python-app" +BINARY_NAME="cpa" +TARGET_DIR="$HOME/bin" + +# Determine OS type and corresponding download asset name +OS_TYPE="" +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + OS_TYPE="Linux" +elif [[ "$OSTYPE" == "darwin"* ]]; then + OS_TYPE="macOS" +else + echo "Unsupported operating system." + exit 1 +fi + +# Prepare the binary and zip names +ZIP_NAME="$BINARY_NAME-$OS_TYPE.zip" +ZIP_PATH="$TARGET_DIR/$ZIP_NAME" + +# Fetch the latest release data from GitHub API +DOWNLOAD_URL=$(curl -s https://api.github.com/repos/$USER_REPO/releases/latest | + grep "browser_download_url.*$OS_TYPE.zip" | + cut -d '"' -f 4) + +# Check if the download URL was found +if [ -z "$DOWNLOAD_URL" ]; then + echo "No release found for $OS_TYPE" + exit 1 +fi + +# Create the target directory if it doesn't exist +mkdir -p "$TARGET_DIR" + +# Download the zip file +curl -L -o "$ZIP_PATH" "$DOWNLOAD_URL" || { + echo "Failed to download the release" + exit 1 +} + +# Unzip the binary to the target directory +unzip -o "$ZIP_PATH" -d "$TARGET_DIR" || { + echo "Failed to unzip the release" + exit 1 +} + +# Assume the binary is named $BINARY_NAME inside the zip +BINARY_PATH="$TARGET_DIR/$BINARY_NAME" + +# Give execute permissions to the binary +chmod +x "$BINARY_PATH" || { + echo "Failed to set execute permissions on the binary" + exit 1 +} + +# Remove the downloaded zip +rm "$ZIP_PATH" + +# Optionally, append the target directory to PATH if it's not already there +if [[ ":$PATH:" != *":$TARGET_DIR:"* ]]; then + echo "export PATH=\$PATH:$TARGET_DIR" >>~/.bashrc + echo "$TARGET_DIR added to PATH" +fi + +echo "cpa installed to $BINARY_PATH" diff --git a/pypropoject.toml b/pyproject.toml similarity index 100% rename from pypropoject.toml rename to pyproject.toml diff --git a/src/main.rs b/src/main.rs index 70cfaa5..4639547 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,13 +14,13 @@ enum Cli { struct CreateArgs { #[clap(long, required = true)] name: String, - #[clap(long, required = false, default_value = "python")] + #[clap(long, required = false, default_value = "python3.10")] preset: String, } #[derive(Parser)] struct UpdateArgs { - #[clap(long, required = false, default_value = "python")] + #[clap(long, required = false, default_value = "python3.10")] preset: String, } diff --git a/src/python.rs b/src/python.rs index 5d6d767..4edd092 100644 --- a/src/python.rs +++ b/src/python.rs @@ -6,14 +6,27 @@ use std::fs::{self, File}; use std::io::Write; use std::process; +#[derive(Template)] +#[template(path = ".gitignore", escape = "none")] +struct GitIgnore {} + +#[derive(Template)] +#[template(path = "Makefile", escape = "none")] +struct Makefile {} + +#[derive(Template)] +#[template(path = "Dockerfile", escape = "none")] +struct Dockerfile {} + +#[derive(Template)] +#[template(path = "main.py", escape = "none")] +struct MainPy {} + #[derive(Template)] #[template(path = ".pre-commit-config.yaml", escape = "none")] struct PreCommitConfig { python: bool, } -#[derive(Template)] -#[template(path = ".gitignore", escape = "none")] -struct GitIgnore {} #[derive(Template)] #[template(path = "pyproject.toml", escape = "none")] @@ -37,38 +50,82 @@ pub fn derive_preset(mut preset: String, name: String) { } let _ = fs::create_dir_all(format!("./{}/.cpa", name)); - // Render gitignore - let gi = GitIgnore {}; - let out_gi = gi.render().expect("Failed to render"); - let mut file_gi = - File::create(format!("./{}/.gitignore", name)).expect("Could not create file"); - file_gi - .write_all(out_gi.as_bytes()) - .expect("Could not write to file"); + // Render .gitignore + File::create(format!("./{}/.gitignore", name)) + .and_then(|mut file| { + file.write_all( + GitIgnore {} + .render() + .expect("Failed to render .gitignore") + .as_bytes(), + ) + }) + .expect("Failed to create or write to .gitignore"); + + // Render Makefile + File::create(format!("./{}/Makefile", name)) + .and_then(|mut file| { + file.write_all( + Makefile {} + .render() + .expect("Failed to render Makefile") + .as_bytes(), + ) + }) + .expect("Failed to create or write to Makefile"); + + // Render Dockerfile + File::create(format!("./{}/Dockerfile", name)) + .and_then(|mut file| { + file.write_all( + Dockerfile {} + .render() + .expect("Failed to render Dockerfile") + .as_bytes(), + ) + }) + .expect("Failed to create or write to Dockerfile"); + + // Render main.py + File::create(format!("./{}/main.py", name)) + .and_then(|mut file| file.write_all(MainPy {}.render().expect("Render fail").as_bytes())) + .expect("Failed to render or write to main.py"); // Render pre-commit conf - let pc = PreCommitConfig { python: true }; - let out_pc = pc.render().expect("Failed to render"); - let mut file_pc = - File::create(format!("./{}/.pre-commit-config.yaml", name)).expect("Could not create file"); - file_pc - .write_all(out_pc.as_bytes()) - .expect("Could not write to file"); + File::create(format!("./{}/.pre-commit-config.yaml", name)) + .and_then(|mut file| { + file.write_all( + PreCommitConfig { python: true } + .render() + .expect("Failed to render .pre-commit-config.yaml") + .as_bytes(), + ) + }) + .expect("Failed to create or write to .pre-commit-config.yaml"); - // Render conf for each pre-commit hook - let f8 = Flake8 {}; - let out_f8 = f8.render().expect("Failed to render"); - let mut f_f8 = - File::create(format!("./{}/.cpa/flake8.cfg", name)).expect("Could not create file"); - f_f8.write_all(out_f8.as_bytes()) - .expect("Could not write to file"); + // Render Flake8 conf + File::create(format!("./{}/.cpa/flake8.cfg", name)) + .and_then(|mut file| { + file.write_all( + Flake8 {} + .render() + .expect("Failed to render flake8.cfg") + .as_bytes(), + ) + }) + .expect("Failed to create or write to flake8.cfg"); - let p = Prettier {}; - let out_p = p.render().expect("Failed to render"); - let mut f_p = - File::create(format!("./{}/.cpa/prettier.json", name)).expect("Could not create file"); - f_p.write_all(out_p.as_bytes()) - .expect("Could not write to file"); + // Render Prettier conf + File::create(format!("./{}/.cpa/prettier.json", name)) + .and_then(|mut file| { + file.write_all( + Prettier {} + .render() + .expect("Failed to render prettier.json") + .as_bytes(), + ) + }) + .expect("Failed to create or write to prettier.json"); // Render Poetry conf let re = Regex::new(r"python(3\.\d+|4\.\d+)").unwrap(); @@ -87,7 +144,7 @@ pub fn derive_preset(mut preset: String, name: String) { }; let out_pyproj: String = pyproj.render().expect("Failed to render"); let mut f_pyproj = - File::create(format!("./{}/pypropoject.toml", name)).expect("Could not create file"); + File::create(format!("./{}/pyproject.toml", name)).expect("Could not create file"); f_pyproj .write_all(out_pyproj.as_bytes()) .expect("Could not write to file"); diff --git a/templates/.pre-commit-config.yaml b/templates/.pre-commit-config.yaml index 2bca8eb..90fe6a5 100644 --- a/templates/.pre-commit-config.yaml +++ b/templates/.pre-commit-config.yaml @@ -59,7 +59,7 @@ repos: - id: isort # Sorts Python imports into sections and by alphabetical order. args: - --settings-path - - .cpa/pyproject.toml + - pyproject.toml types: - python @@ -69,7 +69,7 @@ repos: - id: black # Formats Python code to conform to the Black code style. args: - --config - - .cpa/pyproject.toml + - pyproject.toml types: - python diff --git a/templates/Dockerfile b/templates/Dockerfile new file mode 100644 index 0000000..1b4b414 --- /dev/null +++ b/templates/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.10-slim + +# Set the working directory in the container to /app +WORKDIR /app + +# Copy the current directory contents into the container at /app +COPY . . + +# Install any needed packages specified in requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +CMD ["python", "./main.py"] diff --git a/templates/Makefile b/templates/Makefile new file mode 100644 index 0000000..5c2a614 --- /dev/null +++ b/templates/Makefile @@ -0,0 +1,25 @@ +.PHONY: setuppc +setuppc: + @echo "Setting up pre-commit and hooks..." + python3 -m pip install pre-commit + pre-commit install + +ifeq ($(shell uname),Darwin) + @echo "Setting up shfmt (macOS)..." + brew install shfmt + + @echo "Setting up shellcheck (macOS)..." + brew install shellcheck +else + @echo "Setting up shfmt (Linux)..." + wget -qO shfmt "https://github.com/mvdan/sh/releases/download/v3.7.0/shfmt_v3.7.0_$(shell uname -m)" + chmod +x shfmt + sudo mv shfmt /usr/local/bin/shfmt + + @echo "Setting up shellcheck (Linux)..." + sudo apt-get install shellcheck || sudo yum install shellcheck || sudo dnf install shellcheck +endif + +.PHONY: reqtxt +reqtxt: + poetry export -f requirements.txt --output requirements.txt --without-hashes diff --git a/templates/main.py b/templates/main.py new file mode 100644 index 0000000..ad35e5a --- /dev/null +++ b/templates/main.py @@ -0,0 +1 @@ +print("Hello World")