Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Run NodeCG test in CI on Windows #445

Merged
merged 2 commits into from
Jan 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,63 @@ jobs:
# are mounted by NodeCG. It will fail if one of them is not mounted.
# You may check for other NodeCG runtime errors in the output (these
# may not fail the run).
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v2
with:
node-version: "16"

- name: Install nodecg-cli
run: npm install --global nodecg-cli
- name: Download NodeCG
uses: actions/checkout@v2
with:
repository: nodecg/nodecg

- name: Get NodeCG commit hash
id: nodecgHash
shell: bash
run: echo "::set-output name=nodecgHash::$(git rev-parse HEAD)"

- name: Cache NodeCG dependencies
id: cache-nodecg
uses: actions/cache@v2
with:
path: 'node_modules'
key: ${{ runner.os }}-${{ steps.nodecgHash.outputs.nodecgHash }}-nodecg

- name: Setup NodeCG
run: nodecg setup
- name: Install NodeCG dependencies
# Only get dependencies if we didn't get them from the cache
if: steps.cache-nodecg.outputs.cache-hit != 'true'
run: npm install --prod

- name: Setup NodeCG config
- name: Setup NodeCG config linux
if: matrix.os == 'ubuntu-latest'
run: |
mkdir cfg
echo '{"bundles": {"paths": ["'${GITHUB_WORKSPACE}'/nodecg-io","'${GITHUB_WORKSPACE}'/nodecg-io/services","'${GITHUB_WORKSPACE}'/nodecg-io/samples"]}}' > ./cfg/nodecg.json

# nodecg-io needs to be cloned after NodeCG setup because the nodecg-cli requires an empty directory.
- name: Setup NodeCG config windows
if: matrix.os == 'windows-latest'
shell: bash
run: |
mkdir cfg
# We need to escape backslashes to get valid json. Replaces each "\" with "\\"
echo '{"bundles": {"paths": ["'${GITHUB_WORKSPACE//\\/\\\\}'\\nodecg-io","'${GITHUB_WORKSPACE//\\/\\\\}'\\nodecg-io\\services","'${GITHUB_WORKSPACE//\\/\\\\}'\\nodecg-io\\samples"]}}' > ./cfg/nodecg.json

- uses: actions/checkout@v2
with:
path: "nodecg-io"

- name: Install system dependencies
if: matrix.os == 'ubuntu-latest'
run: sudo apt update && sudo apt-get -y install libusb-1.0-0-dev libasound2-dev libudev-dev

- name: Install node native development files
shell: bash
run: npx node-gyp install

- name: Install nodejs dependencies
run: npm ci
working-directory: ./nodecg-io
Expand All @@ -93,6 +125,7 @@ jobs:
working-directory: ./nodecg-io

- name: Run test
shell: bash
run: node .scripts/ci-nodecg-integration.mjs
working-directory: ./nodecg-io

Expand Down
67 changes: 42 additions & 25 deletions .scripts/ci-nodecg-integration.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (!nodecgiodir) {
* }
* ~~~
*/
const npm = JSON.parse(child_process.execSync("npm ls --json"));
const npm = JSON.parse(child_process.execSync("npm ls --json").toString());

// Filter out any dependencies which are not resolved locally in samples or services because the other npm packages will not be loaded by NodeCG
let bundles = Object.entries(npm.dependencies)
Expand All @@ -33,7 +33,8 @@ let bundles = Object.entries(npm.dependencies)
(j) =>
j[0] === "resolved" &&
(`${j[1]}`.startsWith("file:../samples/") ||
`${j[1]}`.startsWith("file:../services/" || `${j[1]}` === "file:../nodecg-io-core")),
`${j[1]}`.startsWith("file:../services/") ||
`${j[1]}` === "file:../nodecg-io-core"),
),
)
.map((v) => v[0]);
Expand All @@ -44,31 +45,47 @@ console.log("");
console.log("NodeCG sterr");
console.log("--------------------------------------------------------------------------------");

// expects a NodeCG folder be the parent of the cwd needs timeout
const log = child_process
.execSync("timeout --preserve-status 15s node " + cwd.dir + path.sep + "index.js", { cwd: cwd.dir })
.toString("utf8");
// Spawn a process that runs NodeCG
const child = child_process.spawn("node", ["index.js"], { cwd: cwd.dir });

const lines = log.split("\n");
// Store stdout in lines and stream stderr to stderr of this process
const lines = [];
child.stdout.on("data", (data) => lines.push(data.toString()));
child.stderr.on("data", (data) => console.error(data.toString()));

// Try to find each bundle in the logs.
const missing = bundles.filter(
/*Using endsWith here to remove possible ansi styling of "[info]" caused by ModeCG's logger when run locally*/
(i) => !lines.some((j) => j.endsWith("[nodecg/lib/server/extensions] Mounted " + i + " extension")),
);
// Let NodeCG run for 15 seconds to load all bundles
setTimeout(() => {
// We don't want to leave NodeCG running, if it was loaded successfully.
// If it has errored, it will not be running anymore.
if (child.pid) {
child.kill();
}

// Fail the run if there are missing bundles.
if (missing.length > 0) {
// Only log stout if the run has failed because otherwise its unimportant and everything important should be in stderr
console.log("");
console.log("NodeCG stout");
console.log("--------------------------------------------------------------------------------");
console.log(log);
// Check exit code for failure
const exitCode = child.exitCode;
if (exitCode !== null && exitCode !== 0) {
throw new Error(`NodeCG exited with code ${exitCode}`);
}

console.log("");
console.log("Missing Bundles");
console.log("--------------------------------------------------------------------------------");
console.log(missing);
// Try to find each bundle in the logs.
const missing = bundles.filter(
/*Using endsWith here to remove possible ansi styling of "[info]" caused by ModeCG's logger when run locally*/
(i) => !lines.some((j) => j.includes("[nodecg/lib/server/extensions] Mounted " + i + " extension")),
);

throw new Error(`NodeCG did not mount ${missing.length} bundle(s).`);
}
// Fail the run if there are missing bundles.
if (missing.length > 0) {
// Only log stout if the run has failed because otherwise its unimportant and everything important should be in stderr
console.log("");
console.log("NodeCG stout");
console.log("--------------------------------------------------------------------------------");
console.log(lines.join(""));

console.log("");
console.log("Missing Bundles");
console.log("--------------------------------------------------------------------------------");
console.log(missing);

throw new Error(`NodeCG did not mount ${missing.length} bundle(s).`);
}
}, 15000);