diff --git a/.github/actions/README.md b/.github/actions/README.md new file mode 100644 index 0000000..b71210f --- /dev/null +++ b/.github/actions/README.md @@ -0,0 +1,55 @@ +# GitHub Reusable Actions for openDAQ Framework + +This directory contains **reusable GitHub Actions** used to work with the **openDAQ framework**. +The actions support determining the latest or specific release, downloading it from S3, and installing it on Linux or Windows runners. + +--- + +## Actions Overview + +| Action | Description | Inputs | Outputs | +|--------|-------------|--------|---------| +| [framework-latest-release](./framework-latest-release/README.md) | Determines which openDAQ framework package to use (latest release or specific version). | `opendaq-framework-release-version`, `win32-force` | `version`, `platform`, `packaging`, `artefact`, `uri`, `scheme`, `authority`, `path` | +| [framework-download](./framework-download/README.md) | Downloads the resolved openDAQ framework package from AWS S3. | `src-opendaq-framework-dev`, `dst-opendaq-framework-dev`, `aws_access_key_id`, `aws_secret_access_key`, `aws_region` | None | +| [framework-install](./framework-install/README.md) | Installs the downloaded openDAQ framework package on the runner. | `opendaq-framework-package-filename`, `opendaq-framework-package-path` | None | + +--- + +## Recommended Usage + +A typical workflow combining all three actions: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Resolve openDAQ framework version + id: framework + uses: ./.github/actions/framework-latest-release + with: + opendaq-framework-release-version: latest + + - name: Download openDAQ framework + uses: ./.github/actions/framework-download + with: + src-opendaq-framework-dev: ${{ steps.framework.outputs.uri }} + aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws_region: ${{ secrets.AWS_REGION }} + + - name: Install openDAQ framework + uses: ./.github/actions/framework-install + with: + opendaq-framework-package-filename: ${{ steps.framework.outputs.artefact }} +``` + +## Notes + +- Linux and Windows runners are supported. +- framework-latest-release requires GitHub CLI (gh) and jq. +- framework-download requires AWS CLI. +- framework-install installs differently depending on OS. diff --git a/.github/actions/framework-download/README.md b/.github/actions/framework-download/README.md new file mode 100644 index 0000000..e820d1e --- /dev/null +++ b/.github/actions/framework-download/README.md @@ -0,0 +1,45 @@ +# framework-download + +This composite action downloads an **openDAQ framework package** from **AWS S3** to the runner. +It supports both Linux/macOS and Windows runners. + +--- + +## Inputs + +| Name | Required | Default | Description | +|-----------------------------|----------|---------------------|-------------| +| `src-opendaq-framework-dev` | yes | — | Full S3 URI to the package (e.g. `s3://bucket/releases/v3.20.4/SDK/opendaq-3.20.4-win64.exe`). | +| `dst-opendaq-framework-dev` | no | `${{ runner.temp }}`| Destination path for the downloaded package on the runner. | +| `aws_access_key_id` | yes | — | AWS Access Key ID used for authentication. | +| `aws_secret_access_key` | yes | — | AWS Secret Access Key used for authentication. | +| `aws_region` | yes | — | AWS Region where the bucket is located. | + +--- + +## Example usage + +```yaml +jobs: + download: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download openDAQ framework + uses: ./.github/actions/framework-download + with: + src-opendaq-framework-dev: "s3://bb-blueberry-sdk-releases/releases/v3.20.4/SDK/opendaq-3.20.4-ubuntu22.04-x86_64.deb" + dst-opendaq-framework-dev: "/tmp/opendaq-3.20.4-ubuntu22.04-x86_64.deb" + aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws_region: ${{ secrets.AWS_REGION }} +``` + +## Notes +- Uses aws-actions/configure-aws-credentials to set up credentials. +- Downloads via aws s3 cp, which must be available in the runner environment. + - On GitHub-hosted runners, the AWS CLI is pre-installed. +- Supports Linux/macOS (bash) and Windows (pwsh) runners. +- Destination path must be writable by the runner. diff --git a/.github/actions/framework-download/action.yml b/.github/actions/framework-download/action.yml new file mode 100644 index 0000000..6d34b86 --- /dev/null +++ b/.github/actions/framework-download/action.yml @@ -0,0 +1,50 @@ +name: Download openDAQ framework package +description: "Download a package from S3 for Linux or Windows" + +inputs: + src-opendaq-framework-dev: + required: true + description: "S3 path to the package" + dst-opendaq-framework-dev: + required: false + default: ${{ runner.temp }} + description: "Destination path for downloaded package" + + aws_access_key_id: + required: true + description: "AWS Access Key ID" + aws_secret_access_key: + required: true + description: "AWS Secret Access Key" + aws_region: + required: true + description: "AWS Region" + +runs: + using: composite + steps: + - name: Configure AWS + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ inputs.aws_access_key_id }} + aws-secret-access-key: ${{ inputs.aws_secret_access_key }} + aws-region: ${{ inputs.aws_region }} + + - name: Download package from S3 (Linux/macOS) + if: runner.os != 'Windows' + shell: bash + run: | + set -e + DST="${{ inputs.dst-opendaq-framework-dev }}" + SRC="${{ inputs.src-opendaq-framework-dev }}" + echo "Downloading $SRC to $DST" + aws s3 cp "$SRC" "$DST" + + - name: Download package from S3 (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $dst = "${{ inputs.dst-opendaq-framework-dev }}" + $src = "${{ inputs.src-opendaq-framework-dev }}" + Write-Host "Downloading $src to $dst" + aws s3 cp "$src" "$dst" diff --git a/.github/actions/framework-install/README.md b/.github/actions/framework-install/README.md new file mode 100644 index 0000000..fb3f31c --- /dev/null +++ b/.github/actions/framework-install/README.md @@ -0,0 +1,60 @@ +# framework-install + +This composite action installs an **openDAQ framework package** on the runner. +It supports **Windows (installer executable)** and **Linux (Debian package)**. +Other operating systems are not supported. + +--- + +## Inputs + +| Name | Required | Default | Description | +|-----------------------------------|----------|---------------------|-------------| +| `opendaq-framework-package-filename` | yes | — | Name of the package file (e.g. `opendaq-3.20.4-win64.exe`, `opendaq-3.20.4-ubuntu22.04-x86_64.deb`). | +| `opendaq-framework-package-path` | no | `${{ runner.temp }}`| Directory where the package file is located. | + +--- + +## Example usage + +```yaml +jobs: + install: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install openDAQ framework + uses: ./.github/actions/framework-install + with: + opendaq-framework-package-filename: "opendaq-3.20.4-win64.exe" + opendaq-framework-package-path: "C:\\actions\\temp" +``` +```yml +jobs: + install: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install openDAQ framework + uses: ./.github/actions/framework-install + with: + opendaq-framework-package-filename: "opendaq-3.20.4-ubuntu22.04-x86_64.deb" + opendaq-framework-package-path: "/tmp" +``` + +## Notes +- Windows: + - Runs the installer in silent mode (/S). + - After installation, updates the PATH environment variable to include: + ```powershell + PATH=C:\Program Files\openDAQ\bin;$PATH + ``` +- Linux: + - Installs the package via dpkg -i. + - Requires sudo access on the runner. +- Unsupported OS: + - The action exits with an error for macOS or other platforms. diff --git a/.github/actions/framework-install/action.yml b/.github/actions/framework-install/action.yml new file mode 100644 index 0000000..6e3e6de --- /dev/null +++ b/.github/actions/framework-install/action.yml @@ -0,0 +1,42 @@ +name: Install openDAQ framework package + +inputs: + opendaq-framework-package-filename: + required: true + + opendaq-framework-package-path: + required: false + default: ${{ runner.temp }} + +runs: + using: composite + + steps: + - name: Install openDAQ framework package (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $packagePath = Join-Path "${{ inputs.opendaq-framework-package-path }}" "${{ inputs.opendaq-framework-package-filename }}" + $process = Start-Process -FilePath $packagePath -ArgumentList "/S" -Wait -NoNewWindow -PassThru + if ($process.ExitCode -eq 0) { + Write-Host "OpenDAQ installed successfully, updating PATH..." + $openDAQBin = "C:\Program Files\openDAQ\bin" + Add-Content -Path $env:GITHUB_ENV -Value "PATH=$openDAQBin`;$env:PATH" + Write-Host $env:PATH + } + else { + Write-Host "OpenDAQ installation failed with exit code $($process.ExitCode)" + exit $process.ExitCode + } + + - name: Install openDAQ framework package (Linux) + if: runner.os == 'Linux' + shell: bash + run: sudo dpkg -i "${{ inputs.opendaq-framework-package-path }}/${{ inputs.opendaq-framework-package-filename }}" + + - name: Unsupported runner OS + if: runner.os != 'Windows' && runner.os != 'Linux' + shell: bash + run: | + echo "Install openDAQ is not supported for ${{ runner.os }}" + exit 1 diff --git a/.github/actions/framework-latest-release/README.md b/.github/actions/framework-latest-release/README.md new file mode 100644 index 0000000..8791f2d --- /dev/null +++ b/.github/actions/framework-latest-release/README.md @@ -0,0 +1,61 @@ +# framework-latest-release + +This composite action determines the **openDAQ framework package** to use. +It supports resolving either the **latest release** from GitHub or a **specific version** provided as input, +and outputs all required information to download and install the package. + +--- + +## Inputs + +| Name | Required | Default | Description | +|-------------------------------------|----------|---------|-------------| +| `opendaq-framework-release-version` | no | `latest`| openDAQ framework version. Use `latest` for the newest release, or provide a specific version (e.g. `3.20.4`). | +| `win32-force` | no | `false` | On Windows runners, forces `win32` instead of `win64` platform. | + +--- + +## Outputs + +| Name | Description | +|------------|-------------| +| `version` | Resolved openDAQ release version (e.g. `3.20.4`). | +| `platform` | Detected platform string (`ubuntu22.04-x86_64`, `ubuntu22.04-arm64`, `win32`, `win64`). | +| `packaging`| Package type (`deb` on Linux, `exe` on Windows). | +| `artefact` | Resolved artefact filename (e.g. `opendaq-3.20.4-win64.exe`). | +| `scheme` | URI scheme (currently `s3`). | +| `authority`| Storage authority (S3 bucket name). | +| `path` | Path inside the bucket (e.g. `releases/v3.20.4/SDK`). | +| `uri` | Full URI to the artefact (e.g. `s3://bucket/releases/v3.20.4/SDK/opendaq-3.20.4-win64.exe`). | + +--- + +## Example usage + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Determine openDAQ framework package + id: framework + uses: ./.github/actions/framework-latest-release + with: + opendaq-framework-release-version: latest + + - name: Print resolved artefact info + run: | + echo "Version: ${{ steps.framework.outputs.version }}" + echo "Platform: ${{ steps.framework.outputs.platform }}" + echo "Artefact: ${{ steps.framework.outputs.artefact }}" + echo "URI: ${{ steps.framework.outputs.uri }}" +``` + +## Notes +- The action relies on GitHub CLI (gh) and jq. +- These are pre-installed on GitHub-hosted Ubuntu and Windows runners. +- On Windows, if you explicitly need a 32-bit package, set win32-force: true. +- If the latest release cannot be determined, the action fails. diff --git a/.github/actions/framework-latest-release/action.yml b/.github/actions/framework-latest-release/action.yml new file mode 100644 index 0000000..c2750b5 --- /dev/null +++ b/.github/actions/framework-latest-release/action.yml @@ -0,0 +1,111 @@ +name: Determine latest openDAQ framework artefact + +inputs: + + opendaq-framework-release-version: + required: false + default: latest + + win32-force: + required: false + default: false + +outputs: + + version: + description: "Latest openDAQ release version" + value: ${{ steps.determine-latest-package.outputs.version }} + + platform: + description: "Detected platform" + value: ${{ steps.determine-latest-package.outputs.platform }} + + packaging: + description: "Package type (deb/exe)" + value: ${{ steps.determine-latest-package.outputs.packaging }} + + artefact: + description: "Artefact filename" + value: ${{ steps.determine-latest-package.outputs.artefact }} + + uri: + description: "Full URI to artefact" + value: ${{ steps.determine-latest-package.outputs.uri }} + + scheme: + description: "Scheme (s3)" + value: ${{ steps.determine-latest-package.outputs.scheme }} + + authority: + description: "Authority (bucket)" + value: ${{ steps.determine-latest-package.outputs.authority }} + + path: + description: "Path inside bucket" + value: ${{ steps.determine-latest-package.outputs.path }} + +runs: + using: composite + steps: + - name: Determine latest openDAQ package + id: determine-latest-package + shell: bash + run: | + set -e + + input_version="${{ inputs.opendaq-framework-release-version }}" + + if [[ -z "$input_version" || "$input_version" == "latest" ]]; then + version=$(gh api repos/openDAQ/openDAQ/releases/latest --jq '.tag_name') + if [[ -z "$version" || "$version" == "null" ]]; then + echo "::error::Failed to determine latest openDAQ release version" + exit 1 + fi + + version=${version#v} + else + version="$input_version" + fi + + platform="" + packaging="" + + if [[ "$RUNNER_OS" == "Linux" ]]; then + arch=$(uname -m) + if [[ "$arch" == "x86_64" ]]; then + platform="ubuntu22.04-x86_64" + elif [[ "$arch" == "aarch64" ]]; then + platform="ubuntu22.04-arm64" + else + echo "::error::Unsupported Linux arch: $arch" + exit 1 + fi + packaging="deb" + + elif [[ "$RUNNER_OS" == "Windows" ]]; then + WIN32_FORCE="${{ inputs.win32-force }}" + if [[ "$WIN32_FORCE" == "true" ]]; then + platform="win32" + else + platform="win64" + fi + packaging="exe" + + else + echo "::error::Unsupported runner OS $RUNNER_OS" + exit 1 + fi + + artefact="opendaq-${version}-${platform}.${packaging}" + scheme="s3" + authority="bb-blueberry-sdk-releases" + sdk="releases/v${version}/SDK" + + echo "version=$version" >> $GITHUB_OUTPUT + echo "platform=$platform" >> $GITHUB_OUTPUT + echo "packaging=$packaging" >> $GITHUB_OUTPUT + echo "artefact=$artefact" >> $GITHUB_OUTPUT + echo "scheme=$scheme" >> $GITHUB_OUTPUT + echo "authority=$authority" >> $GITHUB_OUTPUT + echo "path=$sdk" >> $GITHUB_OUTPUT + echo "uri=${scheme}://${authority}/${sdk}/${artefact}" >> $GITHUB_OUTPUT diff --git a/.github/actions/opendaq-download-github/action.yml b/.github/actions/opendaq-download-github/action.yml new file mode 100644 index 0000000..45d1055 --- /dev/null +++ b/.github/actions/opendaq-download-github/action.yml @@ -0,0 +1,67 @@ +name: Download openDAQ framework package from GitHub +description: "Download openDAQ package from GitHub" + +inputs: + source-type: + description: "Where to publish the build result (artifact or release)" + required: true + + opendaq-package-filename: + description: "Package filename to download" + required: true + + artifact-run-id: + required: false + + opendaq-release-version: + required: false + default: '' + + destination-directory: + required: false + default: ${{ runner.temp }} + +runs: + using: composite + steps: + - name: Validate arguments + shell: bash + run: | + echo "::group::Validating openDAQ package inputs" + + # Array of allowed source-types + expected_source_types=("artifact" "release") + actual_source_type="${{ inputs.source-type }}" + package_filename="${{ inputs.opendaq-package-filename }}" + + # Validate that source-type is not empty + if [[ -z "$actual_source_type" ]]; then + echo "::error ::❌ openDAQ package source-type is empty. Expected: ${expected_source_types[*]}" + exit 1 + fi + + # Validate that source-type is one of the allowed values + if [[ ! " ${expected_source_types[@]} " =~ " ${actual_source_type} " ]]; then + echo "::error ::❌ openDAQ package source-type='${actual_source_type}' is not supported. Expected: ${expected_source_types[*]}" + exit 1 + fi + + echo "::notice ::✅ openDAQ package source-type '${actual_source_type}' is valid." + + # Validate that package filename is not empty + if [[ -z "$package_filename" ]]; then + echo "::error ::❌ openDAQ package filename is empty. It must not be empty." + exit 1 + fi + + echo "::notice ::✅ openDAQ package filename '${package_filename}' is valid." + + echo "::endgroup::" + + - name: Download openDAQ release + if: ${{ inputs.source-type == 'release' }} + run: gh release download ${{ inputs.opendaq-release-version }} --repo openDAQ/openDAQ --pattern ${{ inputs.opendaq-package-filename }} --dir ${{ inputs.destination-directory }} + + - name: Download openDAQ artifact + if: ${{ inputs.source-type == 'artifact' }} + run: gh run download ${{ inputs.artifact-run-id }} --repo openDAQ/openDAQ --pattern ${{ inputs.opendaq-package-filename }} --dir ${{ inputs.destination-directory }} diff --git a/.github/actions/opendaq-github-download-artifact/action.yml b/.github/actions/opendaq-github-download-artifact/action.yml new file mode 100644 index 0000000..b3272aa --- /dev/null +++ b/.github/actions/opendaq-github-download-artifact/action.yml @@ -0,0 +1,56 @@ +name: Download openDAQ artifact from GitHub +description: "Download openDAQ artifact from GitHub workflow by run ID and artifact name" + +inputs: + opendaq-artifact-run-id: + required: true + + opendaq-artifact-name: + required: true + + destination-dir: + required: false + default: ${{ runner.temp }} + +runs: + using: composite + steps: + - name: Download openDAQ artifact + shell: bash + run: | + DEST="${{ inputs.destination-dir }}" + DEST=$(echo "$DEST" | sed 's|\\|/|g') + RUN_ID="${{ inputs.opendaq-artifact-run-id }}" + + ARTIFACT_NAME="${{ inputs.opendaq-artifact-name }}" + ARTIFACT_DIR="$DEST/$ARTIFACT_NAME" + + echo "ARTIFACT_DIR=$ARTIFACT_DIR" + echo "ARTIFACT_NAME=$ARTIFACT_NAME" + echo "RUN_ID=$RUN_ID" + + REPO="openDAQ/openDAQ" + + + URL=$(gh api repos/$REPO/actions/runs/$RUN_ID/artifacts \ + --jq ".artifacts[] | select(.name==\"$ARTIFACT_NAME\") | .archive_download_url") + + echo "URL to download: '$url'" + if [ -z "$URL" ]; then + echo "❌ Artifact '$ARTIFACT_NAME' not found in run $RUN_ID" + exit 1 + fi + + ZIP_PATH="$DEST/$ARTIFACT_NAME.zip" + gh api "$URL" --output "$ZIP_PATH" + + echo "📦 Downloaded $ZIP_PATH" + unzip -o "$ZIP_PATH" -d "$DEST/$ARTIFACT_NAME" + + # gh run download ${{ inputs.opendaq-artifact-run-id }} \ + # --repo openDAQ/openDAQ \ + # --name $ARTIFACT_NAME \ + # --dir "$DEST" + + echo "$ARTIFACT_DIR/" + ls -la "$ARTIFACT_DIR/" diff --git a/.github/actions/opendaq-github-download-release/action.yml b/.github/actions/opendaq-github-download-release/action.yml new file mode 100644 index 0000000..cf7adc8 --- /dev/null +++ b/.github/actions/opendaq-github-download-release/action.yml @@ -0,0 +1,20 @@ +name: Download openDAQ framework release package from GitHub +description: "Download openDAQ package from GitHub" + +inputs: + opendaq-release-version: + required: false + default: '' + + destination-dir: + required: false + default: ${{ runner.temp }} + +runs: + using: composite + steps: + - name: Download openDAQ release + shell: bash + run: | + echo "::group::Do openDAQ package inputs" + gh release download diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..bfa5c5b --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,4 @@ +## CI/CD Workflows + +- [Build and Test Simple FB Module](ci.md) + Builds and tests against openDAQ framework (latest or specific version). diff --git a/.github/workflows/build-tests.yml b/.github/workflows/build-tests.yml new file mode 100644 index 0000000..ff24ed3 --- /dev/null +++ b/.github/workflows/build-tests.yml @@ -0,0 +1,104 @@ +name: Build simple FB module with openDAQ framework and run tests + +on: + workflow_dispatch: + inputs: + runner: + description: "Runner label" + required: true + type: string + + branch: + description: "Branch to checkout" + required: true + type: string + + artifact-run-id: + required: true + type: string + + artifact-name: + required: true + type: string + + file-name: + required: true + type: string + + workflow_call: + inputs: + runner: + description: "Runner label" + required: true + type: string + + branch: + description: "Branch to checkout" + required: true + type: string + + artifact-run-id: + required: true + type: string + + artifact-name: + required: true + type: string + + file-name: + required: true + type: string + +env: + GH_TOKEN: ${{ github.token }} + +jobs: + build: + runs-on: ${{ inputs.runner }} + + steps: + - name: Checkout openDAQ module repository + uses: actions/checkout@v4 + with: + repository: openDAQ/SimpleFBModule + ref: ${{ inputs.branch }} + + # - name: Download openDAQ framework package + # uses: ./.github/actions/opendaq-github-download-artifact + # with: + # opendaq-artifact-run-id: ${{ inputs.artifact-run-id }} + # opendaq-artifact-name: ${{ inputs.artifact-name }} + + - name: Download openDAQ framework package + id: download + uses: openDAQ/actions/framework-download-artifact@action-opendaq-version-parse + with: + run-id: ${{ inputs.artifact-run-id }} + artifact-name: ${{ inputs.artifact-name }} + artifact-filename: ${{ inputs.file-name }} + + - name: Install openDAQ framework package + uses: ./.github/actions/framework-install + with: + opendaq-framework-package-filename: ${{ inputs.artifact-name }}/${{ inputs.file-name }} + + - name: Set CMake generator and platform + shell: bash + run: | + if [[ "${{ runner.os }}" == "Windows" ]]; then + echo "CMAKE_GENERATOR=Visual Studio 17 2022" >> $GITHUB_ENV + else + echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV + fi + + - name: Configure simple FB module with CMake + shell: bash + run: | + cmake -B build/output -S . -G "$CMAKE_GENERATOR" -DEXAMPLE_MODULE_ENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Release + + - name: Build simple FB module with CMake + run: cmake --build build/output --config Release + + - name: Run simple FB module tests with CMake + run: ctest --test-dir build/output --output-on-failure -C Release -V + diff --git a/.github/workflows/ci.md b/.github/workflows/ci.md new file mode 100644 index 0000000..a9341b3 --- /dev/null +++ b/.github/workflows/ci.md @@ -0,0 +1,50 @@ +# Build and Test Simple FB Module with openDAQ Framework + +This workflow builds and tests the **Simple FB Module** using the **openDAQ framework**. +It supports using either the **latest release** of openDAQ or a **specific version** provided as input. + +## Triggers + +- **push** to `main` +- **pull_request** targeting `main` or `jira/*` +- **workflow_dispatch** (manual run with parameters) + +## Inputs (workflow_dispatch) + +| Name | Type | Required | Default | Description | +|-----------------------------|--------|----------|---------|-------------| +| `branch` | string | no | `main` | Branch to checkout | +| `opendaq-framework-version` | string | no | `latest`| openDAQ framework version. Use `latest` for the newest release, or provide a specific version tag (e.g. `3.20.4`). | + +## Matrix + +The workflow runs on: + +- `ubuntu-latest` (CMake + Ninja) +- `windows-latest` (CMake + Visual Studio 17 2022) + +## Jobs and Steps + +1. **Checkout Simple FB Module repo** — fetches the specified branch. +2. **Determine openDAQ framework package** + - If `opendaq-framework-version` is `latest`, the workflow queries GitHub Releases for the newest version. + - If a version string is provided, that version is used directly. +3. **Download openDAQ framework** — fetches the package (from S3). +4. **Install openDAQ framework package** — installs the framework. +5. **Configure with CMake** — configures the project with the appropriate generator. +6. **Build with CMake** — builds the project. +7. **Run tests** — executes unit tests with CTest. + +## Examples + +### Automatic runs +- On push to `main` +- On pull request to `main` or `jira/*` + +### Manual run +```yaml +workflow_dispatch: + inputs: + branch: "feature/my-branch" + opendaq-framework-version: "3.20.4" +``` diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..01c0c60 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,105 @@ +name: Build and Test simple FB module with latest openDAQ release + +on: + push: + branches: + - main + + pull_request: + branches: + - main + - actions + + workflow_dispatch: + inputs: + + branch: + required: false + default: "main" + + opendaq-framework-version: + required: false + type: string + default: latest + +env: + GH_TOKEN: ${{ github.token }} + +jobs: + build-and-test: + permissions: + contents: read + actions: read + + env: + GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} + + strategy: + matrix: + include: + - os: ubuntu-latest + generator: Ninja + platform-alias: "ubuntu20.04-x86_64" + + - os: windows-latest + generator: "Visual Studio 17 2022" + platform-alias: "win64" + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout simple FB module repo + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch || github.event.client_payload.branch || github.ref }} + + - name: Determine openDAQ framework package + id: opendaq-framework + uses: ./.github/actions/framework-latest-release + with: + opendaq-framework-release-version: ${{ github.event.inputs.opendaq-framework-version || 'latest' }} + + - name: Actions temp + shell: bash + run: | + mkdir actions-temp + + - name: Compose framework filename + id: compose-framework-filename + uses: openDAQ/actions/framework-compose-filename@jira/TBBAS-2680-opendaq-gh-actions-github-api-wrapper-unit-tests + with: + platform: ${{ matrix.platform-alias }} + token: ${{ secrets.PAT_TOKEN }} + + - name: Download framework filename + id: download-framework-filename + uses: openDAQ/actions/framework-download-release@jira/TBBAS-2680-opendaq-gh-actions-github-api-wrapper-unit-tests + with: + platform: ${{ matrix.platform-alias }} + token: ${{ secrets.PAT_TOKEN }} + + - name: Normalize downloaded asset + id: normalize-path + shell: bash + run: | + asset=${{ steps.download-framework-filename.outputs.asset }} + # Normalize output-dir path for cross-platform compatibility + if command -v cygpath >/dev/null 2>&1; then + asset="$(cygpath -w "$asset")" + echo "Normalized path (Windows): $asset" + fi + echo "asset=$asset" >> $GITHUB_OUTPUT + + - name: Install openDAQ framework package + uses: openDAQ/actions/framework-install@jira/TBBAS-2680-opendaq-gh-actions-github-api-wrapper-unit-tests + with: + framework-filename: ${{ steps.normalize-path.outputs.asset }} + + - name: Configure simple FB module with CMake + run: cmake -B build/output -S . -G "${{ matrix.generator }}" -DEXAMPLE_MODULE_ENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Release + + - name: Build simple FB module with CMake + run: cmake --build build/output --config Release + + - name: Run simple FB module tests with CMake + run: ctest --test-dir build/output --output-on-failure -C Release -V diff --git a/CMakeLists.txt b/CMakeLists.txt index 6137cc7..0a6dacb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,10 @@ cmake_minimum_required(VERSION 3.25) -set(REPO_NAME example_fb_module) -set(REPO_OPTION_PREFIX EXAMPLE_MODULE) +project(SimpleFBModule VERSION 1.0.0) + +set(SIMPLE_FB_MODULE_OPENDAQ_SDK_VER "" CACHE STRING "Version of openDAQ SDK to build SimpleFBModule with") -project(${REPO_NAME} VERSION 1.0.0) +set(REPO_OPTION_PREFIX EXAMPLE_MODULE) +set(SDK_TARGET_NAMESPACE daq) if (POLICY CMP0135) cmake_policy(SET CMP0135 NEW) @@ -13,7 +15,7 @@ if (POLICY CMP0077) endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -list(APPEND CMAKE_MESSAGE_CONTEXT ${REPO_NAME}) +list(APPEND CMAKE_MESSAGE_CONTEXT ${PROJECT_NAME}) set(CMAKE_MESSAGE_CONTEXT_SHOW ON CACHE BOOL "Show CMake message context") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -21,7 +23,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") add_definitions(-DFMT_HEADER_ONLY) option(OPENDAQ_FB_EXAMPLE_ENABLE_APP "Enable building example function block application" OFF) -option(EXAMPLE_MODULE_ENABLE_TESTS "Enable building of test suite for the example function block module" OFF) +option(EXAMPLE_MODULE_ENABLE_TESTS "Enable building of test suite for the example function block module" ON) include(CommonUtils) setup_repo(${REPO_OPTION_PREFIX}) @@ -31,6 +33,11 @@ if(OPENDAQ_FB_EXAMPLE_ENABLE_APP) set(DAQMODULES_REF_DEVICE_MODULE ON CACHE BOOL "" FORCE) endif() +if(EXAMPLE_MODULE_ENABLE_TESTS) + message(STATUS "Unit tests are ENABLED") + enable_testing() +endif() + add_subdirectory(external) find_package(openDAQ) add_compile_definitions(MODULE_PATH="${OPENDAQ_MODULES_DIR}") @@ -60,4 +67,4 @@ elseif (UNIX AND NOT APPLE) endif() # Include CPack for packaging -include(CPack) \ No newline at end of file +include(CPack) diff --git a/README.md b/README.md index f46fd5b..80fdc03 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,63 @@ Simple example that builds an openDAQ module giving access to an example functio To test the module, enable the `OPENDAQ_FB_EXAMPLE_ENABLE_APP` cmake flag. Doing so will add an the openDAQ reference device and function block modules to your project. Those are used to create a simulator device via the "daqref://device0" connection string, as well as a renderer via the "RefFBModuleRenderer" function block ID. The main application connects a reference device signal into both the example scaler and renderer. Additionally, it connects the scaler output into the renderer. -To add additional tests, enable the `EXAMPLE_MODULE_ENABLE_TESTS` cmake flag. Doing so will create a new test target configured for use with the GTest framework. \ No newline at end of file +To add additional tests, enable the `EXAMPLE_MODULE_ENABLE_TESTS` cmake flag. Doing so will create a new test target configured for use with the GTest framework. + +--- + +## Prerequisites + +- **CMake** (>= 3.25) +- **Git** +- **C++ compiler** (Visual Studio on Windows, GCC/Clang on Linux/macOS) +- Optional: **openDAQ framework** installed locally or available via versioned checkout + +--- + +## Building the Project + +There are two main ways to provide the openDAQ framework: + +1. **Using a local openDAQ installation** + - Install the openDAQ package on your machine. + - Set the environment variable `OPENDAQ_ROOT` to the path containing the binaries. + - Then CMake will automatically detect the binaries during configuration. + +```bash +export OPENDAQ_ROOT=/path/to/opendaq + +cmake -S . -B build/output \ + -G "Ninja" \ + -DEXAMPLE_MODULE_ENABLE_TESTS=ON \ + -DSIMPLE_FB_MODULE_OPENDAQ_SDK_VER=3.20.4 +``` + +2. **Using a specific openDAQ version via CMake** + - Pass the desired version using the `SIMPLE_FB_MODULE_OPENDAQ_SDK_VER`. + - CMake will perform a checkout of the openDAQ repository at the specified tag and build the minimal set of binaries needed to build the module and run tests. + +```bash +cmake -S . -B build/output \ + -G "Ninja" \ + -DEXAMPLE_MODULE_ENABLE_TESTS=ON \ + -DSIMPLE_FB_MODULE_OPENDAQ_SDK_VER=3.20.4 +``` + +--- + +### Example: Build Module + +```bash +cmake --build build/output --config Release +``` + +#### Note: +- The flag `EXAMPLE_MODULE_ENABLE_TESTS=ON` is required if you want to build the module tests for subsequent execution. +- Building the module without `EXAMPLE_MODULE_ENABLE_TESTS=ON` will skip test compilation. +- Providing either `OPENDAQ_ROOT` or `SIMPLE_FB_MODULE_OPENDAQ_SDK_VER` is mandatory for the module to find the required binaries. + +### Running Tests +Once the build is complete: +```bash +ctest --test-dir build/output --output-on-failure -C Release -V +``` \ No newline at end of file diff --git a/example_module/src/CMakeLists.txt b/example_module/src/CMakeLists.txt index dff37d8..613b0f7 100644 --- a/example_module/src/CMakeLists.txt +++ b/example_module/src/CMakeLists.txt @@ -1,5 +1,6 @@ set(LIB_NAME example_module) set(MODULE_HEADERS_DIR ../include/${TARGET_FOLDER_NAME}) +list(APPEND CMAKE_MESSAGE_CONTEXT ${LIB_NAME}) set(SRC_Include common.h module_dll.h @@ -33,6 +34,7 @@ if (MSVC) target_compile_options(${LIB_NAME} PRIVATE /bigobj) endif() +find_package(openDAQ ${SIMPLE_FB_MODULE_OPENDAQ_SDK_VER} REQUIRED) target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq ) diff --git a/example_module/tests/CMakeLists.txt b/example_module/tests/CMakeLists.txt index 7265fbc..c3928a9 100644 --- a/example_module/tests/CMakeLists.txt +++ b/example_module/tests/CMakeLists.txt @@ -1,5 +1,6 @@ set(MODULE_NAME example_module) set(TEST_APP test_${MODULE_NAME}) +list(APPEND CMAKE_MESSAGE_CONTEXT ${TEST_APP}) set(TEST_SOURCES test_example_module.cpp test_app.cpp @@ -8,11 +9,33 @@ set(TEST_SOURCES test_example_module.cpp add_executable(${TEST_APP} ${TEST_SOURCES} ) -target_link_libraries(${TEST_APP} PRIVATE daq::test_utils +find_package(openDAQ ${SIMPLE_DEVICE_MODULE_OPENDAQ_SDK_VER} REQUIRED) +target_link_libraries(${TEST_APP} PRIVATE daq::opendaq ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} ) +if (NOT TARGET gtest) + include(FetchContent) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip + ) + set(BUILD_GMOCK ON CACHE BOOL "" FORCE) + set(BUILD_GTEST ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) +endif() + +target_link_libraries(${TEST_APP} + PRIVATE + GTest::gtest + GTest::gtest_main + GTest::gmock + GTest::gmock_main +) + add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) + +set_target_properties(${TEST_APP} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY $) \ No newline at end of file diff --git a/example_module/tests/test_app.cpp b/example_module/tests/test_app.cpp index 4f6ea7d..37ad2b1 100644 --- a/example_module/tests/test_app.cpp +++ b/example_module/tests/test_app.cpp @@ -1,20 +1,10 @@ -#include -#include +#include #include -#include -#include - int main(int argc, char** args) { - daq::daqInitializeCoreObjectsTesting(); - daqInitModuleManagerLibrary(); - testing::InitGoogleTest(&argc, args); - testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); - listeners.Append(new DaqMemCheckListener()); - auto res = RUN_ALL_TESTS(); return res; diff --git a/example_module/tests/test_example_module.cpp b/example_module/tests/test_example_module.cpp index 45e6032..4c96694 100644 --- a/example_module/tests/test_example_module.cpp +++ b/example_module/tests/test_example_module.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index c6ccc9d..0336b9d 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -5,6 +5,7 @@ if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "In-source build is not supported!") endif() -include(FetchContent) - -add_subdirectory(openDAQ) +find_package(openDAQ ${SIMPLE_FB_MODULE_OPENDAQ_SDK_VER}) +if (NOT openDAQ_FOUND) + add_subdirectory(openDAQ) +endif() diff --git a/external/openDAQ/CMakeLists.txt b/external/openDAQ/CMakeLists.txt index 065369b..45f89d8 100644 --- a/external/openDAQ/CMakeLists.txt +++ b/external/openDAQ/CMakeLists.txt @@ -1,12 +1,18 @@ set(OPENDAQ_ENABLE_TESTS false) +if(NOT SIMPLE_FB_MODULE_OPENDAQ_SDK_VER) + message(FATAL_ERROR "SIMPLE_FB_MODULE_OPENDAQ_SDK_VER is not set") +endif() + +include(FetchContent) + FetchContent_Declare( openDAQ GIT_REPOSITORY https://github.com/openDAQ/openDAQ.git - GIT_TAG v3.20.2 + GIT_TAG v${SIMPLE_FB_MODULE_OPENDAQ_SDK_VER} GIT_PROGRESS ON - SYSTEM - FIND_PACKAGE_ARGS 3.20.2 GLOBAL + SYSTEM + FIND_PACKAGE_ARGS ${SIMPLE_FB_MODULE_OPENDAQ_SDK_VER} GLOBAL ) FetchContent_MakeAvailable(openDAQ)