Skip to content

Commit 1ea5a0e

Browse files
authored
Merge pull request #257 from Dan-Nolan/task/ci_testing
Adds a CI Script for testing all content
2 parents 94325e5 + 0248969 commit 1ea5a0e

15 files changed

Lines changed: 376 additions & 6 deletions

ci/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.env
2+
!.gitignore

ci/config.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require("dotenv").config();
2+
3+
const EXECUTION_RESULTS = {
4+
NONE: 0,
5+
SUCCESS: 1,
6+
FAILED: 2
7+
}
8+
9+
const LANGUAGE_VERSIONS = {
10+
solidity: ['0.6.12', '0.7.5', '0.8.4'],
11+
javascript: ['10.x', '10.x/babel']
12+
}
13+
14+
const GRAPH_API = process.env.GRAPH_API || "http://localhost:3040/graphql";
15+
16+
const RUN_URL = process.env.RUN_URL || "https://relayer-staging.chainshot.com/run/";
17+
18+
module.exports = {
19+
LANGUAGE_VERSIONS,
20+
EXECUTION_RESULTS,
21+
GRAPH_API,
22+
RUN_URL,
23+
}

ci/execute/executeGroups.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const executeStages = require("./executeStages");
2+
const { EXECUTION_RESULTS } = require('../config');
3+
4+
function sendProcessMessage(msg) {
5+
// process.send not defined outside of child processes
6+
// this is used for the Builder CLI
7+
if(process.send) {
8+
process.send(msg);
9+
}
10+
}
11+
12+
function executeGroups(groups) {
13+
const stageContainers = groups.reduce((arr, group) => {
14+
const containers = group.stageContainers.map((x) => ({ ...x, stageContainerGroup: group }))
15+
return arr.concat(containers);
16+
}, []);
17+
18+
const promises = new Array(stageContainers.length).fill(0).map(async (_, j) => {
19+
const stageContainer = stageContainers[j];
20+
21+
const { version, stages, stageContainerGroup } = stageContainer;
22+
const { title } = stageContainerGroup;
23+
24+
console.log(`Running ${title} ${version}...`);
25+
const results = await executeStages(stages);
26+
const executedResults = results.filter(x => x !== EXECUTION_RESULTS.NONE);
27+
if(executedResults.length === 0) {
28+
return;
29+
}
30+
31+
console.log(`${title} ${version} results:`);
32+
executedResults.forEach((result, i) => {
33+
const stage = stageContainer.stages[i];
34+
if(result === EXECUTION_RESULTS.SUCCESS) {
35+
console.log(`✔️ ${stage.title} passed!`);
36+
sendProcessMessage({ type: "RESULT", data: {
37+
success: true,
38+
version: `${title} ${version}`,
39+
stage: stage.title
40+
}});
41+
}
42+
else {
43+
console.log(`✘ ${stage.title} failed!`);
44+
sendProcessMessage({ type: "RESULT", data: {
45+
success: false,
46+
version: `${title} ${version}`,
47+
stage: stage.title
48+
}});
49+
}
50+
});
51+
});
52+
53+
return Promise.all(promises);
54+
}
55+
56+
module.exports = executeGroups;

ci/execute/executeStage.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const axios = require('axios');
2+
const { RUN_URL } = require('../config');
3+
4+
async function executeStage(stage) {
5+
const files = stage.codeFiles
6+
.filter(x => x.executable)
7+
.map(({ id, initialCode, executablePath, hasProgress }) => {
8+
if(hasProgress) {
9+
const solution = stage.solutions.find(x => x.codeFileId === id);
10+
return { contents: solution.code, path: executablePath }
11+
}
12+
return { contents: initialCode, path: executablePath }
13+
});
14+
15+
const { id, languageVersion, language, testFramework, forkBlockNumber } = stage;
16+
17+
return axios.post(RUN_URL, {
18+
stageId: stage.id,
19+
files,
20+
languageVersion,
21+
language,
22+
testFramework,
23+
forkBlockNumber,
24+
noCache: true
25+
});
26+
}
27+
28+
module.exports = executeStage;

ci/execute/executeStages.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const { LANGUAGE_VERSIONS, EXECUTION_RESULTS } = require('../config');
2+
const executeStage = require("./executeStage");
3+
4+
async function timeout(seconds) {
5+
return new Promise((resolve) => {
6+
setTimeout(resolve, seconds);
7+
});
8+
}
9+
10+
async function executeStages(stages) {
11+
return Promise.all(stages.map(async (stage, i) => {
12+
const { language, languageVersion } = stage;
13+
14+
await timeout(i * 500);
15+
16+
if((LANGUAGE_VERSIONS[language] || []).indexOf(languageVersion) < 0) {
17+
return EXECUTION_RESULTS.NONE;
18+
}
19+
try {
20+
const { data: { result: { completed }} } = await executeStage(stage);
21+
return completed ? EXECUTION_RESULTS.SUCCESS : EXECUTION_RESULTS.FAILED;
22+
}
23+
catch(ex) {
24+
console.log(ex.message);
25+
return EXECUTION_RESULTS.FAILED;
26+
}
27+
}));
28+
}
29+
30+
module.exports = executeStages;

ci/package-lock.json

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ci/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "ci",
3+
"version": "1.0.0",
4+
"main": "executeStage.js",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1"
7+
},
8+
"keywords": [],
9+
"author": "",
10+
"license": "ISC",
11+
"dependencies": {
12+
"axios": "^0.21.1"
13+
},
14+
"devDependencies": {},
15+
"description": ""
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const axios = require('axios');
2+
const { GRAPH_API } = require('../config');
3+
const { stageContainerGroupIds } = require("./queries");
4+
5+
async function getStageContainerGroupIds() {
6+
const r1 = await axios.post(GRAPH_API, {
7+
query: stageContainerGroupIds,
8+
variables: { filter: '{ "productionReady": true }' }
9+
});
10+
const { data: { data: { stageContainerGroups: idObjects }}} = r1;
11+
12+
return idObjects.map(x => x.id);
13+
}
14+
15+
module.exports = getStageContainerGroupIds;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const axios = require('axios');
2+
const { GRAPH_API } = require('../config');
3+
const { stageContainerGroupsByIds } = require("./queries");
4+
5+
async function getStageContainerGroups(ids) {
6+
const variables = { containsId: ids };
7+
const r2 = await axios.post(GRAPH_API, { query: stageContainerGroupsByIds, variables });
8+
const { data: { data: { stageContainerGroups }}} = r2;
9+
return stageContainerGroups;
10+
}
11+
12+
module.exports = getStageContainerGroups;

ci/query/queries.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const stageContainerGroupIds = `
2+
query filterStageContainerGroups($filter: String) {
3+
stageContainerGroups(filter: $filter) {
4+
id
5+
}
6+
}`;
7+
8+
const stageContainerGroupsByIds = `
9+
query stageContainerGroupsByIds($containsId: [String]) {
10+
stageContainerGroups(containsId: $containsId) {
11+
id
12+
title
13+
stageContainers {
14+
version
15+
stages {
16+
id
17+
title
18+
languageVersion
19+
language
20+
testFramework
21+
forkBlockNumber
22+
solutions {
23+
codeFileId
24+
code
25+
}
26+
codeFiles {
27+
id
28+
name
29+
hasProgress
30+
executable
31+
executablePath
32+
readOnly
33+
testFixture
34+
initialCode
35+
}
36+
}
37+
}
38+
}
39+
}`;
40+
41+
module.exports = { stageContainerGroupIds, stageContainerGroupsByIds }

0 commit comments

Comments
 (0)