mirror of
https://github.com/threeal/cmake-action.git
synced 2025-04-21 19:11:21 +00:00
Compare commits
No commits in common. "main" and "v1.1.0" have entirely different histories.
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,2 +0,0 @@
|
||||
dist/** -diff linguist-generated
|
||||
pnpm-lock.yaml -diff linguist-generated
|
18
.github/dependabot.yaml
vendored
18
.github/dependabot.yaml
vendored
@ -1,18 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
commit-message:
|
||||
prefix: chore
|
||||
labels: []
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
commit-message:
|
||||
prefix: chore
|
||||
labels: []
|
||||
versioning-strategy: increase
|
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
25
.github/workflows/build.yaml
vendored
25
.github/workflows/build.yaml
vendored
@ -1,25 +0,0 @@
|
||||
name: Build
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
jobs:
|
||||
build-package:
|
||||
name: Build Package
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: threeal/setup-pnpm-action@v1.0.0
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build Package
|
||||
run: pnpm build
|
||||
|
||||
- name: Check Diff
|
||||
run: git diff && git diff-index --quiet --exit-code HEAD
|
28
.github/workflows/check.yaml
vendored
28
.github/workflows/check.yaml
vendored
@ -1,28 +0,0 @@
|
||||
name: Check
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
jobs:
|
||||
check-package:
|
||||
name: Check Package
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: threeal/setup-pnpm-action@v1.0.0
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Check Formatting
|
||||
run: pnpm format
|
||||
|
||||
- name: Check Diff
|
||||
run: git diff && git diff-index --quiet --exit-code HEAD
|
||||
|
||||
- name: Check Lint
|
||||
run: pnpm lint
|
168
.github/workflows/test.yaml
vendored
168
.github/workflows/test.yaml
vendored
@ -1,168 +0,0 @@
|
||||
name: Test
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
jobs:
|
||||
test-package:
|
||||
name: Test Package
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: threeal/setup-pnpm-action@v1.0.0
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Test Package
|
||||
run: pnpm test
|
||||
|
||||
test-action:
|
||||
name: Test Action
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, macos-14, windows-2022]
|
||||
steps:
|
||||
- name: Checkout Sample Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
repository: threeal/cpp-starter
|
||||
ref: v1.0.0
|
||||
|
||||
- name: Checkout Action
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
path: cmake-action
|
||||
sparse-checkout: |
|
||||
action.yml
|
||||
dist
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Build Sample Project
|
||||
id: cmake-action
|
||||
uses: ./cmake-action
|
||||
|
||||
- name: Run Sample Project
|
||||
run: ${{ steps.cmake-action.outputs.build-dir }}/${{ matrix.os == 'windows-2022' && 'Debug/generate_sequence.exe' || 'generate_sequence' }} 5
|
||||
|
||||
test-action-with-specified-dirs:
|
||||
name: Test Action With Specified Directories
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Sample Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
repository: threeal/cpp-starter
|
||||
ref: v1.0.0
|
||||
path: project
|
||||
|
||||
- name: Checkout Action
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
path: cmake-action
|
||||
sparse-checkout: |
|
||||
action.yml
|
||||
dist
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Build Sample Project
|
||||
id: cmake-action
|
||||
uses: ./cmake-action
|
||||
with:
|
||||
source-dir: project
|
||||
build-dir: output
|
||||
|
||||
- name: Run Sample Project
|
||||
run: output/generate_sequence 5
|
||||
|
||||
test-action-without-run-build:
|
||||
name: Test Action Without Run Build
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Sample Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
repository: threeal/cpp-starter
|
||||
ref: v1.0.0
|
||||
|
||||
- name: Checkout Action
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
path: cmake-action
|
||||
sparse-checkout: |
|
||||
action.yml
|
||||
dist
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Modify Sample Project
|
||||
run: echo 'invalid' >> src/main.cpp
|
||||
|
||||
- name: Configure Sample Project
|
||||
uses: ./cmake-action
|
||||
with:
|
||||
run-build: false
|
||||
|
||||
test-action-with-additional-options:
|
||||
name: Test Action With Additional Options
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Sample Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
repository: threeal/cpp-starter
|
||||
ref: v1.0.0
|
||||
|
||||
- name: Checkout Action
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
path: cmake-action
|
||||
sparse-checkout: |
|
||||
action.yml
|
||||
dist
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Build Sample Project
|
||||
uses: ./cmake-action
|
||||
with:
|
||||
options: BUILD_TESTING=ON
|
||||
|
||||
- name: Test Sample Project
|
||||
uses: threeal/ctest-action@v1.1.0
|
||||
|
||||
test-action-with-custom-generator:
|
||||
name: Test Action With Custom Generator
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Sample Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
repository: threeal/cpp-starter
|
||||
ref: v1.0.0
|
||||
|
||||
- name: Checkout Action
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
path: cmake-action
|
||||
sparse-checkout: |
|
||||
action.yml
|
||||
dist
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Setup Ninja
|
||||
uses: seanmiddleditch/gha-setup-ninja@v6
|
||||
|
||||
- name: Configure Sample Project
|
||||
id: cmake-action
|
||||
uses: ./cmake-action
|
||||
with:
|
||||
generator: Ninja
|
||||
run-build: false
|
||||
|
||||
- name: Build Sample Project
|
||||
run: ninja -C ${{ steps.cmake-action.outputs.build-dir }}
|
97
.github/workflows/test.yml
vendored
Normal file
97
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
name: test
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
jobs:
|
||||
default-usage:
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows, ubuntu, macos]
|
||||
steps:
|
||||
- name: Check out this repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Move test project to the working directory
|
||||
run: mv test/* .
|
||||
|
||||
- name: Use this action
|
||||
uses: ./
|
||||
|
||||
- name: Run the build result
|
||||
run: ${{ matrix.os == 'windows' && 'build\Debug\hello_world.exe' || 'build/hello_world' }}
|
||||
|
||||
specified-dir-usage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out this repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Use this action with specified directories
|
||||
uses: ./
|
||||
with:
|
||||
source-dir: test
|
||||
build-dir: output
|
||||
run-test: true
|
||||
test-args: -R hello_world
|
||||
|
||||
- name: Check if the default build directory does not exist
|
||||
run: test ! -d build && test ! -d test/build
|
||||
|
||||
additional-flags-usage:
|
||||
runs-on: ${{ matrix.compiler == 'msvc' && 'windows' || 'ubuntu' }}-latest
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [gcc, msvc]
|
||||
steps:
|
||||
- name: Check out this repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Use this action with additional compiler flags
|
||||
uses: ./
|
||||
with:
|
||||
source-dir: test
|
||||
targets: test_c test_cpp
|
||||
run-test: true
|
||||
c-flags: ${{ matrix.compiler == 'msvc' && '/w /WX-' || '-Wno-unused-variable' }}
|
||||
cxx-flags: ${{ matrix.compiler == 'msvc' && '/w /WX-' || '-Wno-unused-variable' }}
|
||||
args: -D CHECK_SURPASS_WARNING=ON
|
||||
test-args: -R test ${{ matrix.compiler == 'msvc' && '-C Debug' || '' }}
|
||||
|
||||
specified-compiler-usage:
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows, ubuntu, macos]
|
||||
steps:
|
||||
- name: Check out this repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Use this action with specified compilers
|
||||
uses: ./
|
||||
with:
|
||||
source-dir: test
|
||||
targets: test_c test_cpp
|
||||
run-test: true
|
||||
generator: Ninja
|
||||
c-compiler: clang
|
||||
cxx-compiler: clang++
|
||||
args: -D CHECK_USING_CLANG=ON
|
||||
test-args: -R test
|
||||
|
||||
specified-generator-usage:
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows, ubuntu, macos]
|
||||
steps:
|
||||
- name: Check out this repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Use this action with a specified generator
|
||||
uses: ./
|
||||
with:
|
||||
source-dir: test
|
||||
run-test: true
|
||||
generator: Ninja
|
||||
test-args: -R hello_world
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,6 +1 @@
|
||||
.*
|
||||
!.git*
|
||||
!.npmrc
|
||||
!.prettierignore
|
||||
|
||||
node_modules/
|
||||
build
|
||||
|
@ -1 +0,0 @@
|
||||
pnpm-lock.yaml
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023-2025 Alfi Maulana
|
||||
Copyright (c) 2023 Alfi Maulana
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
137
README.md
137
README.md
@ -1,106 +1,107 @@
|
||||
# CMake Action
|
||||
|
||||
Configure and build [CMake](https://cmake.org/) projects on [GitHub Actions](https://github.com/features/actions).
|
||||
[](https://github.com/threeal/cmake-action/releases/)
|
||||
[](./LICENSE)
|
||||
[](https://github.com/threeal/cmake-action/actions/workflows/test.yml)
|
||||
|
||||
This action wraps the [`cmake`](https://cmake.org/cmake/help/latest/manual/cmake.1.html) command for configuring and building CMake projects. It provides a more streamlined syntax for specifying build options compared to calling the `cmake` command directly.
|
||||
Configure, build, and test a [CMake](https://cmake.org/) project on [GitHub Actions](https://github.com/features/actions).
|
||||
Use this action to simplify the workflow run of your CMake project.
|
||||
This action will configure a build environment for your project using the `cmake` command,
|
||||
then it will build your project by running a `cmake --build` command,
|
||||
and last it could test your project using the `ctest` command.
|
||||
|
||||
## Available Inputs
|
||||
## Features
|
||||
|
||||
- Configure and build a project using the [cmake](https://cmake.org/cmake/help/latest/manual/cmake.1.html) command.
|
||||
- Optionally test a project using the [ctest](https://cmake.org/cmake/help/latest/manual/ctest.1.html) command.
|
||||
- Auto-detect and install required dependencies.
|
||||
- Specify multiple CMake options directly from the Action inputs.
|
||||
|
||||
## Usage
|
||||
|
||||
For more information, see [action.yml](./action.yml) and [GitHub Actions guide](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions).
|
||||
|
||||
### Inputs
|
||||
|
||||
| Name | Value Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `source-dir` | Path | The source directory of the CMake project. Defaults to the current working directory. |
|
||||
| `build-dir` | Path | The build directory of the CMake project. Defaults to the `build` directory inside the source directory. |
|
||||
| `generator` | String | The build system generator for the CMake project. Equivalent to setting the `-G` option. |
|
||||
| `c-compiler` | String | The preferred executable for compiling C language files. Equivalent to defining the `CMAKE_C_COMPILER` variable. |
|
||||
| `cxx-compiler` | String | The preferred executable for compiling C++ language files. Equivalent to defining the `CMAKE_CXX_COMPILER` variable. |
|
||||
| `c-flags` | Multiple strings | Additional flags to pass when compiling C language files. Equivalent to defining the `CMAKE_C_FLAGS` variable. |
|
||||
| `cxx-flags` | Multiple strings | Additional flags to pass when compiling C++ language files. Equivalent to defining the `CMAKE_CXX_FLAGS` variable. |
|
||||
| `options` | Multiple strings | Additional options to pass during the CMake configuration. Equivalent to setting the `-D` option. |
|
||||
| `args` | Multiple strings | Additional arguments to pass during the CMake configuration. |
|
||||
| `run-build` | `true` or `false` | If enabled, builds the project using CMake. Defaults to `true`. |
|
||||
| `build-args` | Multiple strings | Additional arguments to pass during the CMake build. |
|
||||
| `source-dir` | Path | Source directory of the CMake project. Defaults to current directory. |
|
||||
| `build-dir` | Path | Build directory of the CMake project. Defaults to `build` directory inside the source directory. |
|
||||
| `targets` | Multiple strings | List of build targets. |
|
||||
| `run-test` | `true` or `false` | If enabled, run testing using [CTest](https://cmake.org/cmake/help/latest/manual/ctest.1.html). Defaults to `false`. |
|
||||
| `generator` | String | Build system generator of the CMake project. |
|
||||
| `c-compiler` | String | Preferred executable for compiling C language files. |
|
||||
| `cxx-compiler` | String | Preferred executable for compiling C++ language files. |
|
||||
| `c-flags` | Multiple strings | Additional flags passed when compiling C language files. |
|
||||
| `cxx-flags` | Multiple strings | Additional flags passed when compiling C++ language files. |
|
||||
| `args` | Multiple strings | Additional arguments passed during the CMake configuration. |
|
||||
| `test-args` | Multiple strings | Additional arguments passed during the CTest run. |
|
||||
|
||||
## Available Outputs
|
||||
> Note: Multiple strings mean that the input could be specified with more than one value. Separate each value with a space or a new line.
|
||||
|
||||
| Name | Value Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `build-dir` | Path | The build directory of the CMake project. |
|
||||
> Note: All inputs are optional.
|
||||
|
||||
## Example Usages
|
||||
|
||||
This example demonstrates how to use this action to configure and build a CMake project in a GitHub Actions workflow:
|
||||
### Examples
|
||||
|
||||
```yaml
|
||||
name: Build
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
jobs:
|
||||
build-project:
|
||||
name: Build Project
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4.2.2
|
||||
- name: Check out this repository
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
- name: Build Project
|
||||
uses: threeal/cmake-action@v2.1.0
|
||||
- name: Configure and build this project
|
||||
uses: threeal/cmake-action@latest
|
||||
```
|
||||
|
||||
### Specify the Source and Build Directories
|
||||
> Note: You can replace `@latest` with any version you like. See [this](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses).
|
||||
|
||||
By default, this action uses the current working directory as the source directory and the `build` directory inside the source directory as the build directory. To use different directories, set the `source-dir` and/or `build-dir` inputs:
|
||||
#### Specify the Source and the Build Directories
|
||||
|
||||
```yaml
|
||||
- name: Build Project
|
||||
uses: threeal/cmake-action@v2.1.0
|
||||
- name: Configure and build this project
|
||||
uses: threeal/cmake-action@latest
|
||||
with:
|
||||
source-dir: source
|
||||
build-dir: output
|
||||
source-dir: submodules
|
||||
build-dir: submodules/out
|
||||
```
|
||||
|
||||
### Specify Build System Generator and Compiler
|
||||
|
||||
The following example demonstrates how to use this action to configure and build the project using [Ninja](https://ninja-build.org/) as the build system generator and [Clang](https://clang.llvm.org/) as the compiler:
|
||||
#### Specify the Build Targets
|
||||
|
||||
```yaml
|
||||
- name: Setup Ninja
|
||||
uses: seanmiddleditch/gha-setup-ninja@v5
|
||||
- name: Configure and build this project
|
||||
uses: threeal/cmake-action@latest
|
||||
with:
|
||||
targets: hello_mars hello_sun
|
||||
```
|
||||
|
||||
- name: Build Project
|
||||
uses: threeal/cmake-action@v2.1.0
|
||||
#### Run Unit Tests After Build
|
||||
|
||||
```yaml
|
||||
- name: Configure, build, and test this project
|
||||
uses: threeal/cmake-action@latest
|
||||
with:
|
||||
args: -DBUILD_TESTING=ON
|
||||
run-test: true
|
||||
```
|
||||
|
||||
#### Using Ninja as the Generator and Clang as the Compiler
|
||||
|
||||
```yaml
|
||||
- name: Configure and build this project
|
||||
uses: threeal/cmake-action@latest
|
||||
with:
|
||||
generator: Ninja
|
||||
c-compiler: clang
|
||||
cxx-compiler: clang++
|
||||
```
|
||||
|
||||
### Specify Additional Options
|
||||
|
||||
Use the `options` input to specify additional options for configuring a project:
|
||||
|
||||
```yaml
|
||||
- name: Build Project
|
||||
uses: threeal/cmake-action@v2.1.0
|
||||
with:
|
||||
options: |
|
||||
BUILD_TESTS=ON
|
||||
BUILD_EXAMPLES=ON
|
||||
```
|
||||
|
||||
The above example is equivalent to calling the `cmake` command with the `-DBUILD_TESTS=ON` and `-DBUILD_EXAMPLES=ON` arguments.
|
||||
|
||||
### Configure Project Without Building
|
||||
|
||||
By default, this action builds the project after configuration. To skip the build process, set the `run-build` option to `false`:
|
||||
|
||||
```yaml
|
||||
- name: Configure Project
|
||||
uses: threeal/cmake-action@v2.1.0
|
||||
with:
|
||||
run-build: false
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the terms of the [MIT License](./LICENSE).
|
||||
|
||||
Copyright © 2023-2025 [Alfi Maulana](https://github.com/threeal/)
|
||||
Copyright © 2023 [Alfi Maulana](https://github.com/threeal/)
|
||||
|
121
action.yml
121
action.yml
@ -1,37 +1,114 @@
|
||||
name: CMake Action
|
||||
description: Configure and build CMake projects
|
||||
description: Configure, build, and test a CMake project
|
||||
author: Alfi Maulana
|
||||
branding:
|
||||
color: gray-dark
|
||||
icon: terminal
|
||||
inputs:
|
||||
source-dir:
|
||||
description: The source directory of the CMake project
|
||||
description: Source directory of the CMake project
|
||||
required: false
|
||||
build-dir:
|
||||
description: The build directory of the CMake project
|
||||
description: Build directory of the CMake project
|
||||
required: false
|
||||
targets:
|
||||
description: List of build targets
|
||||
required: false
|
||||
run-test:
|
||||
description: If enabled, run testing using CTest (true/false)
|
||||
required: false
|
||||
default: false
|
||||
generator:
|
||||
description: The build system generator for the CMake project
|
||||
description: Build system generator of the CMake project
|
||||
required: false
|
||||
c-compiler:
|
||||
description: The preferred executable for compiling C language files
|
||||
description: Preferred executable for compiling C language files
|
||||
required: false
|
||||
cxx-compiler:
|
||||
description: The preferred executable for compiling C++ language files
|
||||
description: Preferred executable for compiling C++ language files
|
||||
required: false
|
||||
c-flags:
|
||||
description: Additional flags to pass when compiling C language files
|
||||
description: Additional flags passed when compiling C language files
|
||||
required: false
|
||||
cxx-flags:
|
||||
description: Additional flags to pass when compiling C++ language files
|
||||
options:
|
||||
description: Additional options to pass during the CMake configuration
|
||||
description: Additional flags passed when compiling C++ language files
|
||||
required: false
|
||||
args:
|
||||
description: Additional arguments to pass during the CMake configuration
|
||||
run-build:
|
||||
description: If enabled, builds the project using CMake
|
||||
default: true
|
||||
build-args:
|
||||
description: Additional arguments to pass during the CMake build
|
||||
outputs:
|
||||
build-dir:
|
||||
description: The build directory of the CMake project
|
||||
value: ${{ steps.process-inputs.outputs.build-dir }}
|
||||
description: Additional arguments passed during the CMake configuration
|
||||
required: false
|
||||
test-args:
|
||||
description: Additional arguments passed during the CTest run
|
||||
required: false
|
||||
runs:
|
||||
using: node20
|
||||
main: dist/action.mjs
|
||||
using: composite
|
||||
steps:
|
||||
- name: Process the inputs
|
||||
id: process_inputs
|
||||
shell: bash
|
||||
run: |
|
||||
SOURCE_DIR="."
|
||||
if [ -n '${{ inputs.source-dir }}' ]; then
|
||||
SOURCE_DIR="${{ inputs.source-dir }}"
|
||||
fi
|
||||
BUILD_DIR="build"
|
||||
if [ -n '${{ inputs.build-dir }}' ]; then
|
||||
BUILD_DIR="${{ inputs.build-dir }}"
|
||||
elif [ -n "${{ inputs.source-dir }}" ]; then
|
||||
BUILD_DIR="${{ inputs.source-dir }}/build"
|
||||
fi
|
||||
ARGS="'$SOURCE_DIR' -B '$BUILD_DIR'"
|
||||
BUILD_ARGS="--build '$BUILD_DIR'"
|
||||
TEST_ARGS=""
|
||||
if [ -n '${{ inputs.targets }}' ]; then
|
||||
BUILD_ARGS="$BUILD_ARGS --target ${{ inputs.targets }}"
|
||||
fi
|
||||
if [ '${{ inputs.run-test }}' == 'true' ]; then
|
||||
TEST_ARGS="--test-dir '$BUILD_DIR' --output-on-failure --no-tests=error"
|
||||
fi
|
||||
if [ -n '${{ inputs.generator }}' ]; then
|
||||
ARGS="$ARGS -G '${{ inputs.generator }}'"
|
||||
fi
|
||||
if [ -n '${{ inputs.c-compiler }}' ]; then
|
||||
ARGS="$ARGS -D CMAKE_C_COMPILER='${{ inputs.c-compiler }}'"
|
||||
fi
|
||||
if [ -n '${{ inputs.cxx-compiler }}' ]; then
|
||||
ARGS="$ARGS -D CMAKE_CXX_COMPILER='${{ inputs.cxx-compiler }}'"
|
||||
fi
|
||||
if [ -n '${{ inputs.c-flags }}' ]; then
|
||||
ARGS="$ARGS -D CMAKE_C_FLAGS='${{ inputs.c-flags }}'"
|
||||
fi
|
||||
if [ -n '${{ inputs.cxx-flags }}' ]; then
|
||||
ARGS="$ARGS -D CMAKE_CXX_FLAGS='${{ inputs.cxx-flags }}'"
|
||||
fi
|
||||
if [ -n '${{ inputs.args }}' ]; then
|
||||
ARGS="$ARGS ${{ inputs.args }}"
|
||||
fi
|
||||
if [ -n '${{ inputs.test-args }}' ]; then
|
||||
TEST_ARGS="$TEST_ARGS ${{ inputs.test-args }}"
|
||||
fi
|
||||
echo "cmake_args=${ARGS//[$'\t\r\n']}" >> $GITHUB_OUTPUT
|
||||
echo "cmake_build_args=${BUILD_ARGS//[$'\t\r\n']}" >> $GITHUB_OUTPUT
|
||||
echo "cmake_test_args=${TEST_ARGS//[$'\t\r\n']}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install Ninja
|
||||
if: ${{ inputs.generator == 'Ninja' }}
|
||||
shell: bash
|
||||
run: |
|
||||
case "$OSTYPE" in
|
||||
darwin*) brew install ninja ;;
|
||||
linux*) sudo apt install -y ninja-build ;;
|
||||
*) choco install ninja ;;
|
||||
esac
|
||||
|
||||
- name: Configure the CMake project
|
||||
shell: ${{ runner.os == 'Windows' && 'pwsh' || 'bash' }}
|
||||
run: cmake ${{ steps.process_inputs.outputs.cmake_args }}
|
||||
|
||||
- name: Build targets
|
||||
shell: ${{ runner.os == 'Windows' && 'pwsh' || 'bash' }}
|
||||
run: cmake ${{ steps.process_inputs.outputs.cmake_build_args }}
|
||||
|
||||
- name: Run tests
|
||||
if: steps.process_inputs.outputs.cmake_test_args != ''
|
||||
shell: ${{ runner.os == 'Windows' && 'pwsh' || 'bash' }}
|
||||
run: ctest ${{ steps.process_inputs.outputs.cmake_test_args }}
|
||||
|
193
dist/action.mjs
vendored
193
dist/action.mjs
vendored
@ -1,193 +0,0 @@
|
||||
import 'node:fs';
|
||||
import fsPromises from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Retrieves the value of an environment variable.
|
||||
*
|
||||
* @param name - The name of the environment variable.
|
||||
* @returns The value of the environment variable.
|
||||
* @throws Error if the environment variable is not defined.
|
||||
*/
|
||||
function mustGetEnvironment(name) {
|
||||
const value = process.env[name];
|
||||
if (value === undefined) {
|
||||
throw new Error(`the ${name} environment variable must be defined`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Retrieves the value of a GitHub Actions input.
|
||||
*
|
||||
* @param name - The name of the GitHub Actions input.
|
||||
* @returns The value of the GitHub Actions input, or an empty string if not found.
|
||||
*/
|
||||
function getInput(name) {
|
||||
const value = process.env[`INPUT_${name.toUpperCase()}`] ?? "";
|
||||
return value.trim();
|
||||
}
|
||||
/**
|
||||
* Sets the value of a GitHub Actions output.
|
||||
*
|
||||
* @param name - The name of the GitHub Actions output.
|
||||
* @param value - The value to set for the GitHub Actions output.
|
||||
* @returns A promise that resolves when the value is successfully set.
|
||||
*/
|
||||
async function setOutput(name, value) {
|
||||
const filePath = mustGetEnvironment("GITHUB_OUTPUT");
|
||||
await fsPromises.appendFile(filePath, `${name}=${value}${os.EOL}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error message in GitHub Actions.
|
||||
*
|
||||
* @param err - The error, which can be of any type.
|
||||
*/
|
||||
function logError(err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
process.stdout.write(`::error::${message}${os.EOL}`);
|
||||
}
|
||||
/**
|
||||
* Logs a command along with its arguments in GitHub Actions.
|
||||
*
|
||||
* @param command - The command to log.
|
||||
* @param args - The arguments of the command.
|
||||
*/
|
||||
function logCommand(command, ...args) {
|
||||
const message = [command, ...args].join(" ");
|
||||
process.stdout.write(`[command]${message}${os.EOL}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a command with the given arguments.
|
||||
*
|
||||
* The command is executed with `stdin` ignored and both `stdout` and `stderr` inherited by the parent process.
|
||||
*
|
||||
* @param command The command to execute.
|
||||
* @param args The arguments to pass to the command.
|
||||
* @returns A promise that resolves when the command exits successfully or rejects if it exits with a non-zero status code or encounters an error.
|
||||
*/
|
||||
async function exec(command, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn(command, args, {
|
||||
stdio: ["ignore", "inherit", "inherit"],
|
||||
});
|
||||
logCommand(proc.spawnfile, ...proc.spawnargs.splice(1));
|
||||
proc.on("error", reject);
|
||||
proc.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Command exited with status code ${code}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the build system for a CMake project.
|
||||
*
|
||||
* Constructs and runs the `cmake` command to configure the project with the specified
|
||||
* source directory, build directory, generator, options, and additional arguments.
|
||||
*
|
||||
* @param context - The action context containing configuration details.
|
||||
* @returns A promise that resolves when the build system is successfully configured.
|
||||
*/
|
||||
async function configureProject(context) {
|
||||
const configureArgs = [];
|
||||
if (context.sourceDir) {
|
||||
configureArgs.push(context.sourceDir);
|
||||
}
|
||||
configureArgs.push("-B", context.buildDir);
|
||||
if (context.configure.generator) {
|
||||
configureArgs.push("-G", context.configure.generator);
|
||||
}
|
||||
configureArgs.push(...context.configure.options.map((opt) => "-D" + opt));
|
||||
configureArgs.push(...context.configure.args);
|
||||
await exec("cmake", configureArgs);
|
||||
}
|
||||
/**
|
||||
* Builds a CMake project.
|
||||
*
|
||||
* Runs the `cmake --build` command to build the project using the specified
|
||||
* build directory and additional arguments.
|
||||
*
|
||||
* @param context - The action context containing build details.
|
||||
* @returns A promise that resolves when the project is successfully built.
|
||||
*/
|
||||
async function buildProject(context) {
|
||||
await exec("cmake", ["--build", context.buildDir, ...context.build.args]);
|
||||
}
|
||||
|
||||
const regex = /"([^"]*)"|'([^']*)'|`([^`]*)`|(\S+)/g;
|
||||
/**
|
||||
* Converts a space-separated string into a list of arguments.
|
||||
*
|
||||
* This function parses the provided string, which contains arguments separated by spaces and possibly enclosed in quotes, into a list of arguments.
|
||||
*
|
||||
* @param str - The space-separated string to parse.
|
||||
* @returns A list of arguments.
|
||||
*/
|
||||
function parse(str) {
|
||||
const args = [];
|
||||
let match;
|
||||
while ((match = regex.exec(str)) !== null) {
|
||||
args.push(match[1] ?? match[2] ?? match[3] ?? match[4]);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
function getContext() {
|
||||
const sourceDir = getInput("source-dir");
|
||||
const options = [];
|
||||
let input = getInput("c-compiler");
|
||||
if (input)
|
||||
options.push(`CMAKE_C_COMPILER=${input}`);
|
||||
input = getInput("cxx-compiler");
|
||||
if (input)
|
||||
options.push(`CMAKE_CXX_COMPILER=${input}`);
|
||||
input = getInput("c-flags");
|
||||
if (input) {
|
||||
const flags = input.replaceAll(/\s+/g, " ");
|
||||
options.push(`CMAKE_C_FLAGS=${flags}`);
|
||||
}
|
||||
input = getInput("cxx-flags");
|
||||
if (input) {
|
||||
const flags = input.replaceAll(/\s+/g, " ");
|
||||
options.push(`CMAKE_CXX_FLAGS=${flags}`);
|
||||
}
|
||||
input = getInput("options");
|
||||
if (input) {
|
||||
options.push(...parse(input).map((opt) => opt.toString()));
|
||||
}
|
||||
return {
|
||||
sourceDir,
|
||||
buildDir: getInput("build-dir") || path.join(sourceDir, "build"),
|
||||
configure: {
|
||||
generator: getInput("generator"),
|
||||
options,
|
||||
args: parse(getInput("args")).map((arg) => arg.toString()),
|
||||
},
|
||||
build: {
|
||||
enabled: getInput("run-build") == "true",
|
||||
args: parse(getInput("build-args")).map((arg) => arg.toString()),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const context = getContext();
|
||||
await configureProject(context);
|
||||
await setOutput("build-dir", context.buildDir);
|
||||
if (context.build.enabled) {
|
||||
await buildProject(context);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logError(err);
|
||||
process.exit(1);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
...tseslint.configs.stylistic,
|
||||
{
|
||||
ignores: [".*", "dist"],
|
||||
},
|
||||
];
|
34
package.json
34
package.json
@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"format": "prettier --write --cache . !dist !README.md",
|
||||
"lint": "eslint",
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"gha-utils": "^0.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.24.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@rollup/plugin-typescript": "^12.1.2",
|
||||
"@tsconfig/node23": "^23.0.1",
|
||||
"@types/node": "^22.14.1",
|
||||
"@vitest/coverage-v8": "^3.0.8",
|
||||
"eslint": "^9.24.0",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup": "^4.40.0",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.30.1",
|
||||
"vitest": "^3.0.8"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"esbuild"
|
||||
]
|
||||
}
|
||||
}
|
2386
pnpm-lock.yaml
2386
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
|
||||
export default {
|
||||
input: "src/action.ts",
|
||||
output: {
|
||||
dir: "dist",
|
||||
entryFileNames: "[name].mjs",
|
||||
},
|
||||
plugins: [nodeResolve(), typescript()],
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import { logError, setOutput } from "gha-utils";
|
||||
import { buildProject, configureProject } from "./cmake.js";
|
||||
import { getContext } from "./context.js";
|
||||
|
||||
try {
|
||||
const context = getContext();
|
||||
|
||||
await configureProject(context);
|
||||
|
||||
await setOutput("build-dir", context.buildDir);
|
||||
|
||||
if (context.build.enabled) {
|
||||
await buildProject(context);
|
||||
}
|
||||
} catch (err) {
|
||||
logError(err);
|
||||
process.exit(1);
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { buildProject, configureProject } from "./cmake.js";
|
||||
import type { Context } from "./context.js";
|
||||
import { exec } from "./exec.js";
|
||||
|
||||
interface TestCase {
|
||||
name: string;
|
||||
context?: Partial<Context>;
|
||||
expectedArgs: string[];
|
||||
}
|
||||
|
||||
const defaultContext: Context = {
|
||||
sourceDir: "",
|
||||
buildDir: "build",
|
||||
configure: {
|
||||
generator: "",
|
||||
options: [],
|
||||
args: [],
|
||||
},
|
||||
build: {
|
||||
enabled: true,
|
||||
args: [],
|
||||
},
|
||||
};
|
||||
|
||||
vi.mock("./exec.js", () => ({ exec: vi.fn() }));
|
||||
|
||||
describe("configure a CMake project", () => {
|
||||
const testCases: TestCase[] = [
|
||||
{
|
||||
name: "with nothing specified",
|
||||
expectedArgs: ["-B", "build"],
|
||||
},
|
||||
{
|
||||
name: "with source directory specified",
|
||||
context: { sourceDir: "project" },
|
||||
expectedArgs: ["project", "-B", "build"],
|
||||
},
|
||||
{
|
||||
name: "with build directory specified",
|
||||
context: { buildDir: "output" },
|
||||
expectedArgs: ["-B", "output"],
|
||||
},
|
||||
{
|
||||
name: "with generator specified",
|
||||
context: { configure: { generator: "Ninja", options: [], args: [] } },
|
||||
expectedArgs: ["-B", "build", "-G", "Ninja"],
|
||||
},
|
||||
{
|
||||
name: "with additional options specified",
|
||||
context: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON"],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
expectedArgs: [
|
||||
"-B",
|
||||
"build",
|
||||
"-DBUILD_TESTING=ON",
|
||||
"-DBUILD_EXAMPLES=ON",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "with additional arguments specified",
|
||||
context: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: [],
|
||||
args: ["-Wdev", "-Wdeprecated"],
|
||||
},
|
||||
},
|
||||
expectedArgs: ["-B", "build", "-Wdev", "-Wdeprecated"],
|
||||
},
|
||||
{
|
||||
name: "with all specified",
|
||||
context: {
|
||||
sourceDir: "project",
|
||||
buildDir: "output",
|
||||
configure: {
|
||||
generator: "Ninja",
|
||||
options: ["BUILD_TESTING=ON", "BUILD_EXAMPLES=ON"],
|
||||
args: ["-Wdev", "-Wdeprecated"],
|
||||
},
|
||||
},
|
||||
expectedArgs: [
|
||||
"project",
|
||||
"-B",
|
||||
"output",
|
||||
"-G",
|
||||
"Ninja",
|
||||
"-DBUILD_TESTING=ON",
|
||||
"-DBUILD_EXAMPLES=ON",
|
||||
"-Wdev",
|
||||
"-Wdeprecated",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
it(`should execute the correct command ${testCase.name}`, async () => {
|
||||
vi.mocked(exec).mockReset();
|
||||
|
||||
await configureProject({ ...defaultContext, ...testCase.context });
|
||||
|
||||
expect(exec).toHaveBeenCalledTimes(1);
|
||||
expect(exec).toHaveBeenLastCalledWith("cmake", testCase.expectedArgs);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("build a CMake project", () => {
|
||||
const testCases: TestCase[] = [
|
||||
{
|
||||
name: "with nothing specified",
|
||||
expectedArgs: ["--build", "build"],
|
||||
},
|
||||
{
|
||||
name: "with build directory specified",
|
||||
context: { buildDir: "output" },
|
||||
expectedArgs: ["--build", "output"],
|
||||
},
|
||||
{
|
||||
name: "with additional arguments specified",
|
||||
context: { build: { enabled: true, args: ["--target", "foo"] } },
|
||||
expectedArgs: ["--build", "build", "--target", "foo"],
|
||||
},
|
||||
{
|
||||
name: "with all specified",
|
||||
context: {
|
||||
buildDir: "output",
|
||||
build: {
|
||||
enabled: true,
|
||||
args: ["--target", "foo"],
|
||||
},
|
||||
},
|
||||
expectedArgs: ["--build", "output", "--target", "foo"],
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
it(`should execute the correct command ${testCase.name}`, async () => {
|
||||
vi.mocked(exec).mockReset();
|
||||
|
||||
await buildProject({ ...defaultContext, ...testCase.context });
|
||||
|
||||
expect(exec).toHaveBeenCalledTimes(1);
|
||||
expect(exec).toHaveBeenLastCalledWith("cmake", testCase.expectedArgs);
|
||||
});
|
||||
}
|
||||
});
|
43
src/cmake.ts
43
src/cmake.ts
@ -1,43 +0,0 @@
|
||||
import { exec } from "./exec.js";
|
||||
import type { Context } from "./context.js";
|
||||
|
||||
/**
|
||||
* Configures the build system for a CMake project.
|
||||
*
|
||||
* Constructs and runs the `cmake` command to configure the project with the specified
|
||||
* source directory, build directory, generator, options, and additional arguments.
|
||||
*
|
||||
* @param context - The action context containing configuration details.
|
||||
* @returns A promise that resolves when the build system is successfully configured.
|
||||
*/
|
||||
export async function configureProject(context: Context): Promise<void> {
|
||||
const configureArgs = [];
|
||||
|
||||
if (context.sourceDir) {
|
||||
configureArgs.push(context.sourceDir);
|
||||
}
|
||||
|
||||
configureArgs.push("-B", context.buildDir);
|
||||
|
||||
if (context.configure.generator) {
|
||||
configureArgs.push("-G", context.configure.generator);
|
||||
}
|
||||
|
||||
configureArgs.push(...context.configure.options.map((opt) => "-D" + opt));
|
||||
configureArgs.push(...context.configure.args);
|
||||
|
||||
await exec("cmake", configureArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a CMake project.
|
||||
*
|
||||
* Runs the `cmake --build` command to build the project using the specified
|
||||
* build directory and additional arguments.
|
||||
*
|
||||
* @param context - The action context containing build details.
|
||||
* @returns A promise that resolves when the project is successfully built.
|
||||
*/
|
||||
export async function buildProject(context: Context): Promise<void> {
|
||||
await exec("cmake", ["--build", context.buildDir, ...context.build.args]);
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { Context } from "./context.js";
|
||||
|
||||
vi.mock("gha-utils", () => ({ getInput: vi.fn() }));
|
||||
|
||||
describe("get action context", () => {
|
||||
interface TestCase {
|
||||
name: string;
|
||||
inputs?: Record<string, string>;
|
||||
expectedContext?: Partial<Context>;
|
||||
}
|
||||
|
||||
const testCases: TestCase[] = [
|
||||
{
|
||||
name: "with nothing specified",
|
||||
},
|
||||
{
|
||||
name: "with source directory specified",
|
||||
inputs: { "source-dir": "project" },
|
||||
expectedContext: {
|
||||
sourceDir: "project",
|
||||
buildDir: path.join("project", "build"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with build directory specified",
|
||||
inputs: { "build-dir": "output" },
|
||||
expectedContext: { buildDir: "output" },
|
||||
},
|
||||
{
|
||||
name: "with source and build directories specified",
|
||||
inputs: {
|
||||
"source-dir": "project",
|
||||
"build-dir": "output",
|
||||
},
|
||||
expectedContext: {
|
||||
sourceDir: "project",
|
||||
buildDir: "output",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with generator specified",
|
||||
inputs: { generator: "Ninja" },
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "Ninja",
|
||||
options: [],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with C compiler specified",
|
||||
inputs: { "c-compiler": "clang" },
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: ["CMAKE_C_COMPILER=clang"],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with C++ compiler specified",
|
||||
inputs: { "cxx-compiler": "clang++" },
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: ["CMAKE_CXX_COMPILER=clang++"],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with C flags specified",
|
||||
inputs: { "c-flags": "-Werror -Wall\n-Wextra" },
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: ["CMAKE_C_FLAGS=-Werror -Wall -Wextra"],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with C++ flags specified",
|
||||
inputs: { "cxx-flags": "-Werror -Wall\n-Wextra -Wpedantic" },
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: ["CMAKE_CXX_FLAGS=-Werror -Wall -Wextra -Wpedantic"],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with additional options specified",
|
||||
inputs: {
|
||||
options: `BUILD_TESTING=ON BUILD_EXAMPLES=ON\nBUILD_DOCS=ON "FOO=BAR BAZ"`,
|
||||
},
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: [
|
||||
"BUILD_TESTING=ON",
|
||||
"BUILD_EXAMPLES=ON",
|
||||
"BUILD_DOCS=ON",
|
||||
"FOO=BAR BAZ",
|
||||
],
|
||||
args: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with additional arguments specified",
|
||||
inputs: { args: `-Wdev -Wdeprecated\n--fresh --foo "bar baz"` },
|
||||
expectedContext: {
|
||||
configure: {
|
||||
generator: "",
|
||||
options: [],
|
||||
args: ["-Wdev", "-Wdeprecated", "--fresh", "--foo", "bar baz"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with run build specified",
|
||||
inputs: { "run-build": "true" },
|
||||
expectedContext: { build: { enabled: true, args: [] } },
|
||||
},
|
||||
{
|
||||
name: "with additional build arguments specified",
|
||||
inputs: { "build-args": `--target foo\n--parallel 8 --foo "bar baz"` },
|
||||
expectedContext: {
|
||||
build: {
|
||||
enabled: false,
|
||||
args: ["--target", "foo", "--parallel", "8", "--foo", "bar baz"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with all specified",
|
||||
inputs: {
|
||||
"source-dir": "project",
|
||||
"build-dir": "output",
|
||||
generator: "Ninja",
|
||||
"c-compiler": "clang",
|
||||
"cxx-compiler": "clang++",
|
||||
"c-flags": "-Werror -Wall\n-Wextra",
|
||||
"cxx-flags": "-Werror -Wall\n-Wextra -Wpedantic",
|
||||
options: `BUILD_TESTING=ON BUILD_EXAMPLES=ON\nBUILD_DOCS=ON "FOO=BAR BAZ"`,
|
||||
args: `-Wdev -Wdeprecated\n--fresh --foo "bar baz"`,
|
||||
"run-build": "true",
|
||||
"build-args": `--target foo\n--parallel 8 --foo "bar baz"`,
|
||||
},
|
||||
expectedContext: {
|
||||
sourceDir: "project",
|
||||
buildDir: "output",
|
||||
configure: {
|
||||
generator: "Ninja",
|
||||
options: [
|
||||
"CMAKE_C_COMPILER=clang",
|
||||
"CMAKE_CXX_COMPILER=clang++",
|
||||
"CMAKE_C_FLAGS=-Werror -Wall -Wextra",
|
||||
"CMAKE_CXX_FLAGS=-Werror -Wall -Wextra -Wpedantic",
|
||||
"BUILD_TESTING=ON",
|
||||
"BUILD_EXAMPLES=ON",
|
||||
"BUILD_DOCS=ON",
|
||||
"FOO=BAR BAZ",
|
||||
],
|
||||
args: ["-Wdev", "-Wdeprecated", "--fresh", "--foo", "bar baz"],
|
||||
},
|
||||
build: {
|
||||
enabled: true,
|
||||
args: ["--target", "foo", "--parallel", "8", "--foo", "bar baz"],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
it(`should get the action context ${testCase.name}`, async () => {
|
||||
const { getInput } = await import("gha-utils");
|
||||
const { getContext } = await import("./context.js");
|
||||
|
||||
const inputs = testCase.inputs || {};
|
||||
vi.mocked(getInput).mockImplementation((name) => inputs[name] ?? "");
|
||||
|
||||
expect(getContext()).toStrictEqual({
|
||||
sourceDir: "",
|
||||
buildDir: "build",
|
||||
configure: {
|
||||
generator: "",
|
||||
options: [],
|
||||
args: [],
|
||||
},
|
||||
build: {
|
||||
enabled: false,
|
||||
args: [],
|
||||
},
|
||||
...testCase.expectedContext,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
import { getInput } from "gha-utils";
|
||||
import path from "node:path";
|
||||
import { parse } from "./utils.js";
|
||||
|
||||
export interface Context {
|
||||
sourceDir: string;
|
||||
buildDir: string;
|
||||
configure: {
|
||||
generator: string;
|
||||
options: string[];
|
||||
args: string[];
|
||||
};
|
||||
build: {
|
||||
enabled: boolean;
|
||||
args: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export function getContext(): Context {
|
||||
const sourceDir = getInput("source-dir");
|
||||
const options: string[] = [];
|
||||
|
||||
let input = getInput("c-compiler");
|
||||
if (input) options.push(`CMAKE_C_COMPILER=${input}`);
|
||||
|
||||
input = getInput("cxx-compiler");
|
||||
if (input) options.push(`CMAKE_CXX_COMPILER=${input}`);
|
||||
|
||||
input = getInput("c-flags");
|
||||
if (input) {
|
||||
const flags = input.replaceAll(/\s+/g, " ");
|
||||
options.push(`CMAKE_C_FLAGS=${flags}`);
|
||||
}
|
||||
|
||||
input = getInput("cxx-flags");
|
||||
if (input) {
|
||||
const flags = input.replaceAll(/\s+/g, " ");
|
||||
options.push(`CMAKE_CXX_FLAGS=${flags}`);
|
||||
}
|
||||
|
||||
input = getInput("options");
|
||||
if (input) {
|
||||
options.push(...parse(input).map((opt) => opt.toString()));
|
||||
}
|
||||
|
||||
return {
|
||||
sourceDir,
|
||||
buildDir: getInput("build-dir") || path.join(sourceDir, "build"),
|
||||
configure: {
|
||||
generator: getInput("generator"),
|
||||
options,
|
||||
args: parse(getInput("args")).map((arg) => arg.toString()),
|
||||
},
|
||||
build: {
|
||||
enabled: getInput("run-build") == "true",
|
||||
args: parse(getInput("build-args")).map((arg) => arg.toString()),
|
||||
},
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { logCommand } from "gha-utils";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { exec } from "./exec.js";
|
||||
|
||||
describe("execute commands", () => {
|
||||
vi.mock("gha-utils", () => ({
|
||||
logCommand: vi.fn<(command: string, ...args: string[]) => void>(),
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(logCommand).mockClear();
|
||||
});
|
||||
|
||||
it("should successfully execute a command", async () => {
|
||||
await exec("node", ["--version"]);
|
||||
|
||||
expect(logCommand).toHaveBeenCalledTimes(1);
|
||||
expect(logCommand).toHaveBeenCalledWith("node", "--version");
|
||||
});
|
||||
|
||||
it("should fail to execute a command", async () => {
|
||||
await expect(exec("node", ["--invalid"])).rejects.toThrow(
|
||||
"Command exited with status code 9",
|
||||
);
|
||||
|
||||
expect(logCommand).toHaveBeenCalledTimes(1);
|
||||
expect(logCommand).toHaveBeenCalledWith("node", "--invalid");
|
||||
});
|
||||
});
|
28
src/exec.ts
28
src/exec.ts
@ -1,28 +0,0 @@
|
||||
import { logCommand } from "gha-utils";
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
/**
|
||||
* Executes a command with the given arguments.
|
||||
*
|
||||
* The command is executed with `stdin` ignored and both `stdout` and `stderr` inherited by the parent process.
|
||||
*
|
||||
* @param command The command to execute.
|
||||
* @param args The arguments to pass to the command.
|
||||
* @returns A promise that resolves when the command exits successfully or rejects if it exits with a non-zero status code or encounters an error.
|
||||
*/
|
||||
export async function exec(command: string, args: string[]): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const proc = spawn(command, args, {
|
||||
stdio: ["ignore", "inherit", "inherit"],
|
||||
});
|
||||
logCommand(proc.spawnfile, ...proc.spawnargs.splice(1));
|
||||
proc.on("error", reject);
|
||||
proc.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Command exited with status code ${code}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
18
src/utils.ts
18
src/utils.ts
@ -1,18 +0,0 @@
|
||||
const regex = /"([^"]*)"|'([^']*)'|`([^`]*)`|(\S+)/g;
|
||||
|
||||
/**
|
||||
* Converts a space-separated string into a list of arguments.
|
||||
*
|
||||
* This function parses the provided string, which contains arguments separated by spaces and possibly enclosed in quotes, into a list of arguments.
|
||||
*
|
||||
* @param str - The space-separated string to parse.
|
||||
* @returns A list of arguments.
|
||||
*/
|
||||
export function parse(str: string): string[] {
|
||||
const args: string[] = [];
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = regex.exec(str)) !== null) {
|
||||
args.push(match[1] ?? match[2] ?? match[3] ?? match[4]);
|
||||
}
|
||||
return args;
|
||||
}
|
32
test/CMakeLists.txt
Normal file
32
test/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(test)
|
||||
|
||||
option(CHECK_USING_CLANG "check if target is compiled using Clang" OFF)
|
||||
option(CHECK_SURPASS_WARNING "check if target could surpass a compiler warning" OFF)
|
||||
|
||||
if(CHECK_SURPASS_WARNING)
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS "/WX /W4 ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "/WX /W4 ${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "-Werror -Wunused-variable ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-Werror -Wunused-variable ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_executable(hello_world hello_world.cpp)
|
||||
add_test(NAME hello_world COMMAND $<TARGET_FILE:hello_world>)
|
||||
|
||||
list(APPEND LANGS c cpp)
|
||||
foreach(LANG ${LANGS})
|
||||
configure_file(test.in ${CMAKE_CURRENT_BINARY_DIR}/test.${LANG})
|
||||
add_executable(test_${LANG} EXCLUDE_FROM_ALL ${CMAKE_CURRENT_BINARY_DIR}/test.${LANG})
|
||||
target_compile_definitions(
|
||||
test_${LANG} PRIVATE
|
||||
$<$<STREQUAL:"${LANG}","c">:IS_C>
|
||||
$<$<BOOL:${CHECK_USING_CLANG}>:CHECK_USING_CLANG>
|
||||
$<$<BOOL:${CHECK_SURPASS_WARNING}>:CHECK_SURPASS_WARNING>
|
||||
)
|
||||
add_test(NAME test_${LANG} COMMAND $<TARGET_FILE:test_${LANG}>)
|
||||
endforeach()
|
6
test/hello_world.cpp
Normal file
6
test/hello_world.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello world!" << std::endl;
|
||||
return 0;
|
||||
}
|
19
test/test.in
Normal file
19
test/test.in
Normal file
@ -0,0 +1,19 @@
|
||||
#ifdef IS_C
|
||||
#include <stdio.h>
|
||||
#define PRINT(STR) printf(STR); printf("\n")
|
||||
#else
|
||||
#include <iostream>
|
||||
#define PRINT(STR) std::cout << STR << std::endl
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#ifdef CHECK_SURPASS_WARNING
|
||||
int unused;
|
||||
#endif
|
||||
#if defined(CHECK_USING_CLANG) && !defined(__clang__)
|
||||
PRINT("compiler is not clang");
|
||||
return 1;
|
||||
#endif
|
||||
PRINT("all ok");
|
||||
return 0;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "@tsconfig/node23",
|
||||
"include": ["src"],
|
||||
"exclude": ["**/*.test.ts"],
|
||||
"compilerOptions": {
|
||||
"module": "node16"
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
watch: false,
|
||||
coverage: {
|
||||
all: false,
|
||||
enabled: true,
|
||||
reporter: ["text"],
|
||||
thresholds: { 100: true },
|
||||
},
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue
Block a user