Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
70bb408
Tests workflow
k1o0 Apr 11, 2022
33edfe9
Set env
k1o0 Apr 11, 2022
7bda66e
Set dynamic env vars
k1o0 Aug 5, 2022
c4c872a
Fix typo
k1o0 Aug 5, 2022
41bfbb4
Move fetchCommit back to serve.js
k1o0 Aug 5, 2022
a9a8db0
Add more env variables
k1o0 Aug 6, 2022
e7180b6
Merge branch 'coveralls' into workflow
k1o0 Aug 6, 2022
2f569cd
-r dotenv/config
k1o0 Aug 6, 2022
2d5b9d7
debug
k1o0 Aug 6, 2022
35a1234
debug
k1o0 Aug 6, 2022
68733f8
set env vars in test block
k1o0 Aug 6, 2022
bda4647
call moch directly
k1o0 Aug 6, 2022
a3e37fd
call mocha with node
k1o0 Aug 6, 2022
5086fad
dotenv_config_path
k1o0 Aug 6, 2022
c891eec
Bump versions
k1o0 Aug 6, 2022
45c4266
Fix missing ref
k1o0 Aug 6, 2022
12f87ee
Ignore failing test
k1o0 Aug 6, 2022
d72271e
Merge branch 'coveralls' into workflow
k1o0 Aug 6, 2022
ff8058c
shields & changelog
k1o0 Aug 6, 2022
e5707ea
Delete keys with undefined values
k1o0 Aug 6, 2022
74c56ea
Workflow env var
k1o0 Aug 8, 2022
0025c4b
develop -> dev
k1o0 Aug 8, 2022
5f12011
Add branch name to data on status req
k1o0 Aug 10, 2022
0f2a163
Coveralls in workflow
k1o0 Aug 10, 2022
a388922
use npm script
k1o0 Aug 10, 2022
3e2724c
Report lcov
k1o0 Aug 10, 2022
e1c62f0
Print coverage summary to terminal
k1o0 Aug 10, 2022
9ee940e
Double kill jobs
k1o0 Aug 12, 2022
e0e9585
Verbose test
k1o0 Aug 12, 2022
2315a40
Fix test
k1o0 Aug 12, 2022
dea284a
Fix multiple calls to done
k1o0 Aug 12, 2022
9e5d801
do not try to kill the dead
k1o0 Aug 12, 2022
2f163d6
Restore await
k1o0 Aug 12, 2022
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
51 changes: 51 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: CI

on:
schedule:
- cron: '0 0 * * 0' # every Sunday at midnight
workflow_dispatch: # For manual triggering
push:
branches: [ master ]
pull_request:
branches: [ master, dev ]

env:
DOTENV_CONFIG_PATH: ./test/fixtures/.env.test

jobs:
build:
name: build ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # Whether to stop execution of other instances
max-parallel: 4
matrix:
os: ["ubuntu-latest", "windows-latest"] # , "macos-latest"
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
- name: Run tests
run: |
npm run coverage
npx nyc report --reporter=lcovonly --reporter text
- name: Coveralls Parallel
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
flag-name: ${{ matrix.os }}
parallel: true
finish:
needs: build
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
node_modules/*
.env
.pem
coverage/*
.nyc_output/*
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Changelog

## [Latest](https://github.com/cortex-lab/matlab-ci/commits/master) [3.1.0]
## [Latest](https://github.com/cortex-lab/matlab-ci/commits/master) [3.2.0]

## Modified

- if SIGTERM fails to end process(es) in under a minute, SIGKILL is sent

## Added

- git workflow
- set coveralls env vars

## [3.1.0]

## Modified

Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# LabCI
[![Build Status](https://travis-ci.com/cortex-lab/LabCI.svg?branch=master)](https://travis-ci.com/cortex-lab/matlab-ci)
[![Coverage](https://img.shields.io/badge/coverage-91.91-brightgreen)](https://img.shields.io/badge/coverage-72.35-yellowgreen)
![CI workflow](https://github.com/cortex-lab/LabCI/actions/workflows/tests.yml/badge.svg?branch=main)
[![Coverage](https://img.shields.io/badge/coverage-91.69-brightgreen)](https://img.shields.io/badge/coverage-72.35-yellowgreen)

A small set of modules written in Node.js for running automated tests of MATLAB and Python code in response to GitHub events. Also submits code coverage to the Coveralls API.

Expand Down Expand Up @@ -111,6 +111,10 @@ Your test script must do the following:
2. Save the results into the JSON cache file without duplication
3. For code coverage the script must either save the coverage directly, or export a Cobertura formatted XML file.

## Coveralls
Coverage information can be sent to coveralls.io using the [node-coveralls](https://github.com/nickmerwin/node-coveralls) package.
Adding `COVERALLS_REPO_TOKEN` to the .env file will cause the CI to set other dynamic env variables before running a pipeline.

## Built With

* [LocalTunnel](https://localtunnel.me) - A secure tunneling service
Expand Down
51 changes: 43 additions & 8 deletions lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,20 +324,48 @@ function getRepoPath(name) {
function startJobTimer(job, kill_children = false) {
const timeout = config.timeout || 8 * 60000; // How long to wait for the tests to run
return setTimeout(() => {
let log = _log.extend('job_timer');
console.log('Max test time exceeded');
log(kill_children ? 'Killing all processes' : 'Ending test process');
let pid = job._child.pid;
log('Killing process(es) for job #%g, pid = %d', job.id, pid);
job._child.kill();
if (kill_children) {
kill(pid);
}
if (kill_children) kill(pid);
// Give the processes 1 minute before sending a more aggressive signal
return setTimeout(() => {
if (job._child && job._child.exitCode == null) {
log('Failed to kill job process(es); sending SIGKILL (job #%g, pid = %d)', job.id, pid);
job._child.kill('SIGKILL');
if (kill_children) kill(pid, 'SIGKILL');
}
}, 60000)
}, timeout);
}


/**
* Set dynamic env variables for node-coveralls.
* NB: This does not support submodules.
* @param {Object} job - The Job with an associated process in the data field.
*/
function initCoveralls(job) {
const debug = log.extend('pipeline');
debug('Setting COVERALLS env variables');
process.env.COVERALLS_SERVICE_JOB_ID = job.id;
const envMap = {
'COVERALLS_SERVICE_NAME': job.data.context,
'COVERALLS_GIT_COMMIT': job.data.sha,
'COVERALLS_GIT_BRANCH': job.data.branch,
'CI_PULL_REQUEST': job.data.pull_number
};
for (let key in envMap) { // assign value or delete key
if (envMap[key]) { process.env[key] = envMap[key]; } else { delete process.env[key]; }
}
}

/**
* Build task pipeline. Takes a list of scripts/functions and builds a promise chain.
* @param {Object} job - The path of the repository
* @param {Object} job - The Job with an associated process in the data field.
* @returns {Promise} - The job routine
*/
async function buildRoutine(job) {
Expand Down Expand Up @@ -365,6 +393,9 @@ async function buildRoutine(job) {
});
const ops = config.shell ? {'shell': config.shell} : {};

// If environment variable COVERALLS_REPO_TOKEN is not null, set dynamic variables
if (process.env.COVERALLS_REPO_TOKEN) initCoveralls(job);

const init = () => debug('Executing pipeline for job #%g', job.id);
const routine = tasks.reduce(applyTask, Promise.resolve().then(init));
return routine
Expand Down Expand Up @@ -411,6 +442,8 @@ async function buildRoutine(job) {
clearTimeout(timer);
})
.on('close', (code, signal) => {
// FIXME Sometime close is not called after a timeout, maybe because
// the IO streams are kept open by some process?
const callback = (code === 0) ? resolve : reject;
const proc = {
code: code,
Expand All @@ -419,6 +452,8 @@ async function buildRoutine(job) {
stderr: stderr,
process: child
};
// Ensure there's an exitCode as the second kill timer checks for this
if (child.exitCode === null) child.exitCode = -1;
callback(proc);
});
job.child = child; // Assign the child process to the job
Expand Down Expand Up @@ -447,7 +482,7 @@ async function buildRoutine(job) {
message = `${errored.code} - Failed to spawn ${file}`;
}
// Check if the process was killed (we'll assume by the test timeout callback)
} else if (errored.process.killed || errored.signal === 'SIGTERM') {
} else if (errored.process.killed || ['SIGTERM', 'SIGKILL'].includes(errored.signal)) {
message = `Tests stalled after ~${(config.timeout / 60000).toFixed(0)} min`;
} else { // Error raised by process; dig through stdout for reason
debug('error from test function %s', file);
Expand Down Expand Up @@ -511,10 +546,10 @@ async function buildRoutine(job) {
*/
function computeCoverage(job) {
if (typeof job.data.coverage !== 'undefined' && job.data.coverage) {
console.log('Coverage already computed for job #' + job.id);
console.log('Coverage already computed for job #%g', job.id);
return;
}
console.log('Updating coverage for job #' + job.id);
console.log('Updating coverage for job #%g', job.id);
const xmlPath = path.join(config.dataPath, 'reports', job.data.sha, 'CoverageResults.xml');
const modules = listSubmodules(process.env.REPO_PATH);
return Coverage(xmlPath, job.data.repo, job.data.sha, modules).then(obj => {
Expand Down Expand Up @@ -719,5 +754,5 @@ module.exports = {
ensureArray, loadTestRecords, compareCoverage, computeCoverage, getBadgeData, log, shortID,
openTunnel, APIError, queue, partial, startJobTimer, updateJobFromRecord, shortCircuit, isSHA,
fullpath, strToBool, saveTestRecords, listSubmodules, getRepoPath, addParam, context2routine,
buildRoutine
buildRoutine, initCoveralls
};
Loading