diff --git a/.github/workflows/format-lint.yml b/.github/workflows/format-lint.yml index 900b417..67c010b 100644 --- a/.github/workflows/format-lint.yml +++ b/.github/workflows/format-lint.yml @@ -26,6 +26,10 @@ jobs: - uses: actions/checkout@v4 - name: Install clang-tidy and clang-format run: sudo apt-get update && sudo apt-get install -y cmake clang + - name: Install Doxygen + run: sudo apt-get install -y doxygen + - name: Check if documentation is complete + run: doxygen Doxyfile - name: Find C++ Packages, and then Format and Lint run: | for pkg in $(find . -name CMakeLists.txt -exec dirname {} \;); do diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cee4243 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "iis.configDir": "" +} \ No newline at end of file diff --git a/Doxyfile b/Doxyfile index 735ebfb..7a554de 100644 --- a/Doxyfile +++ b/Doxyfile @@ -917,7 +917,7 @@ WARN_IF_INCOMPLETE_DOC = YES # WARN_IF_INCOMPLETE_DOC # The default value is: NO. -WARN_NO_PARAMDOC = NO +WARN_NO_PARAMDOC = YES # If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about # undocumented enumeration values. If set to NO, Doxygen will accept @@ -949,7 +949,7 @@ WARN_LAYOUT_FILE = YES # Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. -WARN_AS_ERROR = NO +WARN_AS_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that Doxygen # can produce. The string should contain the $file, $line, and $text tags, which diff --git a/README.md b/README.md index 57ce665..dcf1ad6 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This template introduces a certain structure so that users and contributors can └── usage/ # Examples and tutorials All code is stored in `lib/` and organized into packages, either C++ or Python packages.\ -All documentation, on the other hand, is stored in `docs/`. Documentation is a crucial aspect of this template. Using **Sphinx** with **Doxygen** via **Breathe**, code documentation is automated based on docstrings/comments and enriched with more info provided by the developers using **reStructuredText (reST)**. Together with GitHub Actions, this allows enforcement of consistent documentation practices across Python and C++ codebases. In this way: +All documentation, on the other hand, is stored in `docs/`. Documentation is a crucial aspect of this template. Using **Sphinx** with **Doxygen** via **Breathe**, code documentation is automated based on comments/docstrings and enriched with more info provided by the developers using **reStructuredText (reST)**. Together with GitHub Actions, this allows enforcement of consistent documentation practices across C++ and Python codebases. In this way: * Documentation stays up-to-date with code changes. * Documentation is organized and easily navigable. @@ -28,9 +28,9 @@ All documentation, on the other hand, is stored in `docs/`. Documentation is a c ## Main Features ### Documentation Tools -- **Sphinx** — Primary tool for generating project documentation - - Supports both **reStructuredText (.rst)** and **Markdown (.md)** formats. +- **Sphinx** — Primary tool for generating project documentation - Primarily uses reStructuredText, including its directives and extensions to produce documentation. + - Supports both **reStructuredText (.rst)** and **Markdown (.md)** formats. - **Doxygen** — Specialized for C++ code documentation - Produces **HTML output** for standalone C++ docs (found in `docs/doxygen/html`). @@ -39,7 +39,7 @@ All documentation, on the other hand, is stored in `docs/`. Documentation is a c ### GitHub Actions - **Formatting**: Automatic styling (ruff format for Python, clang-format for C++) before merging into main - **Linting**: Automatic linting (ruff for Python, clang-tidy for C++) before merging into main -- **Documentation**: Automatic build and deployment to GitHub Pages after merging into main +- **Documentation**: Automatic build and deployment to GitHub Pages when updating main ## Before Using This Template If you haven't done so already, check the following: @@ -53,16 +53,45 @@ Do you think that's not enough? If not, then checking the following is highly re - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html) - [Doxygen Documenting Code Guide](https://www.doxygen.nl/manual/docblocks.html) - [Clang-Tidy](https://clang.llvm.org/extra/clang-tidy/index.html) and [Clang-Format](https://clang.llvm.org/docs/ClangFormat.html) -- [Ruff](https://docs.astral.sh/ruff/) +- [Ruff Formatter](https://docs.astral.sh/ruff/formatter/) and [Ruff Linter](https://docs.astral.sh/ruff/linter/) ## To Produce Documentation Locally: Assuming you are in the root directory of this project and have a Python envioment to work with: 1. Install Python dependencies: ```bash pip install -r requirements-docs.txt + ``` +2. Install Doxygen from [here](https://www.doxygen.nl/download.html). +3. Build your documentation + ```bash doxygen Doxyfile # If there are any C++ packages sphinx-build -b html docs build/html ``` +## Maintaining Your Code +When using this template, repository-level rulesets are NOT copied into the new repository. Project owners must configure these protections themselves in the repository settings. + +Why protect main? +- Prevents direct pushes and accidental changes to main. +- Ensures CI (formatting, linting, testing, etc) runs and passes before code is merged. +- Keeps main stable for releases and documentation builds. + +Template's Linting / formatting behavior +- The template’s GitHub Actions jobs for formatting and linting are intended to run on pull requests. +- Only merge into main after the required status checks pass on the PR. + +Recommended minimal branch-protection rule (GitHub: Settings → Branches → Add branch ruleset) on the main branch: +- Restrict deletions +- Require a pull request before merging + - Require review from Code Owners + - Require conversation resolution before merging +- Require status checks to pass (select cpp-format-lint and python-format-lint) + - Require branches to be up to date before merging + - Do not require status checks on creation +- Block force pushes +- Optionally enable: include administrators, require linear history + +At minimum, create a rule that enforces updates to main only via pull requests with passing status checks. + ## License This template is licensed under the terms in `LICENSE`. diff --git a/docs/README.md b/docs/README.md index 8f3cb38..2305013 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,7 +30,7 @@ All of our documentation is stored and handled in `docs/`. The directory tree be ├─ example.md # Example of using a feature or some features from a package └─ ... -Each directory contains an `index.rst` file, which serves as an entry point. In each index file, we can reference index files from subdirectories. In this way, it is possible to create pages and subpages in order to make a structured and organized documentation web page. The main `index.rst` is located in the source directory of the documentation setup. We can also use Markdown within reStructuredText. This allows some specific documentation intended for display on GitHub to be included in the main documentation. `conf.py` is the central configuration file that defines how the documentation is built and styled. It sets project details, enables extensions, chooses the theme, and controls paths and output formats. Essentially, it's the settings file that tells **Sphinx** what to include and how to present it. +Each directory contains an `index.rst` file (**reStructuredText (reSET)** file), which serves as an entry point. In each index file, we can reference index files from subdirectories. In this way, it is possible to create pages and subpages in order to make a structured and organized documentation web page. The main `index.rst` is located in the source directory of the documentation setup. We can also use Markdown within reStructuredText. This allows some specific documentation intended for display on GitHub to be included in the main documentation. `conf.py` is the central configuration file that defines how the documentation is built and styled. It sets project details, enables extensions, chooses the theme, and controls paths and output formats. Essentially, it's the settings file that tells **Sphinx** what to include and how to present it. ### Main Entry Point @@ -44,10 +44,10 @@ This is the landing section of the project with an overview. A good overview bri Here, an overall architecture is presented. If this project delivers a certain solution, this section should explain what this solution entails. Diagrams (generated by Mermaid) are used to visually explain the architecture. This section contains the following: -* A diagram with an explanation of the overall architecture and the high-level components. -* Info about how these components interact. -* (Recommended Optional) Additional diagrams with detailed explanations of the components. -* (Optional) A list of constraints and trade-offs. +* A diagram with an explanation of the overall architecture and the high-level components +* Info about how these components interact +* (Recommended Optional) Additional diagrams with detailed explanations of the components +* (Optional) A list of constraints and trade-offs Example Mermaid snippet (in an `.rst` or `.md` doc): ```mermaid @@ -58,15 +58,14 @@ graph LR ``` Note that each component should have its own documentation page(s) describing its role, responsibility, use, configuration, and diagrams where useful. More details can be added if necessary. -Here’s your original text with **only grammatical corrections**, keeping all content intact: ### Code Documentation ---------------------- -Code documentation primarily depends on docstrings/comments written in the code. For you as a developer, if you are writing code in: +Code documentation primarily depends on comments/docstrings written in the code. For you as a developer, if you are writing code in: -- **C++**: Use Doxygen-style comments (check Doxygen's Documenting the Code Guide); **Doxygen** produces XML-based documentation, which is used by **Breathe** to integrate into **Sphinx**. **Breathe**-specific directives are used (e.g., `doxygenclass`) to achieve this integration. -- **Python**: Use NumPy-style docstrings (check numpydoc's Style Guide). **Sphinx** extensions (e.g., `automodule`) are used to pull documentation from docstrings. +- **C++**: Use Doxygen-style comments (check [Doxygen Documenting Code Guide](https://www.doxygen.nl/manual/docblocks.html)); **Doxygen** produces XML-based documentation, which is used by **Breathe** to integrate into **Sphinx**. **Breathe**-specific directives are used (e.g., `doxygenclass`) to achieve this integration. +- **Python**: Use NumPy-style docstrings (check [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)). **Sphinx** extensions (e.g., `automodule`) are used to pull documentation from docstrings. A C++ example from `math_utils.hpp`: @@ -98,9 +97,22 @@ def square(x): return x * x ``` -**Sphinx** uses **reStructuredText (reST)** as its markup language to generate structured documentation. Therefore, our documentation should technically be stored in `.rst` files. In these files, we declare the **directives** and **extensions**. +**Sphinx** uses **reStructuredText (reST)** as its markup language to generate structured documentation. Therefore, our documentation should technically be defined in `.rst` files. In these files, we declare the **directives** and **extensions**. -Directives are special instructions in reST that tell **Sphinx** how to include and format content. An extension is a Python module that provides additional features for **Sphinx** projects. For example, to use **Sphinx** on Python code, the `autodoc` extension is often used to automatically pull in docstrings from the source code: +Directives are special instructions in reST that tell **Sphinx** how to include and format content. An extension is a Python module that provides additional features for **Sphinx** projects. + +For example, to use **Sphinx** on C++ code, `autodoc` cannot be used, since it is made for Python. But we can use **Breathe**’s set of directives. They may not be as powerful as `autodoc`, but are still useful in our use case. + +```rst +Math Utilities +-------------- + +.. doxygenclass:: math_utils::Calculator + :project: cpp_pkg + :members: +``` + +To use **Sphinx** on Python code, the `autodoc` extension is often used to automatically pull in docstrings from the source code: ```rst .. automodule:: py_pkg.math_utils @@ -111,16 +123,7 @@ Directives are special instructions in reST that tell **Sphinx** how to include This directive tells **Sphinx** to document the `math_utils` module, including all its members—even those without docstrings—and to show class inheritance. -To use **Sphinx** on C++ code, `autodoc` cannot be used, since it is made for Python. But we can use **Breathe**’s set of directives. They may not be as powerful as `autodoc`, but are still useful in our use case. -```rst -Math Utilities --------------- - -.. doxygenclass:: math_utils::Calculator - :project: cpp_pkg - :members: -``` All this is nice, but writing docstrings/comments alone and using directives and extensions is not sufficient for proper documentation. While some of them are powerful in automatically extracting and displaying documentation from source code, they work best when combined with additional narrative content written in reStructuredText. Writing introductions, explanations, usage examples, and conceptual overviews alongside directives and extensions helps provide context, guide the reader, and make the documentation more accessible and educational. This blend of auto-generated and hand-written content results in a more complete and user-friendly documentation experience. Here is an example of how you can enrich the documentation: @@ -146,20 +149,20 @@ Remember that the file structure in documentation is package-based, i.e., each p In order to quickly start working with the project and provide value for users, a set of examples must be provided. Each example should ideally include an explanation of a use case, a demonstration, and output explanation. The examples should highlight the main features of your solution and explain the usage in a user-friendly way. This may also provide some guidance on how to develop a user-friendly solution. ## Documentation Workflow -1. Document your code using the appropriate style (NumPy for Python, Doxygen for C++). -2. Create a reST file in `/docs/documentation/` with the package name you want to document. - - - **For a Python package**: - **Sphinx** can access your Python packages. Therefore, there is no need for any additional configuration. +1. Document your code using the appropriate style (Doxygen for C++, NumPy for Python). +2. Create a reST file in `/docs/code/` with the package name you want to document. (The current template has two code documentation subdirectories, one for C++ packages, the other for Python packages) - **For a C++ package**: Since **Sphinx** relies on **Doxygen** to get the documentation, it is required to specify the files and/or directories that contain documented source files in **Doxyfile**. Find the key `INPUT`in **Doxyfile**, and add the appropriate paths. -3. Add any necessary directives, extensions, and content enrichments. See an example here: [cpp_pkg.rst](/docs/code/cpp_pkgs/cpp_pkg.rst) -4. (Optional) Build docs locally and check them in `/build/html` before pushing: + - **For a Python package**: + **Sphinx** can access your Python packages based on the paths you specify in `conf.py`. + +3. Add any necessary directives, extensions, and content enrichments. See an example here: [cpp_pkg.rst](/docs/code/cpp_pkgs/cpp_pkg.rst). +4. (Recommended optional) Build docs locally and check them in `/build/html` before pushing: ```bash doxygen Doxyfile # If there are any C++ packages sphinx-build -b html docs build/html ``` 5. Push changes – GitHub Actions will automatically: - - Build and deploy documentation when successfully merging into main \ No newline at end of file + - Build and deploy documentation when successfully merging into main. \ No newline at end of file diff --git a/docs/doxygen/html/doxygen_crawl.html b/docs/doxygen/html/doxygen_crawl.html index f54aa76..e69de29 100644 --- a/docs/doxygen/html/doxygen_crawl.html +++ b/docs/doxygen/html/doxygen_crawl.html @@ -1,40 +0,0 @@ - - - -Validator / crawler helper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/doxygen/html/math__utils_8hpp.html b/docs/doxygen/html/math__utils_8hpp.html index 58289a2..e69de29 100644 --- a/docs/doxygen/html/math__utils_8hpp.html +++ b/docs/doxygen/html/math__utils_8hpp.html @@ -1,163 +0,0 @@ - - - - - - - -My C++ Project: lib/cpp_pkg/include/math_utils.hpp File Reference - - - - - - - - - - - - - - -
-
- - - - - - -
-
My C++ Project -
-
-
- - - - - - - - -
-
- -
-
-
- -
-
- -
-
- - -
-
-
-
-
-
Loading...
-
Searching...
-
No Matches
-
-
-
-
- -
-
math_utils.hpp File Reference
-
-
- -

A dummy math utility module for demonstration. -More...

- -

Go to the source code of this file.

- - - - -

-Classes

class  math_utils::Calculator
 A simple calculator class for basic arithmetic operations. More...
- - - -

-Functions

double math_utils::square (double x)
 Calculate the square of a number.
- - - -

-Variables

-constexpr double math_utils::PI = 3.14159
 The mathematical constant pi.
-

Detailed Description

-

A dummy math utility module for demonstration.

-

Function Documentation

- -

◆ square()

- -
-
- - - - - - - -
double math_utils::square (double x)
-
- -

Calculate the square of a number.

-
Parameters
- - -
xThe number to be squared.
-
-
-
Returns
The square of the input number.
- -
-
-
-
- -
- - - - diff --git a/docs/doxygen/html/math__utils_8hpp_source.html b/docs/doxygen/html/math__utils_8hpp_source.html index b06cac8..3892104 100644 --- a/docs/doxygen/html/math__utils_8hpp_source.html +++ b/docs/doxygen/html/math__utils_8hpp_source.html @@ -98,29 +98,29 @@
8namespace math_utils {
9
11constexpr double PI = 3.14159;
-
12
-
18double square(double x);
-
19
-
-
23class Calculator {
-
24public:
-
31 double add(double a, double b);
-
32
-
39 double subtract(double a, double b);
-
40
-
47 double multiply(double a, double b);
-
48
-
56 double divide(double a, double b);
-
57};
+
12
+
13
+
14double square(double x);
+
15
+
+ +
20public:
+
27 double add(double a, double b);
+
28
+
35 double subtract(double a, double b);
+
36
+
43 double multiply(double a, double b);
+
44
+
52 double divide(double a, double b);
+
53};
-
58
-
59} // namespace math_utils
-
A simple calculator class for basic arithmetic operations.
Definition math_utils.hpp:23
+
54
+
55} // namespace math_utils
+
A simple calculator class for basic arithmetic operations.
Definition math_utils.hpp:19
double add(double a, double b)
Add two numbers.
Definition math_utils.cpp:8
double subtract(double a, double b)
Subtract one number from another.
Definition math_utils.cpp:10
double multiply(double a, double b)
Multiply two numbers.
Definition math_utils.cpp:12
double divide(double a, double b)
Divide one number by another.
Definition math_utils.cpp:14
-
double square(double x)
Calculate the square of a number.
Definition math_utils.cpp:6
constexpr double PI
The mathematical constant pi.
Definition math_utils.hpp:11
diff --git a/docs/doxygen/html/search/all_6.js b/docs/doxygen/html/search/all_6.js index 003454e..5c73695 100644 --- a/docs/doxygen/html/search/all_6.js +++ b/docs/doxygen/html/search/all_6.js @@ -1,8 +1,7 @@ var searchData= [ ['shout_0',['shout',['../string__utils_8hpp.html#a846b06166c7acbde7cf9e2a457f628e3',1,'string_utils']]], - ['square_1',['square',['../math__utils_8hpp.html#a5a6ea77164a9ce3c89c66f186228bf08',1,'math_utils']]], - ['string_5futils_2ehpp_2',['string_utils.hpp',['../string__utils_8hpp.html',1,'']]], - ['subtract_3',['subtract',['../classmath__utils_1_1_calculator.html#a4761e091532dd7b2b3aa5b05d462e745',1,'math_utils::Calculator']]], - ['surround_4',['surround',['../classstring__utils_1_1_formatter.html#a72c83ffa1f6f2564f47f70137d215d56',1,'string_utils::Formatter']]] + ['string_5futils_2ehpp_1',['string_utils.hpp',['../string__utils_8hpp.html',1,'']]], + ['subtract_2',['subtract',['../classmath__utils_1_1_calculator.html#a4761e091532dd7b2b3aa5b05d462e745',1,'math_utils::Calculator']]], + ['surround_3',['surround',['../classstring__utils_1_1_formatter.html#a72c83ffa1f6f2564f47f70137d215d56',1,'string_utils::Formatter']]] ]; diff --git a/docs/doxygen/html/search/functions_3.js b/docs/doxygen/html/search/functions_3.js index e2066ac..e769f4f 100644 --- a/docs/doxygen/html/search/functions_3.js +++ b/docs/doxygen/html/search/functions_3.js @@ -1,7 +1,6 @@ var searchData= [ ['shout_0',['shout',['../string__utils_8hpp.html#a846b06166c7acbde7cf9e2a457f628e3',1,'string_utils']]], - ['square_1',['square',['../math__utils_8hpp.html#a5a6ea77164a9ce3c89c66f186228bf08',1,'math_utils']]], - ['subtract_2',['subtract',['../classmath__utils_1_1_calculator.html#a4761e091532dd7b2b3aa5b05d462e745',1,'math_utils::Calculator']]], - ['surround_3',['surround',['../classstring__utils_1_1_formatter.html#a72c83ffa1f6f2564f47f70137d215d56',1,'string_utils::Formatter']]] + ['subtract_1',['subtract',['../classmath__utils_1_1_calculator.html#a4761e091532dd7b2b3aa5b05d462e745',1,'math_utils::Calculator']]], + ['surround_2',['surround',['../classstring__utils_1_1_formatter.html#a72c83ffa1f6f2564f47f70137d215d56',1,'string_utils::Formatter']]] ]; diff --git a/docs/doxygen/xml/Doxyfile.xml b/docs/doxygen/xml/Doxyfile.xml index 9d7fa10..389dabc 100644 --- a/docs/doxygen/xml/Doxyfile.xml +++ b/docs/doxygen/xml/Doxyfile.xml @@ -120,10 +120,10 @@ - + - + diff --git a/docs/index.rst b/docs/index.rst index d9885ea..041dde8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,15 +5,15 @@ Overview -------- .. note:: - A project overview should briefly describe the scope, purpose, and goals of the project. It helps users quickly understand what the project is about and why it exists. - When writing an overview, mention the main problem the project solves, its target audience, and any unique features or technologies it uses. + *A project overview should briefly describe the scope, purpose, and goals of the project. It helps users quickly understand what the project is about and why it exists. + When writing an overview, mention the main problem the project solves, its target audience, and any unique features or technologies it uses.* - **Example:** + ***Example:*** - This project provides a stadaridized template for DALSA GitHub repositories, designed to help project owners quickly set up new projects with a consistent structure and DevOps features. + *This project provides a stadaridized template for DALSA GitHub repositories, designed to help project owners quickly set up new projects with a consistent structure and DevOps features. Its goal is to ensure maintainability and collaboration by enforcing standards that make future contributions and usage seamless. The template integrates Sphinx + Doxygen for unified documentation of both Python and C++ packages, and uses GitHub Actions to automate generation of web-based documentation, code analyis (linting), code rewrites to follow a - consistent style (formatting), and execution of tests. + consistent style (formatting), and execution of tests.* Here you will find a full description of the project's architecture and core concepts, detailed documentation of all packages, and practical usage examples. This guide is designed to help you understand the structure and functionality of the project, making it easier to get started and make effective use of its features. diff --git a/lib/README.md b/lib/README.md index 576eac9..2679520 100644 --- a/lib/README.md +++ b/lib/README.md @@ -53,7 +53,7 @@ py_pkg This follows a typical Python project layout: (`poetry new py_pkg` was used to create the layout) - `pyproject.toml` for package configuration -- `src/` for implementation (actual Python package lives in src/py_pkg/) +- `src/` for implementation (actual Python package lives in `src/py_pkg/`) - `tests/` for testing - `README.md` for package introductions @@ -61,16 +61,16 @@ This follows a typical Python project layout: (`poetry new py_pkg` was used to c > Remember, you can customize the layout of your package as much as needed to suit your specific requirements. The only requirement is that each package you create must be **modular** and **self-contained**. -A **modular** package is designed to encapsulate a specific functionality or domain, making it easy to understand, maintain, and reuse independently or as part of a larger system. It should expose clear interfaces and avoid unnecessary coupling with other packages. +A ***modular*** package is designed to encapsulate a specific functionality or domain, making it easy to understand, maintain, and reuse independently or as part of a larger system. It should expose clear interfaces and avoid unnecessary coupling with other packages. -A **self-contained** package means it includes everything necessary to build, run, test, and document itself without relying on external parts of the repository. This typically includes: +A ***self-contained*** package means it includes everything necessary to build, run, test, and document itself without relying on external parts of the repository. This typically includes: - Its own source code - Build or configuration files (e.g., `CMakeLists.txt` or `pyproject.toml`) - Tests - Documentation (e.g., `README.md`) - Instructions or mechanisms for installing dependencies -Together, being **modular** and **self-contained** ensures that each package can be developed, tested, and deployed independently, which improves maintainability, scalability, and collaboration across teams. +Together, being ***modular*** and ***self-contained*** ensures that each package can be developed, tested, and deployed independently, which improves maintainability, scalability, and collaboration across teams. --- @@ -83,7 +83,7 @@ Together, being **modular** and **self-contained** ensures that each package can - **Formatting**: `clang-format` - **Linting**: `clang-tidy` -> If you want to use the same tools (CMake, Clang and Ninja), make sure to install them in your machine. +> If you want to try building the same we did, make sure to install CMake, Clang and Ninja in your machine. Assuming you are in the root directory of the package: @@ -98,6 +98,8 @@ cmake -S . -B build -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=cl cmake --build build ``` +--- + ### Python (`py_pkg`) - **Packaging and Dependency Management Tool**: Poetry - **Configuration Tool**: pyproject.toml @@ -105,7 +107,7 @@ cmake --build build > Remember that with Python no build step is required. -Assuming you are in the root directory of the package: +Assuming you are in the root directory of the package and have a Python envioment to work with: To install the package: ```bash @@ -157,7 +159,32 @@ Write tests using your preferred framework. This template does not enforce any s ## Development Golden Rules - Always keep your packages **modular** and **self-contained**. -- Document your code as much as possible. +- Document your code. - Format and lint (This step can make you to refactor your code). -- Write tests for any new functionality you add and check whehter it behaves as expected. -- (Advacnced) Use GitHub Actions to enforce quality gates. \ No newline at end of file +- Write tests for any new functionality you add and check whether it behaves as expected. +- (Advacnced) Use GitHub Actions to enforce functional gates. + +--- + +## DevOps + +This template integrates GitHub Actions to automate common DevOps tasks for both C++ and Python packages. Changes to main must be made via pull requests so CI can run the automated jobs that format, lint, and validate code and documentation before merging. + +How it works +- On every pull request the workflow searches the repository for packages: + - A C++ package is identified by a `CMakeLists.txt` file. + - A Python package is identified by a `pyproject.toml` file. +- For each discovered package the jobs: + - Format source files (`clang-format` for C++, `ruff format` for Python). + - Run linters (`clang-tidy` for C++, `ruff check` for Python). + - *This also includes checking documentation completeness and correctness. Note that Clang does not have a straight forward way to do so; however, Doxygen has. So, Doxygen is used to produce documentation, and warnings like documentation is not available are treated as errors.* +- If linting find errors, the related status checks fail and GitHub will block merging the pull request until the issues are fixed. + +Why this matters +- Prevents regressions by enforcing checks on every change. +- Keeps main stable and ready for releases. +- Ensures contributors address any issues early in the review cycle rather than after merging. + +Recommendation +- Do not push directly to main. Require pull requests and configure branch protection rules, so merges are only allowed when the required status checks pass. +- Ensure each package in the repo is modular and self-contained. \ No newline at end of file diff --git a/lib/py_pkg/pyproject.toml b/lib/py_pkg/pyproject.toml index 2ee2a4d..7895aa8 100644 --- a/lib/py_pkg/pyproject.toml +++ b/lib/py_pkg/pyproject.toml @@ -19,6 +19,6 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] line-length = 88 -lint.select = ["E", "F", "I", "B"] # E: pycodestyle, F: pyflakes, I: isort, B: flake8-bugbear -lint.ignore = ["E501"] +lint.select = ["E", "F", "I", "B", "D"] # E: pycodestyle, F: pyflakes, I: isort, B: flake8-bugbear, D: pydocstyle rules +lint.ignore = ["E501", "D100", "D104"] target-version = "py312" \ No newline at end of file diff --git a/lib/py_pkg/src/py_pkg/math_utils.py b/lib/py_pkg/src/py_pkg/math_utils.py index b472a32..64ccf5a 100644 --- a/lib/py_pkg/src/py_pkg/math_utils.py +++ b/lib/py_pkg/src/py_pkg/math_utils.py @@ -1,13 +1,10 @@ -""" -math_utils.py - A dummy module for demonstration -""" +"""math_utils.py - A dummy module for demonstration.""" PI = 3.14159 def square(x): - """ - Calculate the square of a number. + """Calculate the square of a number. Parameters ---------- @@ -18,18 +15,16 @@ def square(x): ------- float or int The square of the input number. + """ return x * x class Calculator: - """ - A simple calculator class for basic arithmetic operations. - """ + """A simple calculator class for basic arithmetic operations.""" def add(self, a, b): - """ - Add two numbers. + """Add two numbers. Parameters ---------- @@ -42,12 +37,12 @@ def add(self, a, b): ------- float or int The sum of a and b. + """ return a + b def subtract(self, a, b): - """ - Subtract one number from another. + """Subtract one number from another. Parameters ---------- @@ -60,12 +55,12 @@ def subtract(self, a, b): ------- float or int The result of a - b. + """ return a - b def multiply(self, a, b): - """ - Multiply two numbers. + """Multiply two numbers. Parameters ---------- @@ -78,12 +73,12 @@ def multiply(self, a, b): ------- float or int The product of a and b. + """ return a * b def divide(self, a, b): - """ - Divide one number by another. + """Divide one number by another. Parameters ---------- @@ -101,6 +96,7 @@ def divide(self, a, b): ------ ValueError If b is zero. + """ if b == 0: raise ValueError("Cannot divide by zero.") diff --git a/lib/py_pkg/src/py_pkg/module.py b/lib/py_pkg/src/py_pkg/module.py index f1395f3..bb88896 100644 --- a/lib/py_pkg/src/py_pkg/module.py +++ b/lib/py_pkg/src/py_pkg/module.py @@ -1,13 +1,11 @@ -""" -module.py - A dummy module for demonstration +"""module.py - A dummy module for demonstration. This module contains simple functions with docstrings for Sphinx documentation. """ def add(a: int, b: int) -> int: - """ - Add two numbers. + """Add two numbers. Args: a (int or float): First number. @@ -15,18 +13,19 @@ def add(a: int, b: int) -> int: Returns: int or float: The sum of a and b. + """ return a + b def greet(name: str) -> str: - """ - Generate a greeting message. + """Generate a greeting message. Args: name (str): Name of the person. Returns: str: Greeting message. + """ return f"Hello, {name}!" diff --git a/lib/py_pkg/src/py_pkg/string_utils.py b/lib/py_pkg/src/py_pkg/string_utils.py index 152d958..8acaef4 100644 --- a/lib/py_pkg/src/py_pkg/string_utils.py +++ b/lib/py_pkg/src/py_pkg/string_utils.py @@ -1,13 +1,10 @@ -""" -string_utils.py - A dummy module for demonstration -""" +"""string_utils.py - A dummy module for demonstration.""" DEFAULT_GREETING = "Hello" def shout(text): - """ - Convert text to uppercase. + """Convert text to uppercase. Parameters ---------- @@ -18,18 +15,16 @@ def shout(text): ------- str The uppercase version of the input string. + """ return text.upper() class Formatter: - """ - A class for formatting strings. - """ + """A class for formatting strings.""" def surround(self, text, symbol="*"): - """ - Surround text with a given symbol. + """Surround text with a given symbol. Parameters ---------- @@ -42,5 +37,6 @@ def surround(self, text, symbol="*"): ------- str The formatted string with symbols surrounding the text. + """ return f"{symbol}{text}{symbol}" diff --git a/lib/py_pkg/tests/test_main.py b/lib/py_pkg/tests/test_main.py index 2140112..3756862 100644 --- a/lib/py_pkg/tests/test_main.py +++ b/lib/py_pkg/tests/test_main.py @@ -3,6 +3,7 @@ def main(): + """Execute the main dummy test.""" calc = Calculator() print("Square of 4:", square(4)) print("Add 2 + 3:", calc.add(2, 3))