Skip to content

Latest commit

 

History

History
460 lines (358 loc) · 15.2 KB

File metadata and controls

460 lines (358 loc) · 15.2 KB

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-

    1. 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/

    1. 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