diff --git a/.github/workflows/validate_json.yml b/.github/workflows/validate_apps.yml similarity index 85% rename from .github/workflows/validate_json.yml rename to .github/workflows/validate_apps.yml index 0502b6e..b58bb0b 100644 --- a/.github/workflows/validate_json.yml +++ b/.github/workflows/validate_apps.yml @@ -16,6 +16,6 @@ jobs: - uses: actions/setup-node@v1 with: node-version: 14 - - run: npm ci && npm run validate_json && npm run formatter + - run: npm ci && npm run validate_apps && npm run formatter env: GITHUB_PERSONAL_TOKEN: ${{secrets.GITHUB_PERSONAL_TOKEN}} diff --git a/package.json b/package.json index cb7fe85..bc45323 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "formatter": "prettier --check './public/**/*.(json|yml)'", "formatter-write": "prettier --write './public/**/*.(json|yml)'", "build": "rm -rf ./dist/ && mkdir -p dist && node ./scripts/build_one_click_apps.js && node ./scripts/build_one_click_apps_from_v4.js", - "validate_json": "node ./scripts/validate_json.js", + "validate_apps": "node ./scripts/validate_apps.js", "publish": "npm run build && ./scripts/publish-from-actions.sh" }, "repository": { diff --git a/scripts/validate_apps.js b/scripts/validate_apps.js new file mode 100644 index 0000000..5923fac --- /dev/null +++ b/scripts/validate_apps.js @@ -0,0 +1,138 @@ + /*jshint esversion: 6 */ + const path = require('path'); + const yaml = require('yaml'); + const fs = require('fs-extra'); + + const PUBLIC = `public`; + const pathOfPublic = path.join(__dirname, '..', PUBLIC); + + + // validating version 4 + function validateV4() { + + const version = '4'; + const pathOfVersion = path.join(pathOfPublic, 'v' + version); + const pathOfApps = path.join(pathOfVersion, 'apps'); + + return fs.readdir(pathOfApps) + .then(function (items) { + + const apps = items.filter(v => v.includes('.yml')); + + if (items.length !== apps.length) { + throw new Error('All files in v4 must end with .yml'); + } + + for (var i = 0; i < apps.length; i++) { + const contentString = fs.readFileSync(path.join(pathOfApps, apps[i]), 'utf-8'); + const content = yaml.parse(contentString); + const captainVersion = (content.captainVersion + ''); + const versionString = (version + ''); + if (versionString !== captainVersion) + throw new Error(`unmatched versions ${versionString} ${captainVersion} for ${apps[i]}`); + + apps[i] = apps[i].replace('.yml', ''); + + if (!content.caproverOneClickApp) { + throw new Error(`Cannot find caproverOneClickApp for ${apps[i]}`); + } + + if (!content.caproverOneClickApp.description) { + throw new Error(`Cannot find description for ${apps[i]}`); + } + + if (!content.caproverOneClickApp.instructions || + !content.caproverOneClickApp.instructions.start || + !content.caproverOneClickApp.instructions.end) { + throw new Error(`Cannot find instructions.start or instructions.end for ${apps[i]}`); + } + + if (!content.services) { + throw new Error(`Cannot find services for ${apps[i]}`); + } + + Object.keys(content.services).forEach( + (serviceName) => { // jshint ignore:line + const s = content.services[serviceName]; + if (s.image && s.image.endsWith(':latest')) { + throw new Error(`"latest" tag is not allowed as it can change and break the setup, see ${apps[i]}`); + } + }); + + const logoFileName = apps[i] + '.png'; + + const logoFullPath = path.join(pathOfVersion, 'logos', logoFileName); + + if (!fs.existsSync(logoFullPath) || + !fs.statSync(logoFullPath).isFile()) { + let printablePath = logoFullPath; + printablePath = printablePath.substr(printablePath.indexOf(`/${PUBLIC}`)); + throw new Error(`Cannot find logo for ${apps[i]} ${printablePath}`); + } + + console.log(`Validated ${apps[i]}`); + + } + + }); + } + + // validating version 2 + function validateV2() { + + const version = '2'; + const pathOfVersion = path.join(pathOfPublic, 'v' + version); + const pathOfApps = path.join(pathOfVersion, 'apps'); + + return fs.readdir(pathOfApps) + .then(function (items) { + + const apps = items.filter(v => v.includes('.json')); + + if (items.length !== apps.length) { + throw new Error('All files in v2 must end with .json'); + } + + for (var i = 0; i < apps.length; i++) { + const contentString = fs.readFileSync(path.join(pathOfApps, apps[i])); + const content = JSON.parse(contentString); + const captainVersion = (content.captainVersion + ''); + const versionString = (version + ''); + if (versionString !== captainVersion) + throw new Error(`unmatched versions ${versionString} ${captainVersion} for ${apps[i]}`); + + apps[i] = apps[i].replace('.json', ''); + + if (!content.description) { + throw new Error(`Cannot find description for ${apps[i]}`); + } + + const logoFileName = apps[i] + '.png'; + + const logoFullPath = path.join(pathOfVersion, 'logos', logoFileName); + + if (!fs.existsSync(logoFullPath) || + !fs.statSync(logoFullPath).isFile()) { + let printablePath = logoFullPath; + printablePath = printablePath.substr(printablePath.indexOf(`/${PUBLIC}`)); + throw new Error(`Cannot find logo for ${apps[i]} ${printablePath}`); + } + + console.log(`Validated ${apps[i]}`); + + } + + }); + } + + Promise.resolve() + .then(function () { + return validateV2(); + }) + .then(function () { + return validateV4(); + }) + .catch(function (err) { + console.error(err); + process.exit(127); + }); \ No newline at end of file diff --git a/scripts/validate_json.js b/scripts/validate_json.js deleted file mode 100644 index 3e58338..0000000 --- a/scripts/validate_json.js +++ /dev/null @@ -1,104 +0,0 @@ - /*jshint esversion: 6 */ - const path = require('path'); - const fs = require('fs-extra'); - - const PUBLIC = `public`; - const pathOfPublic = path.join(__dirname, '..', PUBLIC); - - - // validating version 4 - // function validateV4() { - - // const version = '2'; - // const pathOfVersion = path.join(pathOfPublic, 'v' + version); - // const pathOfApps = path.join(pathOfVersion, 'apps'); - - // return fs.readdir(pathOfApps) - // .then(function (items) { - - // const apps = items.filter(v => v.includes('.json')); - - // for (var i = 0; i < apps.length; i++) { - // const contentString = fs.readFileSync(path.join(pathOfApps, apps[i])); - // const content = JSON.parse(contentString); - // const captainVersion = (content.captainVersion + ''); - // const versionString = (version + ''); - // if (versionString !== captainVersion) - // throw new Error(`unmatched versions ${versionString} ${captainVersion} for ${apps[i]}`); - - // apps[i] = apps[i].replace('.json', ''); - - // if (!content.description){ - // throw new Error(`Cannot find description for ${apps[i]}`); - // } - - // const logoFileName = apps[i] + '.png'; - - // const logoFullPath = path.join(pathOfVersion, 'logos', logoFileName); - - // if (!fs.existsSync(logoFullPath) || - // !fs.statSync(logoFullPath).isFile()) { - // let printablePath = logoFullPath; - // printablePath = printablePath.substr(printablePath.indexOf(`/${PUBLIC}`)); - // throw new Error(`Cannot find logo for ${apps[i]} ${printablePath}`); - // } - - // console.log(`Validated ${apps[i]}`); - - // } - - // }); - // } - - // validating version 2 - function validateV2() { - - const version = '2'; - const pathOfVersion = path.join(pathOfPublic, 'v' + version); - const pathOfApps = path.join(pathOfVersion, 'apps'); - - return fs.readdir(pathOfApps) - .then(function (items) { - - const apps = items.filter(v => v.includes('.json')); - - for (var i = 0; i < apps.length; i++) { - const contentString = fs.readFileSync(path.join(pathOfApps, apps[i])); - const content = JSON.parse(contentString); - const captainVersion = (content.captainVersion + ''); - const versionString = (version + ''); - if (versionString !== captainVersion) - throw new Error(`unmatched versions ${versionString} ${captainVersion} for ${apps[i]}`); - - apps[i] = apps[i].replace('.json', ''); - - if (!content.description) { - throw new Error(`Cannot find description for ${apps[i]}`); - } - - const logoFileName = apps[i] + '.png'; - - const logoFullPath = path.join(pathOfVersion, 'logos', logoFileName); - - if (!fs.existsSync(logoFullPath) || - !fs.statSync(logoFullPath).isFile()) { - let printablePath = logoFullPath; - printablePath = printablePath.substr(printablePath.indexOf(`/${PUBLIC}`)); - throw new Error(`Cannot find logo for ${apps[i]} ${printablePath}`); - } - - console.log(`Validated ${apps[i]}`); - - } - - }); - } - - Promise.resolve() - .then(function () { - return validateV2(); - }) - .catch(function (err) { - console.error(err); - process.exit(127); - }); \ No newline at end of file