diff --git a/.github/workflows/main.yml b/.github/workflows/buildMain.yml similarity index 67% rename from .github/workflows/main.yml rename to .github/workflows/buildMain.yml index 40d20573..dce771c9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/buildMain.yml @@ -1,15 +1,12 @@ -name: CI +name: Publish Tutorials and Courses on: repository_dispatch: types: [dispatch-katacoda-scenarios] - workflow_dispatch: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - name: choose random polling time id: randompoll @@ -28,33 +25,45 @@ jobs: poll-interval-seconds: ${{ steps.randompoll.outputs.selected }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + - name: Checkout tutorial-compiler uses: actions/checkout@v2 with: repository: devonfw-tutorials/tutorial-compiler + path: compiler - name: Checkout playbooks uses: actions/checkout@v2 with: repository: devonfw-tutorials/tutorials - path: playbooks + path: compiler/playbooks + - uses: actions/setup-node@v2-beta - - name: install TS - run: npm install typescript - - - name: npm install - run: npm install + run: | + cd compiler + npm install typescript - - name: run buildRun.sh - run: sh buildRun.sh -e katacoda -p ${{ github.event.client_payload.tutorial }} + - name: npm install + run: | + cd compiler + npm install - name: Checkout uses: actions/checkout@v2 with: path: repo + + - uses: actions/setup-node@v2-beta + - name: npm install + run: | + cd repo + npm install + - - name: publish tutorials - run: bash repo/publishTutorials.sh + - name: create tutorials and courses + run: node repo/publish.js $GITHUB_WORKSPACE + + - name: publish tutorials and courses + run: bash repo/publishScenariosAndCourses.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6fd10a4d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/node_modules/* \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..afe7bc8d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,37 @@ +{ + "name": "katacoda-scenarios", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..c47839a3 --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "katacoda-scenarios", + "version": "1.0.0", + "description": "", + "dependencies": { + "fs-extra": "^10.0.0" + }, + "author": "", + "license": "ISC" +} diff --git a/publish.js b/publish.js new file mode 100644 index 00000000..ca877798 --- /dev/null +++ b/publish.js @@ -0,0 +1,191 @@ +const path = require('path'); +const fs = require('fs-extra'); +const child_process = require("child_process"); + +const SCENARIOS = path.join(process.argv[2], 'repo'); +const COMPILER = path.join(process.argv[2], 'compiler'); +const PLAYBOOKS = path.join(COMPILER, 'playbooks'); + +const TEMP = path.join(process.argv[2], 'temp'); +const TEMP_COURSES = path.join(process.argv[2], 'temp', 'courses'); +const TEMP_FILES = path.join(process.argv[2], 'temp', 'scenarios'); + +let usedScenarios = new Array(); +let folderNames = new Array(); + +function publish(){ + try{ + + + const SPECIFIED_COURSES = getCourses(PLAYBOOKS); + const SPECIFIED_SCENARIOS = getScenarios(PLAYBOOKS); + + //create directories to save temp courses and scenarios + createFolder(TEMP); + createFolder(TEMP_COURSES); + createFolder(TEMP_FILES); + + //TODO UPDATE changed course files only + //ISSUE #24 + updateCourseFiles(); + + //TODO GENERATE changed tutorials only + //ISSUE #25 + generateNewScenarios(); + + //TODO UPDATE changed courses only + //ISSUE #26 + SPECIFIED_COURSES.forEach(course =>{ + createCourse(course); + }); + + //TODO UPDATE changed scenarios only + //ISSUE #27 + SPECIFIED_SCENARIOS.forEach( scenario => { + if(! usedScenarios.includes(scenario)){ + createScenario(scenario); + } + }); + + //Delete unused and newly generated tutorials + cleanUp(); + fs.copySync(TEMP_COURSES, SCENARIOS + "/."); + fs.copySync(TEMP_FILES, SCENARIOS + "/."); + + let NEW_ONLINE_COURSES = getCourses(SCENARIOS); + let NEW_ONLINE_SCENARIOS = getScenarios(SCENARIOS); + console.log("ALL COURSES", NEW_ONLINE_COURSES) + console.log("ALL SCENARIO- AND COURSE-FOLDERS", NEW_ONLINE_SCENARIOS); + } + + catch(e) { + console.error(e); + return -1; + } + +} + +function updateCourseFiles(){ + const ONLINE_COURSES = fs.readdirSync(SCENARIOS, { withFileTypes: true }).filter(dirent => dirent.isFile()); + const SPECIFIED_COURSES = fs.readdirSync(PLAYBOOKS, { withFileTypes: true }).filter(dirent => dirent.isFile()); + + ONLINE_COURSES.forEach(course => { + if(course.name.includes('-pathway')){ + fs.removeSync(path.join(SCENARIOS, course.name)); + } + }); + + SPECIFIED_COURSES.forEach(course => { + if(course.name.includes('-pathway')){ + fs.copyFile(path.join(PLAYBOOKS, course.name), path.join(SCENARIOS, course.name)); + console.log(course.name, 'updated.' ); + } + }); +} + +function generateNewScenarios(){ + let cp = child_process.spawnSync(`bash buildRun.sh -e katacoda`, { shell: true, cwd: COMPILER, encoding: 'utf-8' }); + if(!fs.existsSync(path.join(COMPILER, 'build', 'output', 'katacoda'))) { + console.log("ERROR[generateNewScenarios]: ", cp); + return ""; + } +} + +function createCourse(coursefile){ + //create course folder + let courseDirName = coursefile.replace("-pathway.json", ''); + createFolder(path.join(TEMP_COURSES, courseDirName)); + folderNames.push(courseDirName); + + //parse scenario names + const genScenariosDir = path.join(COMPILER, 'build', 'output', 'katacoda'); + let rawData = fs.readFileSync(path.join(SCENARIOS, coursefile)); + let courseJson = JSON.parse(rawData); + + courseJson.courses.forEach(scenario => { + fs.copySync(path.join(genScenariosDir, scenario.course_id), path.join(TEMP_COURSES, courseDirName, scenario.course_id)); + if(!fs.existsSync(path.join(TEMP_COURSES, courseDirName, scenario.course_id))) { + console.log('Copying', scenario.course_id, 'to', courseDirName, 'failed'); + return ""; + } + if(!usedScenarios.includes(scenario.course_id)){ + usedScenarios.push(scenario.course_id); + } + }); + + console.log(courseDirName, 'created in temporory directory.' ); + +} + +function createScenario(scenario){ + const genScenariosDir = path.join(COMPILER, 'build', 'output', 'katacoda'); + folderNames.push(scenario); + fs.copySync(path.join(genScenariosDir, scenario), path.join(TEMP_FILES, scenario)); + + console.log(scenario, 'created in temporory directory.' ); +} + +function cleanUp(){ + const ONLINE_COURSES = getCourses(SCENARIOS); + const ONLINE_FOLDERS = getScenarios(SCENARIOS); + + ONLINE_COURSES.forEach(coursefile => { + course = coursefile.replace('-pathway.json'); + if(! folderNames.includes(course)){ + fs.removeSync(path.join(SCENARIOS, course), { recursive: true }); + console.log(course, "doesn't exist anymore in the tutorials repository." ); + } + }); + + ONLINE_FOLDERS.forEach(scenario => { + if(! folderNames.includes(scenario)){ + fs.removeSync(path.join(SCENARIOS, scenario), { recursive: true }); + console.log(scenario, "doesn't exist anymore in the tutorials repository." ); + } + }); + + //TODO Filter only newly generated folders + //ISSUE #25 #26 + ONLINE_FOLDERS.forEach(scenario => { + if(fs.existsSync(path.join(SCENARIOS, scenario))){ + fs.removeSync(path.join(SCENARIOS, scenario), { recursive: true }); + console.log(scenario, "removed to replace it with build." ); + } + }); + + +} + + +function getScenarios(dirname){ + let folders = fs.readdirSync(dirname, { withFileTypes: true }).filter(dirent => dirent.isDirectory()); + let scenarios = new Array(); + folders.forEach(folder => { + if(!folder.name.includes('git')){ + scenarios.push(folder.name); + } + }); + return scenarios; +} + + +function getCourses(dirname){ + let files = fs.readdirSync(dirname, { withFileTypes: true }).filter(dirent => dirent.isFile()); + let coursefiles = new Array(); + files.forEach(file => { + if(file.name.includes("pathway")){ + coursefiles.push(file.name); + } + }); + return coursefiles; +} + +function createFolder(dirname){ + if (fs.existsSync(dirname)){ + fs.removeSync(dirname); + } + fs.mkdir(dirname); + console.log(dirname, "was created."); +} + +publish(); \ No newline at end of file diff --git a/publishScenariosAndCourses.sh b/publishScenariosAndCourses.sh new file mode 100644 index 00000000..3c6ed551 --- /dev/null +++ b/publishScenariosAndCourses.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd repo/ +git add -A +git config user.email "devonfw" +git config user.name "devonfw" +git commit -m "Updated tutorials" +git pull --rebase origin/master +git push diff --git a/publishTutorials.sh b/publishTutorials.sh deleted file mode 100644 index a94aaf6d..00000000 --- a/publishTutorials.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -cd playbooks -SPECIFIED_TUTORIALS=() -for dir in */; do SPECIFIED_TUTORIALS+=("${dir::-1}"); done -echo "SPECIFIED_TUTORIALS:\n" -printf "%s\n" "${SPECIFIED_TUTORIALS[@]}" - -cd ../repo -ONLINE_TUTORIALS=() -for dir in */; do ONLINE_TUTORIALS+=("${dir::-1}"); done -echo "ONLINE_TUTORIALS:\n" -printf "%s\n" "${ONLINE_TUTORIALS[@]}" - -# delete tutorials, which are not specified anymore -for tutorial in "${ONLINE_TUTORIALS[@]}" -do - if [[ ! " ${SPECIFIED_TUTORIALS[@]} " =~ " ${tutorial} " ]]; then - rm -rf "${tutorial}" - echo "deleted ${tutorial} as not specified anymore in tutorials repository" - fi -done - -cd ../build/output/katacoda -GENERATED_TUTORIALS=() -for dir in */; do GENERATED_TUTORIALS+=("${dir::-1}"); done -echo "GENERATED_TUTORIALS:\n" -printf "%s\n" "${GENERATED_TUTORIALS[@]}" -cd ../../.. - -# delete tutorials, which are newly generated -for tutorial in "${ONLINE_TUTORIALS[@]}" -do - if [[ ! " ${GENERATED_TUTORIALS[@]} " =~ " ${tutorial} " ]]; then - rm -rf repo/'${tutorial}' - echo "deleted ${tutorial} as this is up to be replaced by the build" - fi -done - -cp -r build/output/katacoda/*/ repo/ -cd repo/ -git add -A -git config user.email "devonfw" -git config user.name "devonfw" -git commit -m "Updated tutorials" -git pull --rebase origin/master -git push