Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <gtest/gtest.h> #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 Signed-off-by: J. K. Edwards <joed6834@colorado.edu>
- Loading branch information