diff --git a/.env b/.env new file mode 100644 index 0000000..013ad2c --- /dev/null +++ b/.env @@ -0,0 +1 @@ +LOG_LEVEL=info \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65715ac..a964a8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,13 +3,13 @@ name: Build, package and test on: push: branches: - - master - workflow_dispatch: - pull_request: - branches: - - master - schedule: - - cron: '0 4 * * *' # Runs every day at 4am: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule + - main + #workflow_dispatch: + #pull_request: + # branches: + # - master + #schedule: + # - cron: '0 4 * * *' # Runs every day at 4am: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule jobs: @@ -46,33 +46,44 @@ jobs: shell: bash run: | yarn --skip-integrity-check --network-timeout 100000 - yarn build:dev + yarn build yarn download:plugins - yarn package:applications:preview + yarn package:applications:prod + yarn add jszip pino pino-pretty -W + yarn eos package + mkdir applications/electron/dist/uploads + mv applications/electron/dist/EosThesisIDE.* applications/electron/dist/uploads + (test -e "applications/electron/dist/uploads/EosThesisIDE.exe.blockmap" && rm applications/electron/dist/uploads/EosThesisIDE.exe.blockmap) || true env: NODE_OPTIONS: --max_old_space_size=4096 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9 - - name: Test (Linux) - if: matrix.tests != 'skip' && runner.os == 'Linux' - uses: GabrielBB/xvfb-action@v1 + - name: Upload artifacts to workflow action + uses: actions/upload-artifact@v2 with: - run: yarn electron test + name: dist + path: applications/electron/dist/uploads - - name: Test (Windows) - if: matrix.tests != 'skip' && runner.os == 'Windows' - shell: bash - run: | - yarn electron test + #- name: Test (Linux) + # if: matrix.tests != 'skip' && runner.os == 'Linux' + # uses: GabrielBB/xvfb-action@v1 + # with: + # run: yarn electron test + + #- name: Test (Windows) + # if: matrix.tests != 'skip' && runner.os == 'Windows' + # shell: bash + # run: | + # yarn electron test - - name: Test (macOS) - if: matrix.tests != 'skip' && runner.os == 'macOS' - shell: bash - run: | - yarn electron test + #- name: Test (macOS) + # if: matrix.tests != 'skip' && runner.os == 'macOS' + # shell: bash + # run: | + # yarn electron test - - name: Lint - if: matrix.tests != 'skip' - shell: bash - run: | - yarn lint + #- name: Lint + # if: matrix.tests != 'skip' + # shell: bash + # run: | + # yarn lint diff --git a/jakefile.d/package.js b/jakefile.d/package.js new file mode 100644 index 0000000..522b6c9 --- /dev/null +++ b/jakefile.d/package.js @@ -0,0 +1,75 @@ +"use strict"; + +const { logger, DATA_DIR, DIST_DIR } = require('./utils.cjs'); + +const { desc, namespace, task } = require('jake'); +const archiver = require("archiver"); +const fs = require('fs'); +const fse = require('fs-extra'); +const os = require('os'); +const path = require('path'); +const { dirname } = require('path'); + +desc("Run package data .... tasks in a single call"); +task("package", ["package:data", "package:portable"], () => { + logger.info("Done!"); +}); + +function getUnpackedDir() { + return fs.readdirSync(DIST_DIR).find(d => d.endsWith('-unpacked')); +} + +function isLinux() { + return os.platform() === 'linux'; +} + +namespace("package", function () { + desc("Copy Eos Thesis default data to dist"); + task("data", async () => { + let targetData = path.resolve(DIST_DIR, getUnpackedDir(), 'data'); + logger.info(`package:data - copying data files to ${targetData}`); + await fse.ensureDir(targetData); + await fse.copy(DATA_DIR, targetData); + logger.info("package:data - done"); + }); + + desc("Create portable compressed file"); + task("portable", ["data"], async () => { + const dirName = getUnpackedDir(); + const oldPath = path.resolve(DIST_DIR, dirName); + const portableName = `EosThesisIDE-${dirName.split('-')[0]}`; + const newPath = path.resolve(DIST_DIR, portableName); + logger.info(`package:portable - renaming from ${dirName} to ${portableName}`); + fs.renameSync(oldPath, newPath); + + const linux = isLinux(); + + + /** + * @param {String} sourceDir: /some/folder/to/compress + * @param {String} outPath: /path/to/created.zip + * @returns {Promise} + */ + async function compressDirectory(sourceDir, outPath) { + const archive = archiver( + linux ? 'tar' : 'zip' , + linux ? { gzip: true } : { zlib: { level: 9 } } + ); + const stream = fs.createWriteStream(outPath); + + return new Promise((resolve, reject) => { + archive + .directory(sourceDir, false) + .on("error", (err) => reject(err)) + .pipe(stream); + stream.on("close", () => resolve()); + archive.finalize(); + }); + } + + const newFile = path.resolve(DIST_DIR, portableName.replace('-', '.') + (linux ? '.tar.gz' : '.zip')); + logger.info(`package:portable - compressing ${newFile}...`); + await compressDirectory(newPath, newFile); + logger.info('package:portable - compressed'); + }); +}); diff --git a/jakefile.d/utils.cjs b/jakefile.d/utils.cjs new file mode 100644 index 0000000..fbb7d14 --- /dev/null +++ b/jakefile.d/utils.cjs @@ -0,0 +1,110 @@ +'use strict'; + +const fetch = require('node-fetch'); +const fs = require('fs'); +const fse = require("fs-extra"); +const JSZip = require('jszip'); +const path = require('path'); +const pino = require('pino'); +const pretty = require('pino-pretty'); + + +const BASEDIR = path.resolve(__dirname, '..'); + +console.log('!!!! Set LOG_LEVEL environment variable to set pino js log level. Default is trace.'); +const logger = pino( + { + level: process.env.LOG_LEVEL || 'info', + }, + pretty({ + colorize: true, + sync: true, + ignore: 'pid,hostname' + }) +); + +const sleep = (ms) => { + logger.trace(`Sleeping for ${ms}ms`) + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + + +module.exports = { + BASEDIR, + DATA_DIR: path.resolve(BASEDIR, "applications/data"), + DIST_DIR: path.resolve(BASEDIR, "applications/electron/dist"), + ELECTRON_DIR: path.resolve(BASEDIR, "applications/electron"), + PACKAGE_JSON: path.resolve(BASEDIR, "applications/electron/package.json"), + PLUGINS_DIR: path.resolve(BASEDIR, "applications/data/backend/extensions/"), + PLUGINS_FILE: path.resolve(BASEDIR, "jakefile.d/plugins-list.json"), + logger, + sleep, + get: async (url) => { + let response = await fetch(url); + if (response.status !== 200) { + process.exit(1); + } + return await response.json(); + }, + download: async (url, filepath, opts = {}) => { + opts = Object.assign({ prefix: 'fn:download' }, opts) + logger.info(`${opts.prefix} - download from ${url}...`); + const response = await fetch(url); + await new Promise((resolve, reject) => { + logger.info(`${opts.prefix} - saving to ${filepath}`); + fse.ensureDirSync(path.dirname(filepath)); + const fileStream = fs.createWriteStream(filepath); + response.body.pipe(fileStream); + response.body.on("error", (err) => { + fileStream.close(); + reject(err); + }); + fileStream.on("finish", function () { + fileStream.close(); + resolve(); + }); + }); + }, + attempt: async (callable, opts) => { + opts = Object.assign({ delay: 100, maxTries: 5, prefix: 'fn:attempt' }, opts); + let error = null; + while (opts.maxTries > 0) { + try { + const result = await callable() + logger.info(`${opts.prefix} - attempt success`); + return result; + } catch (err) { + error = err; + logger.error(`${opts.prefix} - attempt error (${opts.maxTries > 0 ? 'will try again' : 'no more tries'}): ${error}`); + opts.maxTries--; + await sleep(opts.delay); + } + } + if (opts.maxTries == 0) { + throw error; + } + }, + unzip: async (file, destination, opts = {}) => { + opts = Object.assign({ verbose: false, prefix: 'fn:unzip' }, opts); + logger.info(`${opts.prefix} - unzipping ${file}`); + const data = fs.readFileSync(file); + if (data) { + const zip = new JSZip(); + const contents = await zip.loadAsync(data); + for (const filename in contents.files) { + const buffer = zip.file(filename).async('nodebuffer'); + await buffer.then(function (content) { + const dest = path.resolve(destination, filename); + if (opts.verbose) { + logger.trace(`${opts.prefix} - extracting file ${destination} / ${filename}`); + } + fs.mkdirSync(path.dirname(dest), { recursive: true }); + fs.writeFileSync(dest, content); + }); + } + logger.info(`${opts.prefix} - unzipped ${file}`); + } + } +}; \ No newline at end of file diff --git a/jakefile.js b/jakefile.js new file mode 100644 index 0000000..a46314a --- /dev/null +++ b/jakefile.js @@ -0,0 +1,47 @@ +'use strict'; + +//require('dotenv').config(); + +const { task, desc, Task } = require("jake"); +const { logger } = require("./jakefile.d/utils.cjs"); + +desc("Show help about this project"); +task("default", ["help"], function() {}); + +desc("Show help about this project"); +task("help", function () { + const tasks = []; + + for (let taskName in Task) { + if (!Object.prototype.hasOwnProperty.call(Task, taskName)) { + continue; + } + let task = Task[taskName]; + + let taskParams = ""; + if (task.params != "") { + taskParams = "[" + task.params + "]"; + } + + let descr = task.description; + if (descr) { + tasks.push(taskName.padEnd(30, ' ') + taskParams + " # " + descr); + } + } + + logger.info(` + =============================================== + Eos Thesis IDE :: Build Help + ----------------------------------------------- + + Use "yarn eos help" to show this help. + + Use "yarn eos " to run a task. + + You can use jake directly too as "yarn jake [arguments]". + + # Available tasks: + ${tasks.reduce((p, c) => p + "\n " + c)} + =============================================== + `); +}); diff --git a/package.json b/package.json index 60c0c8a..a00d517 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "browser": "yarn --cwd applications/browser", "update:next": "ts-node scripts/update-theia-to-next.ts && lerna run update:next", "lint": "eslint --ext js,jsx,ts,tsx scripts && lerna run lint", - "lint:fix": "eslint --ext js,jsx,ts,tsx scripts --fix && lerna run lint:fix" + "lint:fix": "eslint --ext js,jsx,ts,tsx scripts --fix && lerna run lint:fix", + "eos": "yarn jake --jakelibdir jakefile.d" }, "theiaPluginsDir": "plugins", "theiaPlugins": {