From 93ef4eb084e108e67f1612e1b7cbd7778b422586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20R=C3=B6mer?= Date: Wed, 1 Feb 2023 10:34:25 +0100 Subject: [PATCH 1/3] Add model validation workflow These changes add a new workflow that validates new and updated models and adds a comment for each new or updated model of a pull request --- .github/actions/model-validation/action.yml | 24 + .github/actions/model-validation/index.js | 128 ++++++ .../model-validation/package-lock.json | 431 ++++++++++++++++++ .github/actions/model-validation/package.json | 16 + .github/workflows/governance.yml | 36 +- .github/workflows/upload.yml | 52 ++- 6 files changed, 685 insertions(+), 2 deletions(-) create mode 100644 .github/actions/model-validation/action.yml create mode 100644 .github/actions/model-validation/index.js create mode 100644 .github/actions/model-validation/package-lock.json create mode 100644 .github/actions/model-validation/package.json diff --git a/.github/actions/model-validation/action.yml b/.github/actions/model-validation/action.yml new file mode 100644 index 00000000..c7caa158 --- /dev/null +++ b/.github/actions/model-validation/action.yml @@ -0,0 +1,24 @@ +name: Validate Semantic Models +description: Validates TTL files with the SDS SDK +inputs: + added: + description: 'The changed files, detected by a previous action' + default: "[]" + required: false + modified: + description: 'The modified files, detected by a previous action' + default: "[]" + required: false + bamm_version: + description: The version of the used BAMM SDK + default: 2.1.1 + required: true + token: + description: GitHub token + required: true + pr_number: + description: Number of the pull request that triggered the action + required: true +runs: + using: node16 + main: index.js \ No newline at end of file diff --git a/.github/actions/model-validation/index.js b/.github/actions/model-validation/index.js new file mode 100644 index 00000000..92c73e5b --- /dev/null +++ b/.github/actions/model-validation/index.js @@ -0,0 +1,128 @@ +const core = require('@actions/core'); +const github = require('@actions/github'); +const https = require('https'); +const fs = require('fs'); +const path = require('path') +const { exec } = require("child_process"); + + +try { + var added = JSON.parse(core.getInput('added')) + var modified = JSON.parse(core.getInput('modified')) + var bammVersion = core.getInput('bamm_version') + var prNumber = core.getInput('pr_number') + + var bammSdkPath = `${__dirname}/bamm-cli-${bammVersion}.jar`; + var validationOutput = [] + + main() +} catch (error) { + core.setFailed(error.message) +} + +async function main() { + await asyncBammSdkDownload(`https://github.com/eclipse-esmf/esmf-sdk/releases/download/v${bammVersion}/bamm-cli-${bammVersion}.jar`) + + await validateAllInputs() + + console.log(validationOutput) + + var output = await produceValidationMarkdown() + + writeOutputToFilesystem({ + comments: output, + prNumber: prNumber + }) +} + +function writeOutputToFilesystem(output) { + const archiveDir = "output" + if (!fs.existsSync(archiveDir)){ + fs.mkdirSync(archiveDir); + } + + fs.writeFileSync(`${archiveDir}/validation-output.json`, JSON.stringify(output)) +} + +function produceValidationMarkdown() { + return Promise.all(validationOutput.map(async (model) => { + var lines = model.response.split('\n') + + var firstLine = lines[0] + + lines.splice(0,2) + lines.splice(-3) + + var remainingLines = lines.join('\n') + + var body = `### Validation Report for ${model.file} + +#### ${firstLine}` + + if(remainingLines !== '') { + body = body + `\n\`\`\`ttl\n${remainingLines}\n\`\`\`` + } + + return body + })) +} + +async function validateAllInputs() { + return Promise.all( + added.concat(modified).map((file) => { + return validateModel(file) + .then(result => { + validationOutput.push({ + file: file, + response: result + }) + }) + }) + ) +} + +async function validateModel(file) { + return new Promise((resolve, reject) => { + if (path.extname(file) === ".ttl") { + console.log(`Validating TTL file ${path.basename(file)}`) + + exec(`java -jar ${bammSdkPath} aspect ${file} validate`, (error, stdout, stderr) => { + if (stderr) { + reject(stderr) + } + + resolve(stdout) + }) + } + }) + +} + +async function asyncBammSdkDownload(url) { + return new Promise((resolve, reject) => { + downloadBammSdk(url, resolve, reject) + }) +} + +async function downloadBammSdk(url, resolve, reject) { + https.get(url, (response) => { + if (response.statusCode >= 400) { + reject("Could not download BAMM SDK v${bammVersion}") + } + + if (response.statusCode > 300 && response.statusCode < 400 && !!response.headers.location) { + downloadBammSdk(response.headers.location, resolve, reject) + } else { + console.log(`Starting download of BAMM SDK v${bammVersion}`) + + const filePath = fs.createWriteStream(bammSdkPath); + + response.pipe(filePath) + filePath.on('finish', () => { + filePath.close() + console.log(`Downloaded BAMM SDK v${bammVersion}`) + resolve(`Downloaded BAMM SDK v${bammVersion}`) + }) + } + }) +} \ No newline at end of file diff --git a/.github/actions/model-validation/package-lock.json b/.github/actions/model-validation/package-lock.json new file mode 100644 index 00000000..56cc3596 --- /dev/null +++ b/.github/actions/model-validation/package-lock.json @@ -0,0 +1,431 @@ +{ + "name": "model-validation", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "model-validation", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/github": "^5.1.1" + } + }, + "node_modules/@actions/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", + "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "dependencies": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/github": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", + "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", + "dependencies": { + "@actions/http-client": "^2.0.1", + "@octokit/core": "^3.6.0", + "@octokit/plugin-paginate-rest": "^2.17.0", + "@octokit/plugin-rest-endpoint-methods": "^5.13.0" + } + }, + "node_modules/@actions/http-client": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", + "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "dependencies": { + "tunnel": "^0.0.6" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", + "dependencies": { + "@octokit/types": "^6.40.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", + "dependencies": { + "@octokit/types": "^6.39.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/types": { + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "dependencies": { + "@octokit/openapi-types": "^12.11.0" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", + "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + } + }, + "dependencies": { + "@actions/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", + "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "requires": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "@actions/github": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", + "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", + "requires": { + "@actions/http-client": "^2.0.1", + "@octokit/core": "^3.6.0", + "@octokit/plugin-paginate-rest": "^2.17.0", + "@octokit/plugin-rest-endpoint-methods": "^5.13.0" + } + }, + "@actions/http-client": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", + "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "requires": { + "tunnel": "^0.0.6" + } + }, + "@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "requires": { + "@octokit/types": "^6.0.3" + } + }, + "@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "requires": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "requires": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "requires": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" + }, + "@octokit/plugin-paginate-rest": { + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", + "requires": { + "@octokit/types": "^6.40.0" + } + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", + "requires": { + "@octokit/types": "^6.39.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "requires": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/types": { + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "requires": { + "@octokit/openapi-types": "^12.11.0" + } + }, + "before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "node-fetch": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", + "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + } + } +} diff --git a/.github/actions/model-validation/package.json b/.github/actions/model-validation/package.json new file mode 100644 index 00000000..e7ef4557 --- /dev/null +++ b/.github/actions/model-validation/package.json @@ -0,0 +1,16 @@ +{ + "name": "model-validation", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/github": "^5.1.1" + } +} diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index 56f6cb9a..057637de 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -26,6 +26,10 @@ jobs: synchronize-models: name: 00 Determine Target Environment runs-on: ubuntu-latest + outputs: + ADDED: ${{ steps.changes.outputs.added }} + MODIFIED: ${{ steps.changes.outputs.modified }} + REMOVED: ${{ steps.changes.outputs.removed }} steps: - name: Checkout @@ -60,4 +64,34 @@ jobs: uses: actions/upload-artifact@v3 with: name: output - path: toArchive \ No newline at end of file + path: toArchive + validate-model-proposal: + runs-on: ubuntu-latest + if: github.event.pull_request + name: 01 Validate new semantic model + needs: synchronize-models + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + - name: Install Node dependencies + working-directory: ./.github/actions/model-validation + run: npm install + - name: Validate semantic models + id: model_validation + uses: ./.github/actions/model-validation + with: + pr_number: ${{ github.event.number }} + bamm_version: 2.1.1 + added: ${{needs.synchronize-models.outputs.ADDED}} + modified: ${{needs.synchronize-models.outputs.MODIFIED}} + - name: Archive + uses: actions/upload-artifact@v3 + with: + name: validation-output + path: output \ No newline at end of file diff --git a/.github/workflows/upload.yml b/.github/workflows/upload.yml index eeae6929..63b6ad6f 100644 --- a/.github/workflows/upload.yml +++ b/.github/workflows/upload.yml @@ -80,4 +80,54 @@ jobs: uses: ./.github/actions/upload with: SEMANTIC_HUB_URL: ${{ secrets[format('SEMANTIC_HUB_{0}_BASE', env.WORKSPACE_UPPERCASE)] }} - TOKEN: ${{ env.ACCESS_TOKEN }} \ No newline at end of file + TOKEN: ${{ env.ACCESS_TOKEN }} + add-comments: + name: 01 Add comments + runs-on: ubuntu-latest + permissions: + contents: read + actions: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Download artifact + uses: actions/github-script@v6.3.3 + with: + script: | + var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{github.event.workflow_run.id }}, + }); + var matchArtifact = artifacts.data.artifacts.filter((artifact) => { + return artifact.name == "validation-output" + })[0]; + var download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + var fs = require('fs'); + fs.writeFileSync('${{github.workspace}}/validation-output.zip', Buffer.from(download.data)); + - name: Unzip + run: | + unzip validation-output.zip + cat validation-output.json + - name: Upload comments + uses: actions/github-script@v6.3.3 + with: + script: | + var fs = require('fs'); + var rawOutputValidationFile = fs.readFileSync('validation-output.json'); + var validationOutput = JSON.parse(rawOutputValidationFile); + + validationOutput.comments.forEach((comment) => { + github.rest.issues.createComment({ + issue_number: validationOutput.prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }) + }) \ No newline at end of file From 5efb4e69bae20c0ea0aec9b0df47cc504fc62cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20R=C3=B6mer?= Date: Thu, 2 Feb 2023 12:05:40 +0100 Subject: [PATCH 2/3] Remove ref configuration from model validation checkout step --- .github/workflows/governance.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index 057637de..44cd578e 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -73,8 +73,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - uses: actions/setup-java@v3 with: distribution: 'temurin' From 9185dbc5f2e03e453fa6dcec29b507644af7754d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20R=C3=B6mer?= Date: Thu, 2 Feb 2023 18:07:03 +0100 Subject: [PATCH 3/3] Add bulk model validation These changes add another GitHub Actions workflow that allow the user to validate all models in one repository at once. --- .github/actions/model-validation/action.yml | 4 + .github/actions/model-validation/index.js | 98 +++++++++++++++------ .github/workflows/bulk-validation.yml | 37 ++++++++ 3 files changed, 113 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/bulk-validation.yml diff --git a/.github/actions/model-validation/action.yml b/.github/actions/model-validation/action.yml index c7caa158..8804bd8b 100644 --- a/.github/actions/model-validation/action.yml +++ b/.github/actions/model-validation/action.yml @@ -19,6 +19,10 @@ inputs: pr_number: description: Number of the pull request that triggered the action required: true + bulk: + description: Flag that defines whether all files on a branch should be validated + required: false + default: "false" runs: using: node16 main: index.js \ No newline at end of file diff --git a/.github/actions/model-validation/index.js b/.github/actions/model-validation/index.js index 92c73e5b..9040a940 100644 --- a/.github/actions/model-validation/index.js +++ b/.github/actions/model-validation/index.js @@ -4,47 +4,93 @@ const https = require('https'); const fs = require('fs'); const path = require('path') const { exec } = require("child_process"); +const { TIMEOUT } = require('dns'); -try { - var added = JSON.parse(core.getInput('added')) - var modified = JSON.parse(core.getInput('modified')) - var bammVersion = core.getInput('bamm_version') - var prNumber = core.getInput('pr_number') +var bulk = JSON.parse(core.getInput('bulk')) +var bammVersion = core.getInput('bamm_version') +var bammSdkPath = `${__dirname}/bamm-cli-${bammVersion}.jar`; - var bammSdkPath = `${__dirname}/bamm-cli-${bammVersion}.jar`; - var validationOutput = [] +var added = JSON.parse(core.getInput('added')) +var modified = JSON.parse(core.getInput('modified')) +var prNumber = core.getInput('pr_number') - main() -} catch (error) { - core.setFailed(error.message) -} +main() async function main() { - await asyncBammSdkDownload(`https://github.com/eclipse-esmf/esmf-sdk/releases/download/v${bammVersion}/bamm-cli-${bammVersion}.jar`) + try { + await asyncBammSdkDownload(`https://github.com/eclipse-esmf/esmf-sdk/releases/download/v${bammVersion}/bamm-cli-${bammVersion}.jar`) + + if(bulk === false){ + validateChanges(added, modified, prNumber) + } else { + validateAllModels() + } + } catch (error) { + core.setFailed(error.message) + } +} + +async function validateAllModels() { + var validationResultPromises = [] + + gatherValidationResults('./', '.ttl', validationResultPromises) + + var validationResults = await Promise.all(validationResultPromises) + + var formattedOutput = await produceValidationMarkdown(validationResults) + + var fullReport = `# Validation report for all models + + ` + + formattedOutput.forEach((report) => { + fullReport += '\n\n' + report + '\n' + }) + + writeOutputToFilesystem(fullReport, 'full-validation-report.md') +} + +async function gatherValidationResults(startPath, fileEnding, returnValue) { + var allFiles = fs.readdirSync(startPath) + + for (file of allFiles) { + var fileName = path.join(startPath, file) + + if(fs.lstatSync(fileName).isDirectory()) { + gatherValidationResults(fileName, fileEnding, returnValue) + } else if(fileName.endsWith(fileEnding)) { + returnValue.push(validateModel(fileName)) + } + } +} - await validateAllInputs() + +async function validateChanges(added, modified, prNumber) { + var validationOutput = [] + + await validateAllInputs(added, modified, validationOutput) console.log(validationOutput) - var output = await produceValidationMarkdown() + var output = await produceValidationMarkdown(validationOutput) - writeOutputToFilesystem({ + writeOutputToFilesystem(JSON.stringify({ comments: output, prNumber: prNumber - }) + }), 'validation-output.json') } -function writeOutputToFilesystem(output) { +function writeOutputToFilesystem(output, filename) { const archiveDir = "output" if (!fs.existsSync(archiveDir)){ fs.mkdirSync(archiveDir); } - fs.writeFileSync(`${archiveDir}/validation-output.json`, JSON.stringify(output)) + fs.writeFileSync(`${archiveDir}/${filename}`, output) } -function produceValidationMarkdown() { +function produceValidationMarkdown(validationOutput) { return Promise.all(validationOutput.map(async (model) => { var lines = model.response.split('\n') @@ -67,15 +113,12 @@ function produceValidationMarkdown() { })) } -async function validateAllInputs() { +async function validateAllInputs(added, modified, validationOutput) { return Promise.all( added.concat(modified).map((file) => { return validateModel(file) .then(result => { - validationOutput.push({ - file: file, - response: result - }) + validationOutput.push(result) }) }) ) @@ -84,14 +127,17 @@ async function validateAllInputs() { async function validateModel(file) { return new Promise((resolve, reject) => { if (path.extname(file) === ".ttl") { - console.log(`Validating TTL file ${path.basename(file)}`) + console.log(`Validating TTL file ${file}`) exec(`java -jar ${bammSdkPath} aspect ${file} validate`, (error, stdout, stderr) => { if (stderr) { reject(stderr) } - resolve(stdout) + resolve({ + file: file, + response: stdout + }) }) } }) diff --git a/.github/workflows/bulk-validation.yml b/.github/workflows/bulk-validation.yml new file mode 100644 index 00000000..0a8e9f3f --- /dev/null +++ b/.github/workflows/bulk-validation.yml @@ -0,0 +1,37 @@ +# +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# See the LICENSE file(s) distributed with this work for +# additional information regarding license terms. +# + +name: Bulk Validation +on: + workflow_dispatch: + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + - name: Install Node dependencies + working-directory: ./.github/actions/model-validation + run: npm install + - name: validate models + uses: ./.github/actions/model-validation + with: + bamm_version: 2.1.1 + bulk: true + - name: Archive + uses: actions/upload-artifact@v3 + with: + name: full-validation-report + path: output \ No newline at end of file