From 3922adb738995954122c9adf0db60bfc636a7844 Mon Sep 17 00:00:00 2001 From: MasterLaplace Date: Fri, 13 Oct 2023 06:13:38 +0200 Subject: [PATCH] [Feat] : add Scripts and github workflows --- .github/ISSUE_TEMPLATE/bug_report.yml | 30 +++++ .github/ISSUE_TEMPLATE/feature_request.yml | 29 +++++ .github/ISSUE_TEMPLATE/question.yml | 24 ++++ .github/workflows/build_laplace_libs.yml | 28 +++++ .github/workflows/commit_norm_check.yml | 6 +- .github/workflows/cpp_norm_checker.yml | 25 ++++ .github/workflows/create-release.yml | 70 +++++++++++ .github/workflows/run_test_engine.yml | 30 +++++ .github/workflows/update_readme.yml | 48 ++++++++ Scripts/cpp_norm_checker.py | 128 +++++++++++++++++++++ Scripts/get_latest_release_date.py | 27 +++++ Scripts/improve_build.py | 49 ++++++++ Scripts/increment_version.py | 28 +++++ Scripts/install_criterion.sh | 35 ++++++ Scripts/install_csfml.sh | 35 ++++++ Scripts/test_regex_norm_checker.py | 49 ++++++++ 16 files changed, 638 insertions(+), 3 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/question.yml create mode 100644 .github/workflows/build_laplace_libs.yml create mode 100644 .github/workflows/cpp_norm_checker.yml create mode 100644 .github/workflows/create-release.yml create mode 100644 .github/workflows/run_test_engine.yml create mode 100644 .github/workflows/update_readme.yml create mode 100644 Scripts/cpp_norm_checker.py create mode 100644 Scripts/get_latest_release_date.py create mode 100644 Scripts/improve_build.py create mode 100644 Scripts/increment_version.py create mode 100644 Scripts/install_criterion.sh create mode 100644 Scripts/install_csfml.sh create mode 100644 Scripts/test_regex_norm_checker.py diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..36ffbac --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,30 @@ +name: Report a bug +description: Report a bug +title: '[Bug]: ' +labels: + - bug +body: + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Tell us what happened + validations: + required: true + - type: textarea + id: what-should-happened + attributes: + label: 'What should have happened?' + validations: + required: true + - type: textarea + id: log + attributes: + label: LOG + description: If you have log, please send it to us! + - type: checkboxes + attributes: + label: I read the Code Of Conduct + options: + - label: I read the Code Of Conduct and I comply to it + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..2b5968a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,29 @@ +name: Feature request +description: Suggest an idea for this project +title: '[Feature]: ' +assignees: + - {{ github.actor }} +labels: + - enhancement +projects: + - '1044' +body: + - type: input + id: featureName + attributes: + label: Feature name + validations: + required: true + - type: textarea + id: featureContent + attributes: + label: Explain the feature + description: Tell us what we should add + validations: + required: true + - type: checkboxes + attributes: + label: I read the Code Of Conduct + options: + - label: I read the Code Of Conduct and I comply to it + required: true diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 0000000..1c75d83 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,24 @@ +name: I have a question +description: Ask you question, we will answer in documentation () and below your question +title: '[Question]: ' +labels: + - enhancement +body: + - type: input + id: questionAbout + attributes: + label: What is your question is about ? + validations: + required: true + - type: textarea + id: questionContent + attributes: + label: Ask your question here + validations: + required: true + - type: checkboxes + attributes: + label: I read the Code Of Conduct + options: + - label: I read the Code Of Conduct and I comply to it + required: true diff --git a/.github/workflows/build_laplace_libs.yml b/.github/workflows/build_laplace_libs.yml new file mode 100644 index 0000000..6e93001 --- /dev/null +++ b/.github/workflows/build_laplace_libs.yml @@ -0,0 +1,28 @@ +name: Build Laplace Libs CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + if: always() + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: make lib + run: | + make lib + exit $(($? != 0)) + + - name: SonarCloud Scan for C and C++ + uses: SonarSource/sonarcloud-github-c-cpp@v1.3 + + - name: Check if build succeeded + run: exit $(($? != 0)) diff --git a/.github/workflows/commit_norm_check.yml b/.github/workflows/commit_norm_check.yml index 2f8a600..e851a05 100644 --- a/.github/workflows/commit_norm_check.yml +++ b/.github/workflows/commit_norm_check.yml @@ -19,14 +19,14 @@ jobs: - name: Commit Name Checker run: | commit_msg=$(git log --format=%B -n 1 ${{ github.sha }}) - keyword_regex="^\[[A-Z][@_A-Za-z,/| ]+\] : " - echo "Commit message: $commit_msg" + keyword_regex="^([a-z]+\([A-Za-z_.]+\)|^[a-z]+): " if [[ ! $commit_msg =~ $keyword_regex ]]; then if [[ $commit_msg =~ ^Merge\ .* ]]; then echo "Skipping merge commit" else - echo "Commit message does not match expected format. Please use the following format: \"[Keyword@file] : comment\"" + echo $commit_msg + echo "Commit message does not match expected format. Please use the following format:\"keyword(scope): comment\"" exit 1 fi fi diff --git a/.github/workflows/cpp_norm_checker.yml b/.github/workflows/cpp_norm_checker.yml new file mode 100644 index 0000000..77d2049 --- /dev/null +++ b/.github/workflows/cpp_norm_checker.yml @@ -0,0 +1,25 @@ +name: C++ Norm Checker + +on: + push: + branches: + - '*' + pull_request: + branches: + - '*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Set up C++ environment + uses: actions/checkout@v3 + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Check C++ norm by Laplace Linter + run: | + ./Scripts/norm_checker.py \ No newline at end of file diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..949342b --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,70 @@ +name: Create Release + +on: + pull_request: + branches: + - main + types: + - closed + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_BOT_ACC_EMAIL: guillaume.papineau@epitech.eu + GH_BOT_ACC_NAME: github-actions[bot] + +jobs: + create-release: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Check if PR is merged to main + id: pr-check + run: echo "::set-output name=merged::$(jq -r '.pull_request.merged' $GITHUB_EVENT_PATH)" + + - name: Install GitHub CLI + run: | + sudo apt update + sudo apt install gh + + - name: Set up Git + run: | + git config --local user.email $GH_BOT_ACC_EMAIL + git config --local user.name $GH_BOT_ACC_NAME + + - name: Authenticate GitHub CLI + run: gh auth login --with-token <<<"${GITHUB_TOKEN}" + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Increment Version + if: steps.pr-check.outputs.merged == 'true' + run: | + # Read the current version from the VERSION file + current_version=$(cat VERSION) + + # Increment the version (you can use any logic you prefer) + new_version=$(python3 increment_version.py $current_version) + + # Update the VERSION file with the new version + echo "$new_version" > VERSION + + # Commit and push the updated VERSION file + git add VERSION + git commit -m "chore(VERSION): bump version to $new_version" + git push origin main + + - name: Create Tag and Release + if: success() && steps.pr-check.outputs.merged == 'true' + run: | + # Create a new tag with the version + git tag -a v$new_version -m "Engine-3D v$new_version" + git push origin v$new_version + + # Create a new release + gh release create v$new_version diff --git a/.github/workflows/run_test_engine.yml b/.github/workflows/run_test_engine.yml new file mode 100644 index 0000000..b23cc51 --- /dev/null +++ b/.github/workflows/run_test_engine.yml @@ -0,0 +1,30 @@ +name: Engine testing + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + testing: + runs-on: ubuntu-latest + + steps: + - name: Install CMake + run: sudo apt-get install -y cmake build-essential + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install CSFML + run: ./Scripts/install_csfml.sh + + - name: Install Criterion + run: sudo apt-get install libcriterion-dev + + - name: Build engine + run: make build_tests + + - name: Testing engine + run: make run_tests diff --git a/.github/workflows/update_readme.yml b/.github/workflows/update_readme.yml new file mode 100644 index 0000000..a6207c1 --- /dev/null +++ b/.github/workflows/update_readme.yml @@ -0,0 +1,48 @@ +on: + workflow_run: + workflows: ["Publish Release"] + types: + - completed + +env: + GH_PAT: ${{ secrets.GITHUB_TOKEN }} + GH_BOT_ACC_EMAIL: guillaume.papineau@epitech.eu + GH_BOT_ACC_NAME: github-actions[bot] + +jobs: + readme-update: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Git + run: | + git config --local user.email $GH_BOT_ACC_EMAIL + git config --local user.name $GH_BOT_ACC_NAME + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Get Latest Release Date + id: latest_release_date + run: | + python3 Scripts/get_latest_release_date.py > latest_release_date.txt + echo "::set-output name=release_date::$(cat latest_release_date.txt)" + + - name: Update README.md + run: | + release_date=$(cat latest_release_date.txt) + sed -i "s/- Release Date: \*\*([JFMASOND][a-z]+ \d+, \d+)\*\*/- Release Date: $release_date/" README.md + + - name: Commit and Push Changes + run: | + git add README.md + git commit -m "chore(README): update README.md with latest release date (bot)" + git push diff --git a/Scripts/cpp_norm_checker.py b/Scripts/cpp_norm_checker.py new file mode 100644 index 0000000..fb5594c --- /dev/null +++ b/Scripts/cpp_norm_checker.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# # -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: cpp_norm_checker.py +# Author: MasterLaplace +# Created on: 2023-10-12 + +import os +import re + +class NormChecker: + def __init__(self): + self.nb_errors = 0 + + def check_End_Of_File(self, file_name: str, content: str): + """_summary_ + * The file must end with a new line + * The EOF must be alone on its line + """ + lines = content.split('\n') + + last_line = lines[-1] + if last_line.strip() != '': + raise AssertionError(f"The file \"{file_name}\" does not end with an empty line.") + + + def check_structure_name(self, file_name: str, content: str): + """_summary_ + * All the structure names must start with a capital letter and end with _s + """ + pattern = r'struct\s+(\w+)\s*{' + incorrect_structures = [] + + matches = re.findall(pattern, content) + for struct_name in matches: + if not struct_name[0].isupper() or not struct_name.endswith('_s'): + incorrect_structures.append(struct_name) + + if incorrect_structures: + print(f"Incorrect structure names found in file '{file_name}':") + for struct_name in incorrect_structures: + print(struct_name) + raise AssertionError(f"The file \"{file_name}\" contains structures with incorrect names.") + + def check_namespace_name(self, file_name: str, content: str): + """_summary_ + * All the namespace names must start with a capital letter + """ + pattern = r'namespace\s+(\w+)\s*{' + incorrect_namespaces = [] + + matches = re.findall(pattern, content) + for struct_name in matches: + if not struct_name[0].isupper(): + incorrect_namespaces.append(struct_name) + + if incorrect_namespaces: + print(f"Incorrect namespace names found in file '{file_name}':") + for struct_name in incorrect_namespaces: + print(struct_name) + raise AssertionError(f"The file \"{file_name}\" contains namespaces with incorrect names.") + + def check_tab_size(self, file_name: str, content: str): + """_summary_ + * All the lines must be indented with 4 spaces + """ + lines_incorrect = [] + + for i, ligne in enumerate(content.split('\n')): + # Check if the line is a Doxygen documentation + if ligne.strip().startswith('/**') or ligne.strip().startswith('*') or ligne.strip().startswith('*/'): + continue + + # Check if the line contains comments + if ligne.strip().startswith('#') or ligne.strip().startswith('//'): + continue + + # Check line indentation + indentation = len(ligne) - len(ligne.lstrip()) + if indentation % 4 != 0: + lines_incorrect.append(i + 1) + + if lines_incorrect: + raise AssertionError(f"The file \"{file_name}\" contains lines with incorrect indentation on the lines:", lines_incorrect) + + def call_all_checks(self, file_name: str, content: str): + self.check_tab_size(file_name, content) + self.check_structure_name(file_name, content) + self.check_namespace_name(file_name, content) + self.check_End_Of_File(file_name, content) + + +FOLDER_SRC = 'Engine/Plugins/' + +def main(): + check_norm = NormChecker() + + for directory, subdirectories, files in os.walk(FOLDER_SRC): + for file in files: + file_path = os.path.join(directory, file) + + try: + # We're only interested in C++ files + if file_path.endswith('.cpp'): + if file != 'main.cpp' and not file[0].isupper() or file[0].isdigit(): + raise AssertionError("The name of the file \"" + file_path + "\" does not start with a capital letter") + with open(file_path, 'r', encoding='latin-1') as f: + check_norm.call_all_checks(file_path, f.read()) + + # We're only interested in C++ Header files + elif file_path.endswith('.hpp'): + if not file[0].isupper() or file[0].isdigit(): + raise AssertionError("The name of the file \"" + file_path + "\" does not start with a capital letter") + with open(file_path, 'r', encoding='latin-1') as f: + check_norm.call_all_checks(file_path, f.read()) + else: + raise AssertionError("Unknow file detected in the Plugin: " + file_path) + except AssertionError as e: + check_norm.nb_errors += 1 + print(e) + + if check_norm.nb_errors > 0: + raise AssertionError(f"\033[1;31mThere are {check_norm.nb_errors} error(s) in the plugins source code\033[0m") + else: + print("\033[1;32m► The plugins source code complies with C++ coding standards!\033[0m") + +if __name__ == '__main__': + main() diff --git a/Scripts/get_latest_release_date.py b/Scripts/get_latest_release_date.py new file mode 100644 index 0000000..4577bce --- /dev/null +++ b/Scripts/get_latest_release_date.py @@ -0,0 +1,27 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: get_latest_release_date.py +# Author: MasterLaplace +# Created on: 2023-10-12 + +import requests +import json + +# Replace with your GitHub repository information +repo_owner = "MasterLaplace" +repo_name = "Engine-3D" + +# Fetch the latest release information from GitHub API +response = requests.get(f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/latest") +data = json.loads(response.text) + +# Extract the release date +latest_release_date = data['published_at'] + +# publish at this format: **October 13, 2023** + +formatted_date = f"**{latest_release_date[8:10]} {latest_release_date[5:7]}, {latest_release_date[:4]}**" + +# Print the formatted date (you can also save it to a file) +print(formatted_date) diff --git a/Scripts/improve_build.py b/Scripts/improve_build.py new file mode 100644 index 0000000..83f788f --- /dev/null +++ b/Scripts/improve_build.py @@ -0,0 +1,49 @@ +#/usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: get_latest_release_date.py +# Author: MasterLaplace +# Created on: 2023-10-13 + +from time import sleep +import sys + + +bold = '\033[1m' +normal = '\033[0m' +red = '\033[31m\033[1m' +yellow = '\033[33m\033[1m' +green = '\033[32m\033[1m' + +spaces = " "*50 +sys.stdout.write('\r') +sys.stdout.write(spaces * 2) +sys.stdout.write('\r') + +file = sys.argv[1] +nb = sys.argv[2] +all = sys.argv[3] + +place = 30 +percentage = int(nb) * 100 / int(all) + +display = bold + file +if len(file) < place: + display += " " * (place - len(file)) +display += "[" +sys.stdout.write(display) + +if percentage > 67: + color = green +elif percentage > 33: + color = yellow +else: + color = red +sys.stdout.write(color) + +sys.stdout.write(u"\u25AE" * int(int(percentage) * place / 100)) +sys.stdout.write(" " * int(place - (percentage * place / 100))) + +sys.stdout.write(normal + bold + "]" + "\t" + str(int(percentage)) + '%' + normal + "\t" +"(" + nb + '/' + all +")" + spaces ) +sys.stdout.flush() +sleep(0.01) diff --git a/Scripts/increment_version.py b/Scripts/increment_version.py new file mode 100644 index 0000000..f266b69 --- /dev/null +++ b/Scripts/increment_version.py @@ -0,0 +1,28 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: increment_version.py +# Author: MasterLaplace +# Created on: 2023-10-12 + +import re + +def increment_version(current_version: str): + match = re.search(r'v(\d+\.\d+\.\d+)', current_version) + if match: + current_version_number = match.group(1) + major, minor, patch = map(int, current_version_number.split('.')) + return f"Engine-3D v{major}.{minor}.{patch + 1}" + + return current_version + +if __name__ == "__main__": + # Read the current version from the VERSION file + with open("VERSION", "r") as version_file: + current_version = version_file.read().strip() + + new_version = increment_version(current_version) + + # Update the VERSION file with the new version + with open("VERSION", "w") as version_file: + version_file.write(new_version) diff --git a/Scripts/install_criterion.sh b/Scripts/install_criterion.sh new file mode 100644 index 0000000..fc19c94 --- /dev/null +++ b/Scripts/install_criterion.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: install_criterion.sh +# Author: MasterLaplace +# Created on: 2023-10-12 + +URL="https://github.com/Snaipe/Criterion.git" +DIR="Criterion" +INSTALL_DIR=~/criterion + +# install Criterion dependencies +sudo apt-get update +sudo apt-get install -y libeigen3-dev libgsl-dev + +# clone Criterion repository +cd build +rm -rf $DIR +git clone $URL +if [ $? != 0 ]; then + echo "failed to clone Criterion repository, exiting" + exit 1 +fi + +# build Criterion +cd $DIR +echo "building $DIR" +cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR . && make install +if [ $? != 0 ]; then + echo "failed to build Criterion, exiting" + exit 1 +fi + +rm -rf ../$DIR +echo "Criterion successfully installed to $INSTALL_DIR" diff --git a/Scripts/install_csfml.sh b/Scripts/install_csfml.sh new file mode 100644 index 0000000..a365937 --- /dev/null +++ b/Scripts/install_csfml.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: install_csfml.sh +# Author: MasterLaplace +# Created on: 2023-10-12 + +URL="https://github.com/SFML/CSFML.git" +DIR="CSFML" +INSTALL_DIR=~/csfml + +# install SFML dependencies +sudo apt-get update +sudo apt-get install -y libsfml-dev libcsfml-dev + +# clone CSFML repository +cd build +rm -rf $DIR +git clone $URL +if [ $? != 0 ]; then + echo "failed to clone CSFML repository, exiting" + exit 1 +fi + +# build CSFML +cd $DIR +echo "building $DIR" +cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR . && make install +if [ $? != 0 ]; then + echo "failed to build CSFML, exiting" + exit 1 +fi + +rm -rf ../$DIR +echo "CSFML successfully installed to $INSTALL_DIR" diff --git a/Scripts/test_regex_norm_checker.py b/Scripts/test_regex_norm_checker.py new file mode 100644 index 0000000..f3b03f5 --- /dev/null +++ b/Scripts/test_regex_norm_checker.py @@ -0,0 +1,49 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# File name: test_regex_norm_checker.py +# Author: MasterLaplace +# Created on: 2023-10-12 + +import re + +# # Define your regex pattern +# keyword_regex = r"^([a-z]+\([A-Za-z_.]+\)|^[a-z]+): " + +# # List of sample commit messages +# commit_messages = [ +# "fix(readme): fix link about the wiki", +# "fix(.github): move funding script", +# "feat(main): add new feature", +# "style: fix linting issues", +# ] + +# # Test the regex pattern on each commit message +# for message in commit_messages: +# match = re.search(keyword_regex, message) +# if match: +# print(f"Match found in '{message}': {match.group()}") +# else: +# print(f"No match found in '{message}'") + + +# Define regex for release date +realease_date_regex = r"- Release Date: \*\*([JFMASOND][a-z]+ \d+, \d+)\*\*" + +# List of sample release notes +release_notes = """ +> :clipboard: [Change Log](CHANGELOG.md). + +- [![Latest Release](https://img.shields.io/github/v/release/MasterLaplace/Engine-3D.svg?label=version)](https://github.com/MasterLaplace/Engine-3D/releases/latest/) +- Release Date: **October 13, 2023** + + +
+""" + +# Test the regex pattern on each release note +match = re.search(realease_date_regex, release_notes) +if match: + print(f"Match found in '{release_notes}': {match.group(1)}") +else: + print(f"No match found in '{release_notes}'")