Skip to content

Commit

Permalink
feat: prepare CI configuration files
Browse files Browse the repository at this point in the history
  • Loading branch information
MatteoGuadrini committed Sep 6, 2024
2 parents 86af8a4 + 4eafe55 commit 6e505ac
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 20 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release notes

## 0.0.6
Sep 06, 2024
- Add **prj_ci** function
- Fix _pyproject.toml_ file

## 0.0.5
Sep 02, 2024
- Add **prj_deps** function
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "psp"
version = "0.0.5"
version = "0.0.6"
edition = "2021"
authors = ["matteoguadrini <[email protected]>"]
description = "PSP (Python Scaffolding Projects)"
Expand Down
38 changes: 28 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,39 @@

```console
psp # Press Enter
Welcome to PSP (Python Scaffolding Projects): 0.0.5
Welcome to PSP (Python Scaffolding Projects): 0.0.6
> Name of Python project: test
> Do you want to start git repository? Yes
> Do you want unit test files? Yes
> Do you want to create a virtual environment? Yes
> Install dependencies: scipy numpy
> Select CI provider: CircleCI
Project `test` created
```

The result is

```console
tree test --filelimit=8
tree test --filelimit=8 -a
test # project folder
├── pyproject.toml # python package configuration file
├── .circleci # CI folder
│   └── config.yml # CI configuration file
├── .git # git folder
│   ├── branches
│   ├── config
│   ├── description
│   ├── HEAD
│   ├── hooks [14 entries exceeds filelimit, not opening dir]
│   ├── info
│   │   └── exclude
│   ├── objects
│   │   ├── info
│   │   └── pack
│   └── refs
│   ├── heads
│   └── tags
├── .gitignore # git ignore file
├── test # python package
│   └── __init__.py
├── tests # tests package for modules
Expand Down Expand Up @@ -72,7 +91,7 @@ test # project folder
├── lib64 -> lib
└── pyvenv.cfg

22 directories, 32 files
33 directories, 39 files
```

> This project is WIP
Expand All @@ -91,16 +110,16 @@ To install compiled file into your machine, download it:
```console
# For Linux (all users)
sudo -i
curl -L https://github.com/MatteoGuadrini/psp/releases/download/v0.0.5/psp_linux > /usr/bin/psp
curl -L https://github.com/MatteoGuadrini/psp/releases/download/v0.0.6/psp_linux > /usr/bin/psp
chmod +x /usr/bin/psp

# For Linux (current user)
curl -L https://github.com/MatteoGuadrini/psp/releases/download/v0.0.5/psp_linux > $HOME/.local/bin/psp
curl -L https://github.com/MatteoGuadrini/psp/releases/download/v0.0.6/psp_linux > $HOME/.local/bin/psp
chmod +x $HOME/.local/bin/psp

# For MacOS
sudo su -
curl -L https://github.com/MatteoGuadrini/psp/releases/download/v0.0.5/psp_macos > /usr/bin/psp
curl -L https://github.com/MatteoGuadrini/psp/releases/download/v0.0.6/psp_macos > /usr/bin/psp
chmod +x /usr/bin/psp
```

Expand All @@ -117,11 +136,10 @@ cd psp && cargo build && sudo cp -var target/release/psp /usr/bin/psp
- [x] Prepare git and gitignore
- [x] Prepare unit test files (also with pytest)
- [x] Prepare virtual environment
- [ ] Install dependencies
- [ ] Prepare pyproject.toml
- [ ] Prepare CI configuration files
- [x] Install dependencies
- [x] Prepare pyproject.toml
- [x] Prepare CI configuration files
- [ ] Prepare Github/Gitlab files
- [ ] Prepare virtual environment
- [ ] Prepare tox environment
- [ ] Prepare docs folder for sphinx/mkdocs documentation
- [ ] Prepare README, LICENSE, CONTRIBUTING, CODE_OF_CONDUCT and CHANGES files
Expand Down
172 changes: 163 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use inquire::{Confirm, Text};
use inquire::{Confirm, Select, Text};
use std::{
env::var,
fs::{create_dir_all, File},
Expand All @@ -8,7 +8,7 @@ use std::{
};

// Constants
const VERSION: &str = "0.0.5";
const VERSION: &str = "0.0.6";

// Utility functions

Expand Down Expand Up @@ -73,6 +73,18 @@ fn prompt_confirm(question: &str, default: bool, help: &str) -> bool {
answer.unwrap()
}

// Function for prompt selections
fn prompt_select(question: &str, options: Vec<&str>, help: &str) -> String {
let answer = if help != "None" {
Select::new(question, options)
.with_help_message(help)
.prompt()
} else {
Select::new(question, options).prompt()
};
answer.unwrap().to_string()
}

// Core functions

// Project name
Expand All @@ -93,7 +105,10 @@ fn prj_name() -> String {
// Make file structures
let file_ret = make_file(
format!("{project}/__init__.py").as_str(),
"#! /usr/bin/env python3\n\n".to_string(),
"#! /usr/bin/env python3\n\
# -*- encoding: utf-8 -*-\n\
# vim: se ts=4 et syn=python:\n\n\n"
.to_string(),
);
match file_ret {
Err(e) => {
Expand Down Expand Up @@ -184,7 +199,10 @@ fn prj_test(name: &str) {
// Make file structures
let init_file = make_file(
format!("{name}/tests/__init__.py").as_str(),
"#! /usr/bin/env python3\n\n".to_string(),
"#! /usr/bin/env python3\n\
# -*- encoding: utf-8 -*-\n\
# vim: se ts=4 et syn=python:\n\n\n"
.to_string(),
);
match init_file {
Err(e) => {
Expand All @@ -193,17 +211,22 @@ fn prj_test(name: &str) {
}
Ok(_) => (),
}
let project_name = name.to_lowercase();
let all_module = make_file(
format!("{name}/tests/test_{name}.py").as_str(),
format!(
"#! /usr/bin/env python3\n\n\n\
"#! /usr/bin/env python3\n\
# -*- encoding: utf-8 -*-\n\
# vim: se ts=4 et syn=python:\n\n\n\
import unittest\n\n\n\
class TestAll(unittest.TestCase):\n\n\
\tdef test_all(self):\n\
\t\tprint('Test all {} successfully!')\n\n\n\
\t\tprint('Test all {project_name} successfully!')\n\n\n\
# Test functions for pytest\n\
def test_all():\n\
\tassert '{project_name}' == '{project_name}'\n\n\n\
if __name__ == '__main__':\n\
\tunittest.main()",
name.to_lowercase()
\tunittest.main()"
)
.to_string(),
);
Expand Down Expand Up @@ -271,6 +294,133 @@ fn prj_deps(name: &str, venv: bool) -> Vec<String> {
dependencies
}

// Project pyproject.toml
fn prj_toml(name: &str, deps: &Vec<String>) {
let requirements = if deps.contains(&"No".to_string()) {
"[]".to_string()
} else {
format!("{deps:?}")
};
let content = format!(
"[build-system]\n\
requires = ['setuptools', 'wheel']\n\
build-backend = 'setuptools.build_meta'\n\n\
[project]\n\
name = '{}'\n\
version = '0.0.1'\n\
readme = 'README.md'\n\
license = ''\n\
authors = [{{name = 'psp', email = '[email protected]'}}]\n\
maintainers = [{{name = 'psp', email = '[email protected]'}}]\n\
description = 'A simple but structured Python project'\n\
requires-python = '>=3.12'\n\
classifiers = ['Programming Language :: Python :: 3']\n\
dependencies = {}\n\n\
[project.urls]\n\
homepage = ''\n\
documentation = ''\n\
repository = ''\n\
changelog = ''\n
",
name.to_lowercase(),
requirements
);
// Write pyproject.toml
let pyproject = make_file(format!("{name}/pyproject.toml").as_str(), content);
match pyproject {
Err(e) => {
eprintln!("error: {}", e);
exit(7);
}
Ok(_) => (),
}
}

// Project CI
fn prj_ci(name: &str, deps: &Vec<String>) {
let options = vec!["None", "TravisCI", "CircleCI"];
let ci = prompt_select("Select CI provider:", options, "None");
let requirements = if deps.contains(&"No".to_string()) {
"".to_string()
} else {
deps.join(" ")
};
// Travis or CircleCI
if ci.as_str() == "TravisCI" {
let travis = make_file(
format!("{name}/.travis.yml").as_str(),
format!(
"language: python\n\
cache: pip\n\
python:\n\
\t- 3.10\n\
\t- 3.11\n\
\t- 3.12\n\
before_install:\n\
\t- sudo apt-get update\n\
\t- sudo apt-get install python3-pip\n\
\t- sudo apt-get install python3-pytest\n\
install:\n\
\t- pip install {requirements} pipenv\n\
\t- pipenv install --dev\n\
script:\n\
\t- python -m unittest discover tests\n\
\t- pytest tests
"
),
);
match travis {
Err(e) => {
eprintln!("error: {}", e);
}
Ok(_) => (),
}
} else if ci.as_str() == "CircleCI" {
let dir_ret = make_dirs(format!("{name}/.circleci").as_str());
match dir_ret {
Err(e) => {
eprintln!("error: {}", e);
}
Ok(_) => (),
}
let circle = make_file(
format!("{name}/.circleci/config.yml").as_str(),
format!(
"version: 2.1\n\
jobs:\n\
\tbuild-and-test:\n\
\t\tdocker:\n\
\t\t\t- image: circleci/python\n\
\t\tsteps:\n\
\t\t\t- checkout\n\
\t\t\t- run:\n\
\t\t\t\t\tname: Install pytest\n\
\t\t\t\t\tcommand: pip install pytest\n\
\t\t\t- run:\n\
\t\t\t\t\tname: Install dependencies\n\
\t\t\t\t\tcommand: pip install {requirements}\n\
\t\t\t- run:\n\
\t\t\t\t\tname: Install package\n\
\t\t\t\t\tcommand: pip install .\n\
\t\t\t- run:\n\
\t\t\t\t\tname: Run tests\n\
\t\t\t\t\tcommand: python -m pytest tests\n\
\tworkflows:\n\
\t\tmain:\n\
\t\t\tjobs:\n\
\t\t\t\t- build-and-test\n
"
),
);
match circle {
Err(e) => {
eprintln!("error: {}", e);
}
Ok(_) => (),
}
}
}

// Main program
fn main() {
// Print welcome screen and version
Expand All @@ -288,7 +438,11 @@ fn main() {
// Virtual Environment
let venv = prj_venv(&name);
// Install dependencies
let _deps = prj_deps(&name, venv);
let deps = prj_deps(&name, venv);
// CI configuration
prj_ci(&name, &deps);
// Write pyproject.toml
prj_toml(&name, &deps);
// Finish scaffolding process
println!("Project `{name}` created")
}

0 comments on commit 6e505ac

Please sign in to comment.