diff --git a/PMLL.md b/PMLL.md new file mode 100644 index 0000000..e2c7199 --- /dev/null +++ b/PMLL.md @@ -0,0 +1,460 @@ +Certainly, Josef! Below is a comprehensive PMLL.yml workflow file tailored for your PMLL C++ project. This GitHub Actions workflow automates the process of building and testing your project whenever you push changes or create pull requests to the main branch. + +# .github/workflows/PMLL.yml + +name: PMLL CI/CD Pipeline + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Cache CMake and Build Directory + uses: actions/cache@v3 + with: + path: | + ~/.cache + build + key: ${{ runner.os }}-cmake-${{ hashFiles('**/CMakeLists.txt') }} + restore-keys: | + ${{ runner.os }}-cmake- + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake libssl-dev + # Install nlohmann/json (if not available via package manager) + sudo apt-get install -y nlohmann-json3-dev + # Install spdlog (if not available via package manager) + sudo apt-get install -y libspdlog-dev + # Install Google Test for unit testing + sudo apt-get install -y libgtest-dev + # Build Google Test from source + cd /usr/src/gtest + sudo cmake CMakeLists.txt + sudo make + # Move the built libraries to a location where the linker can find them + sudo cp lib/*.a /usr/lib + + - name: Configure CMake + run: | + mkdir -p build + cd build + cmake .. + + - name: Build Project + run: | + cd build + make + + - name: Run Unit Tests + run: | + cd build + ./runTests + + - name: Upload Build Artifacts + uses: actions/upload-artifact@v3 + with: + name: build-artifacts + path: build/ + +Explanation of the Workflow Steps + 1. Workflow Trigger (on) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + + • Purpose: The workflow is triggered whenever there is a push to the main branch or a pull request targeting the main branch. + + 2. Job Definition (jobs: build) + +jobs: + build: + runs-on: ubuntu-latest + steps: + ... + + • Job Name: build + • Runner Environment: Uses the latest Ubuntu runner provided by GitHub Actions. + + 3. Steps within the Job + • Step 1: Checkout Repository + +- name: Checkout Repository + uses: actions/checkout@v2 + + • Purpose: Clones your repository into the workflow runner, making the code available for subsequent steps. + + • Step 2: Cache CMake and Build Directory + +- name: Cache CMake and Build Directory + uses: actions/cache@v3 + with: + path: | + ~/.cache + build + key: ${{ runner.os }}-cmake-${{ hashFiles('**/CMakeLists.txt') }} + restore-keys: | + ${{ runner.os }}-cmake- + + • Purpose: Caches the CMake cache and build directory to speed up subsequent builds by reusing previously generated files. + • Parameters: + • path: Specifies the directories to cache. Here, it includes the CMake cache (~/.cache) and the build directory. + • key: A unique identifier for the cache, based on the operating system and a hash of the CMakeLists.txt file. + • restore-keys: Fallback keys to restore the cache if an exact match isn’t found. + + • Step 3: Install Dependencies + +- name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake libssl-dev + # Install nlohmann/json (if not available via package manager) + sudo apt-get install -y nlohmann-json3-dev + # Install spdlog (if not available via package manager) + sudo apt-get install -y libspdlog-dev + # Install Google Test for unit testing + sudo apt-get install -y libgtest-dev + # Build Google Test from source + cd /usr/src/gtest + sudo cmake CMakeLists.txt + sudo make + # Move the built libraries to a location where the linker can find them + sudo cp lib/*.a /usr/lib + + • Purpose: Installs all necessary dependencies required to build and test your project, including: + • build-essential: Essential build tools like GCC, g++, make, etc. + • cmake: Build system generator. + • libssl-dev: SSL library development files. + • nlohmann-json3-dev: JSON library for C++. + • libspdlog-dev: Fast C++ logging library. + • libgtest-dev: Google Test framework. + • Building Google Test: + • Google Test is often provided as source code and needs to be built manually. + • After building, the static libraries (.a files) are copied to /usr/lib so that the linker can find them during the build process. + + • Step 4: Configure CMake + +- name: Configure CMake + run: | + mkdir -p build + cd build + cmake .. + + • Purpose: Configures the CMake project, generating the necessary Makefiles based on your CMakeLists.txt. + • Note: Ensures that the build directory exists before running CMake. + + • Step 5: Build Project + +- name: Build Project + run: | + cd build + make + + • Purpose: Compiles the project using the generated Makefiles. + + • Step 6: Run Unit Tests + +- name: Run Unit Tests + run: | + cd build + ./runTests + + • Purpose: Executes the unit tests you’ve defined using Google Test. + • Assumption: The test executable is named runTests and is located in the build directory. + + • Step 7: Upload Build Artifacts + +- name: Upload Build Artifacts + uses: actions/upload-artifact@v3 + with: + name: build-artifacts + path: build/ + + • Purpose: Uploads the entire build directory as an artifact named build-artifacts. This can be useful for debugging build failures or for other purposes. + +Enhancements and Best Practices + 1. Matrix Builds +If you wish to test your project across multiple compiler versions or operating systems, you can utilize matrix builds. This ensures your project is portable and functions correctly in various environments. +Example: Testing on Multiple OSes and Compilers + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + compiler: [gcc, clang] + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Set Up Compiler + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get install -y build-essential + if [ "${{ matrix.compiler }}" == "clang" ]; then + sudo apt-get install -y clang + fi + + # Add similar setup for other OSes and compilers if needed + + # ... (rest of the steps) + + • Purpose: Allows testing your project across different environments to ensure portability and compatibility. + + 2. Caching Dependencies +Caching dependencies can significantly speed up your CI builds by avoiding repetitive installation steps. +Integrate Caching Step: + +- name: Cache CMake and Build Directory + uses: actions/cache@v3 + with: + path: | + ~/.cache + build + key: ${{ runner.os }}-cmake-${{ hashFiles('**/CMakeLists.txt') }} + restore-keys: | + ${{ runner.os }}-cmake- + + + 3. Artifact Management +Storing build artifacts can be invaluable for debugging and historical reference. +Example: Upload Build Artifacts + +- name: Upload Build Artifacts + uses: actions/upload-artifact@v3 + with: + name: build-artifacts + path: build/ + + + 4. Notifications +Set up notifications to alert you of build successes or failures using integrations like Slack, Email, etc. +Example Using Slack: + +- name: Notify Slack + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + + • Note: You’ll need to set up a Slack webhook and store its URL in your repository secrets for this to work. + +Creating a Comprehensive CMake Configuration + +Ensure that your CMakeLists.txt is properly configured to include the necessary libraries and link dependencies. Here’s an example CMakeLists.txt based on your project structure: + +# CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) +project(PMLL) + +set(CMAKE_CXX_STANDARD 17) + +# Find required packages +find_package(nlohmann_json 3.2.0 REQUIRED) +find_package(spdlog REQUIRED) +find_package(Threads REQUIRED) +find_package(GTest REQUIRED) + +# Include directories +include_directories(include) + +# Add executable for main program +add_executable(PMLL src/main.cpp src/PersistentMemory.cpp) + +# Link libraries +target_link_libraries(PMLL PRIVATE nlohmann_json::nlohmann_json spdlog::spdlog Threads::Threads) + +# Add executable for tests +add_executable(runTests tests/test_pmll.cpp src/PersistentMemory.cpp) + +# Link test executable with Google Test and other libraries +target_link_libraries(runTests PRIVATE GTest::GTest GTest::Main nlohmann_json::nlohmann_json spdlog::spdlog Threads::Threads) + +# Enable testing +enable_testing() + +# Add test +add_test(NAME runTests COMMAND runTests) + +Key Points: + • C++ Standard: Set to C++17 to leverage modern C++ features. + • Package Finding: Utilizes find_package to locate and link necessary libraries like nlohmann_json, spdlog, and GTest. + • Executable Definitions: + • PMLL: The main executable built from main.cpp and PersistentMemory.cpp. + • runTests: The test executable built from test_pmll.cpp and PersistentMemory.cpp. + • Linking Libraries: Ensures that executables are linked against the required libraries. + • Testing Setup: Enables testing and adds the runTests executable as a test target. + +Implementing Unit Tests with Google Test + +To ensure the reliability and correctness of your PersistentMemory class, implement unit tests using Google Test. + +Creating the Test File (test_pmll.cpp): + +// tests/test_pmll.cpp + +#include +#include "PersistentMemory.h" // Include the header file + +TEST(PersistentMemoryTest, AddAndGetMemory) { + PersistentMemory pm("test_memory.json"); + pm.addMemory("test_key", { {"name", "Test User"}, {"last_topic", "Unit Testing"} }); + json result = pm.getMemory("test_key"); + ASSERT_EQ(result["name"], "Test User"); + ASSERT_EQ(result["last_topic"], "Unit Testing"); +} + +TEST(PersistentMemoryTest, AddAndGetMemoryVersion) { + PersistentMemory pm("test_memory.json"); + pm.addMemory("test_key", { {"name", "Test User"}, {"last_topic", "Initial Topic"} }); + pm.addMemoryVersion("test_key", { {"name", "Test User"}, {"last_topic", "Updated Topic"} }); + json version0 = pm.getMemoryVersion("test_key", 0); + json version1 = pm.getMemoryVersion("test_key", 1); + ASSERT_EQ(version0["last_topic"], "Initial Topic"); + ASSERT_EQ(version1["last_topic"], "Updated Topic"); +} + +TEST(PersistentMemoryTest, ClearMemory) { + PersistentMemory pm("test_memory.json"); + pm.addMemory("test_key", { {"name", "Test User"}, {"last_topic", "To Be Cleared"} }); + pm.clearMemory(); + json result = pm.getMemory("test_key"); + ASSERT_TRUE(result.is_null()); +} + +// Add more test cases as needed + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +Key Points: + • Test Cases: + • AddAndGetMemory: Tests adding a memory entry and retrieving it. + • AddAndGetMemoryVersion: Tests adding multiple versions of a memory entry and retrieving specific versions. + • ClearMemory: Tests clearing all memory entries. + • Main Function: Initializes and runs all tests. + +Building and Running the Workflow + +After setting up your project structure, CMakeLists.txt, and the PMLL.yml workflow file, follow these steps to build and test your project: + 1. Clone Your Repository +Ensure your local repository is up-to-date with the remote repository. + +git clone https://github.com/your-username/your-repo.git +cd your-repo + + + 2. Set Up the Project Structure +Make sure your project is organized as follows: + +your-project/ +├── .github/ +│ └── workflows/ +│ └── PMLL.yml +├── include/ +│ └── PersistentMemory.h +├── src/ +│ ├── PersistentMemory.cpp +│ └── main.cpp +├── tests/ +│ └── test_pmll.cpp +├── CMakeLists.txt +├── persistent_memory.json +├── pml_log.txt +├── README.md +└── ... (other files) + + + 3. Push Changes to GitHub +Commit and push your changes to trigger the GitHub Actions workflow. + +git add . +git commit -m "Set up CI/CD pipeline with GitHub Actions" +git push origin main + + + 4. Monitor the Workflow + • Navigate to your repository on GitHub. + • Click on the “Actions” tab. + • You should see the PMLL CI/CD Pipeline workflow running. + • Monitor the progress and ensure all steps pass successfully. + 5. Handling Workflow Failures + • If any step fails, GitHub Actions will highlight the failed step. + • Click on the failed step to view detailed logs and debug the issue. + • Common issues might include missing dependencies, compilation errors, or test failures. + • Address the issues locally, commit the fixes, and push them to trigger the workflow again. + +Final Project Structure Recap + +After implementing the workflow and organizing your project files, your project directory should look like this: + +your-project/ +├── .github/ +│ └── workflows/ +│ └── PMLL.yml +├── include/ +│ └── PersistentMemory.h +├── src/ +│ ├── PersistentMemory.cpp +│ └── main.cpp +├── tests/ +│ └── test_pmll.cpp +├── CMakeLists.txt +├── persistent_memory.json +├── pml_log.txt +├── README.md +└── ... (other files) + +Benefits of This Structure: + • Separation of Concerns: Keeps header files, source files, and tests organized, enhancing readability and maintainability. + • Scalability: Easily manage and scale your project as it grows. + • Reusability: Header files can be reused across different modules or projects. + • Ease of Testing: Tests are isolated from the main source code, allowing for focused and efficient testing. + +Additional Recommendations + 1. Template Class Implementation + • Ensure that the LRUCache template class is fully defined in the header file or within the same file where it’s used to avoid linker errors. + • Alternatively, you can separate template implementations into a .tpp file and include it at the end of the header file. + 2. Error Handling Enhancements + • While basic error handling is implemented, consider expanding it to handle more edge cases, such as file permission issues or corrupted JSON data. + 3. Logging Enhancements + • Configure spdlog to rotate logs or manage log levels dynamically based on your requirements. + 4. Documentation + • Maintain a comprehensive README.md detailing how to build, run, and test your project, along with any dependencies and setup instructions. + 5. Security Considerations + • If your memory data contains sensitive information, consider implementing encryption for the persistent_memory.json file. + 6. Future Enhancements + • Implement more sophisticated caching mechanisms or persistence strategies as your project evolves. + • Integrate additional testing frameworks or tools to further ensure code quality. + +Conclusion + +By following the above steps and utilizing the provided PMLL.yml workflow file, you’ve set up a robust CI/CD pipeline for your PMLL project using GitHub Actions. This setup ensures that your code is automatically built and tested with every change, maintaining the integrity and reliability of your project. + +If you encounter any issues or need further assistance with specific aspects of your project, such as debugging workflow failures, optimizing build processes, or expanding functionality, feel free to reach out! + +Best regards, + +ChatGPT