Merge pull request #350 from aminya/install-tool [skip ci]

feat: install setup-cpp CLI in GitHub Actions
This commit is contained in:
Amin Ya 2025-03-01 03:07:49 -08:00 committed by GitHub
commit fd2c1df30d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 107 additions and 37 deletions

View File

@ -200,6 +200,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
- name: Smoke Test Modern Bundle
if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
run: |
@ -208,6 +209,11 @@ jobs:
env:
RUNNER_OS_NAME: ${{ matrix.os }}
- name: Smoke Test Global Install
if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
run: |
setup-cpp --help
- name: Setup Node 12
if: ${{ !contains(matrix.os, 'macos-14') && !contains(matrix.os, 'macos-15') }}
uses: actions/setup-node@v4

View File

@ -31,7 +31,7 @@ Setting up a **cross-platform** environment for building and testing C++/C proje
| --------------- | ----------------------------------------------------------------------------------------------------------- |
| compiler | llvm, gcc, msvc, apple-clang, vcvarsall |
| build system | cmake, ninja, meson, make, task, bazel |
| package manager | vcpkg, conan, choco, brew, nala |
| package manager | vcpkg, conan, choco, brew, nala, setup-cpp |
| analyzer/linter | clang-tidy, clang-format, cppcheck, cpplint, flawfinder, lizard, infer, cmakelang, cmake-format, cmake-lint |
| cache | ccache, sccache |
| documentation | doxygen, graphviz |
@ -195,6 +195,19 @@ jobs:
cppcheck: true # instead of `true`, which chooses the default version, you can pass a specific version.
```
When using the `setup-cpp` action in GitHub Actions, by default it will also install the `setup-cpp` CLI, which you can use in the subsequent commands. You can modify the default behaviour if needed.
```yaml
- name: Setup Cpp
uses: aminya/setup-cpp@v1
with:
setup-cpp: true
node-package-manager: "npm"
- name: Use Setup Cpp CLI
run: setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
```
### Prebuilt Docker Images
To provide fast development environments, `setup-cpp` provides several prebuilt docker images that have the tools you need. You can use these images as a base image for your project.

View File

@ -157,6 +157,12 @@ inputs:
python:
description: "Wether to install python (true/false) or the specific version to install."
required: false
setup-cpp:
description: "Wether to install setup-cpp (true/false) or the specific version to install. (Default to the current version called by the action)"
required: false
node-package-manager:
description: "The node package manager to use (npm/yarn/pnpm) when installing setup-cpp globally"
required: false
runs:
using: "node20"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,11 +6,12 @@ import { type Inputs, inputs } from "./tool.js"
import type { InstallationInfo } from "./utils/setup/setupBin.js"
export function parseArgs(args: string[]): Opts {
return mri<Record<Inputs, string | undefined> & { help: boolean }>(args, {
string: [...inputs, "timeout"],
default: Object.fromEntries(inputs.map((inp) => [inp, maybeGetInput(inp)])),
alias: { h: "help" },
boolean: "help",
const defaults = Object.fromEntries(inputs.map((inp) => [inp, maybeGetInput(inp)]))
return mri<Record<Inputs, string | undefined> & { help: boolean; version: boolean; "setup-cpp": boolean }>(args, {
string: [...inputs, "timeout", "node-package-manager"],
default: defaults,
alias: { h: "help", v: "version" },
boolean: ["help", "version", "setup-cpp"],
})
}
@ -25,7 +26,10 @@ Install all the tools required for building and testing C++/C projects.
--timeout\t the timeout for the installation of each tool in minutes. By default it is 10 minutes.
--compiler\t the <compiler> to install.
\t You can specify the version instead of specifying just the name e.g: --compiler 'llvm-13.0.0'
--$tool_name\t pass "true" or pass the <version> you would like to install for this tool. e.g. --conan true or --conan "1.42.1"
--tool_name\t pass "true" or pass the <version> you would like to install for this tool. e.g. --conan true or --conan "1.42.1"
--nodePackageManager\t the node package manager to use (npm/yarn/pnpm) when installing setup-cpp globally
--help\t show this help message
--version\t show the version of setup-cpp
All the available tools:
`)
@ -38,7 +42,7 @@ All the available tools:
"build system": {
tools: "--cmake, --ninja, --meson, --make, --task, --bazel",
},
"package manager": { tools: "--vcpkg, --conan, --choco, --brew, --nala" },
"package manager": { tools: "--vcpkg, --conan, --choco, --brew, --nala, --setup-cpp" },
"analyzer/linter": {
tools:
"--clang-tidy, --clang-format, --cppcheck, --cpplint, --flawfinder, --lizard, --infer, , --cmakelang, --cmake-lint, --cmake-format",
@ -63,7 +67,10 @@ export function maybeGetInput(key: string) {
export type Opts = mri.Argv<
Record<Inputs, string | undefined> & {
help: boolean
version: boolean
"setup-cpp"?: boolean
timeout?: string
"node-package-manager"?: string
}
>

View File

@ -0,0 +1,27 @@
import { error, info } from "ci-log"
import { execa } from "execa"
import which from "which"
/**
* Install the setup-cpp CLI globally
* @param version - The version of setup-cpp to install
* @param packageManager - The package manager to use
*/
export async function installSetupCpp(version: string, packageManager: string = "npm") {
try {
// check if `setup-cpp` is available in the shell, if so, skip the installation to avoid overwriting the existing version
const setupCppPath = await which("setup-cpp", { nothrow: true })
if (setupCppPath !== null) {
return
}
// Install setup-cpp globally
info(`Installing setup-cpp@${version} via ${packageManager}...`)
await execa(packageManager, ["install", "-g", `setup-cpp@${version}`], {
stdio: "inherit",
// 1 minutes timeout
timeout: 1000 * 60 * 1,
})
} catch (err) {
error(`Failed to install the setup-cpp@${version} CLI: ${err}. Ignoring...`)
}
}

View File

@ -9,10 +9,12 @@ import numerousLocale from "numerous/locales/en.js"
import timeDelta from "time-delta"
import timeDeltaLocale from "time-delta/locales/en.js"
import { untildifyUser } from "untildify-user"
import packageJson from "../package-version.json"
import { checkUpdates } from "./check-updates.js"
import { parseArgs, printHelp, rcOptions } from "./cli-options.js"
import { getCompilerInfo, installCompiler } from "./compilers.js"
import { installTool } from "./installTool.js"
import { installSetupCpp } from "./setup-cpp-installer.js"
import { type Inputs, llvmTools, tools } from "./tool.js"
import { isArch } from "./utils/env/isArch.js"
import { ubuntuVersion } from "./utils/env/ubuntu_version.js"
@ -21,11 +23,7 @@ import { syncVersions } from "./versions/versions.js"
/** The main entry function */
async function main(args: string[]): Promise<number> {
let checkUpdatePromise = Promise.resolve()
if (!GITHUB_ACTIONS) {
checkUpdatePromise = checkUpdates()
process.env.ACTIONS_ALLOW_UNSECURE_COMMANDS = "true"
}
const checkUpdatePromise = GITHUB_ACTIONS ? Promise.resolve() : checkUpdates()
// parse options using mri or github actions
const opts = parseArgs(args)
@ -35,6 +33,11 @@ async function main(args: string[]): Promise<number> {
printHelp()
}
// print version
if (opts.version) {
info(`${packageJson.version}`)
}
// cpu architecture
const arch = opts.architecture ?? process.arch
@ -122,11 +125,20 @@ async function main(args: string[]): Promise<number> {
await finalizeRC(rcOptions)
if (successMessages.length === 0 && errorMessages.length === 0) {
warning("setup-cpp was called without any arguments. Nothing to do.")
return 0
const noTool = successMessages.length === 0 && errorMessages.length === 0
// if setup-cpp option is not passed, install setup-cpp by default unless only help or version is passed
// So that --help and --version are immutable
if (opts["setup-cpp"] === undefined) {
opts["setup-cpp"] = !(noTool && (opts.version || opts.help))
}
const installSetupCppPromise = opts["setup-cpp"]
? installSetupCpp(packageJson.version, opts["node-package-manager"])
: Promise.resolve()
await Promise.all([checkUpdatePromise, installSetupCppPromise])
// report the messages in the end
for (const tool of successMessages) {
success(tool)
@ -135,27 +147,26 @@ async function main(args: string[]): Promise<number> {
error(tool)
}
info("setup-cpp finished")
if (successMessages.length !== 0 || errorMessages.length !== 0) {
info("setup-cpp finished")
if (!GITHUB_ACTIONS) {
switch (process.platform) {
case "win32": {
warning("Run `RefreshEnv.cmd` or restart your shell to update the environment.")
break
}
case "linux":
case "darwin": {
warning("Run `source ~/.cpprc` or restart your shell to update the environment.")
break
}
default: {
// nothing
if (!GITHUB_ACTIONS) {
switch (process.platform) {
case "win32": {
warning("Run `RefreshEnv.cmd` or restart your shell to update the environment.")
break
}
case "linux":
case "darwin": {
warning("Run `source ~/.cpprc` or restart your shell to update the environment.")
break
}
default: {
// nothing
}
}
}
}
await checkUpdatePromise
return errorMessages.length === 0 ? 0 : 1 // exit with non-zero if any error message
}