diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml new file mode 100644 index 0000000..16e067b --- /dev/null +++ b/.github/actions/test/action.yml @@ -0,0 +1,50 @@ +# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action +name: "Test custom" +description: "Custom test step to run during a pull request" +# this inputs are always provided by flowzone, so they must always be defined on the composite action +inputs: + json: + description: "JSON stringified object containing all the inputs from the calling workflow" + required: true + secrets: + description: "JSON stringified object containing all the secrets from the calling workflow" + required: true +runs: + using: "composite" + steps: + - name: Setup Node.js 18 + if: ${{ fromJSON(env.os_value)[0] == 'ubuntu-20.04' }} + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Setup Node.js lts + if: ${{ fromJSON(env.os_value)[0] != 'ubuntu-20.04' }} + uses: actions/setup-node@v3 + with: + node-version: lts/* + + - name: Install dependencies + shell: bash + run: | + if [ -e package-lock.json ]; then + npm ci + else + npm i + fi + + - name: Run custom node tests + shell: bash + run: | + # os_value is a JSON array of runner labels but we are only looking at the first element + echo "OS: ${{ fromJSON(env.os_value)[0] }}" + node -v + npm -v + + export TEST_EMAIL_KEY=${{ format('TEST_EMAIL{0}', fromJSON('{"windows-2019":"","ubuntu-20.04":"_1","macos-12":"_2"}')[fromJSON(env.os_value)[0]]) }} + export TEST_EMAIL=${{ fromJSON(inputs.secrets)[ format('TEST_EMAIL{0}', fromJSON('{"windows-2019":"","ubuntu-20.04":"_1","macos-12":"_2"}')[fromJSON(env.os_value)[0]]) ] }} + export TEST_PASSWORD=${{ fromJSON(inputs.secrets).TEST_PASSWORD }} + + echo "TEST_EMAIL_KEY: [ ${TEST_EMAIL_KEY} ]" + echo "TEST_EMAIL: [ ${TEST_EMAIL} ]" + npm test diff --git a/.github/workflows/flowzone.yml b/.github/workflows/flowzone.yml new file mode 100644 index 0000000..d13685b --- /dev/null +++ b/.github/workflows/flowzone.yml @@ -0,0 +1,23 @@ +name: Flowzone + +on: + pull_request: + types: [opened, synchronize, closed] + branches: [main, master] + # allow external contributions to use secrets within trusted code + pull_request_target: + types: [opened, synchronize, closed] + branches: [main, master] + +jobs: + flowzone: + name: Flowzone + uses: product-os/flowzone/.github/workflows/flowzone.yml@master + # prevent duplicate workflows and only allow one `pull_request` or `pull_request_target` for + # internal or external contributions respectively + if: | + (github.event.pull_request.head.repo.full_name == github.repository && github.event_name == 'pull_request') || + (github.event.pull_request.head.repo.full_name != github.repository && github.event_name == 'pull_request_target') + secrets: inherit + with: + custom_runs_on: '[["windows-2019"],["ubuntu-20.04"],["macos-12"]]' diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e029def..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,24 +0,0 @@ -# appveyor file -# http://www.appveyor.com/docs/appveyor-yml - -init: - - git config --global core.autocrlf input - -# what combinations to test -environment: - matrix: - - nodejs_version: 8 - - nodejs_version: 6 - -install: - - ps: Install-Product node $env:nodejs_version x64 - - npm -g install npm - - set PATH=%APPDATA%\npm;%PATH% - - npm install - -build: off - -test_script: - - node --version - - npm --version - - cmd: npm test diff --git a/circle.yml b/circle.yml deleted file mode 100644 index c206d18..0000000 --- a/circle.yml +++ /dev/null @@ -1,84 +0,0 @@ ---- -version: 2 - -buildSteps: &buildSteps - - checkout - - run: - name: install-npm - command: npm install - - run: - name: test - command: npm test - - persist_to_workspace: - # Persist all job output, so we can (potentially) use it for deploys - root: ../ - paths: - - ./node-* - -jobs: - "node-10": - docker: - - image: circleci/node:10 - working_directory: ~/node-10 - steps: *buildSteps - - "node-12": - docker: - - image: circleci/node:12 - working_directory: ~/node-12 - steps: *buildSteps - - "node-14": - docker: - - image: circleci/node:14 - working_directory: ~/node-14 - steps: *buildSteps - - deploy: - # For this to work NPM_TOKEN must be set for the account used for publishing - docker: - - image: circleci/node:10 - steps: - - attach_workspace: - at: $CIRCLE_WORKING_DIRECTORY - - run: - name: Login to npm - command: | - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc - npm whoami - - deploy: - name: Deploy to npm - command: npm publish - # Output used for publish is from node 10 build - working_directory: $CIRCLE_WORKING_DIRECTORY/node-10 - -workflows: - version: 2 - build: - jobs: - - "node-10": - # Run for all tags (required to allow the deploy to trigger on version tags) - filters: - tags: - only: /.*/ - - "node-12": - # Run for all tags (required to allow the deploy to trigger on version tags) - filters: - tags: - only: /.*/ - - "node-14": - # Run for all tags (required to allow the deploy to trigger on version tags) - filters: - tags: - only: /.*/ - - deploy: - # Deploy passing builds if they're tagged with a version - requires: - - "node-10" - - "node-12" - - "node-14" - filters: - tags: - only: /^v\d+\.\d+\.\d+$/ - branches: - ignore: /.*/ diff --git a/package.json b/package.json index e6b6589..40fdb59 100644 --- a/package.json +++ b/package.json @@ -20,18 +20,21 @@ }, "scripts": { "build": "gulp build && npm run readme", - "pretest": "npm run build", - "test": "gulp test && coffee tests/e2e.coffee", - "prepublish": "require-npm4-to-publish", + "test": "([ \"$GITHUB_WORKFLOW\" = 'Flowzone' ] && [ \"$GITHUB_JOB\" = 'npm_test' ] && echo \"Skipping 'npm test' in flowzone in favor of the custom test action!\") || (npm run build && npm run test:all)", + "test:all": "gulp test && coffee tests/e2e.coffee", "prepare": "npm run build", "readme": "jsdoc2md --template doc/README.hbs build/init.js > README.md" }, "author": "Juan Cruz Viotti ", "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, "devDependencies": { "balena-sdk": "^12.27.0", "coffeescript": "^1.12.7", "dotenv": "^4.0.0", + "etcher-sdk": "^9.0.8", "gulp": "^4.0.2", "gulp-coffee": "^2.3.5", "gulp-coffeelint": "^0.5.0", @@ -40,7 +43,6 @@ "jsdoc-to-markdown": "^5.0.3", "mocha": "^2.5.3", "mochainon": "^1.0.0", - "require-npm4-to-publish": "^1.0.0", "wary": "^1.1.1" }, "dependencies": { @@ -49,7 +51,7 @@ "bluebird": "^3.7.2", "lodash": "^4.17.15", "reconfix": "1.0.0-v0-1-0-fork-46760acff4d165f5238bfac5e464256ef1944476", - "resin-device-operations": "^1.7.0", + "resin-device-operations": "^2.0.0", "rindle": "^1.3.4", "string-to-stream": "^1.1.1" } diff --git a/tests/e2e.coffee b/tests/e2e.coffee index ef937f0..102d6d4 100644 --- a/tests/e2e.coffee +++ b/tests/e2e.coffee @@ -7,6 +7,7 @@ fs = Promise.promisifyAll(require('fs')) wary = require('wary') settings = require('balena-settings-client') +etcherSdk = require('etcher-sdk') sdk = require('balena-sdk')({ apiUrl: settings.get('apiUrl') }) @@ -170,14 +171,52 @@ wary.it 'should not trigger a state event when configuring a raspberry pi', .then -> m.chai.expect(spy).to.not.have.been.called +mockBlockDeviceFromFile = (path) -> + drive = { + raw: path, + device: path, + devicePath: path, + displayName: path, + icon: 'some icon', + isSystem: false, + description: 'some description', + mountpoints: [], + size: fs.statSync(path).size, + isReadOnly: false, + busType: 'UNKNOWN', + error: null, + blockSize: 512, + busVersion: null, + enumerator: 'fake', + isCard: null, + isRemovable: true, + isSCSI: false, + isUAS: null, + isUSB: true, + isVirtual: false, + logicalBlockSize: 512, + partitionTableType: null, + }; + device = new etcherSdk.sourceDestination.BlockDevice({ + drive, + unmountOnSuccess: false, + write: true, + direct: false, + }) + + device._open = () -> + etcherSdk.sourceDestination.File.prototype._open.call(device) + device._close = () -> + etcherSdk.sourceDestination.File.prototype._close.call(device) + + device + wary.it 'should initialize a raspberry pi image', raspberrypi: RASPBERRYPI_OS1 random: RANDOM , (images) -> - drive = - raw: images.random - size: fs.statSync(images.random).size + drive = mockBlockDeviceFromFile(images.random) sdk.models.device.get(DEVICES.raspberrypi.id).then (device) -> getManifest(device.device_type).then (manifest) -> @@ -196,9 +235,7 @@ wary.it 'should initialize a raspberry pi image containing a device type', random: RANDOM , (images) -> - drive = - raw: images.random - size: fs.statSync(images.random).size + drive = mockBlockDeviceFromFile(images.random) sdk.models.device.get(DEVICES.raspberrypi.id).then (device) -> # make sure the device-type.json file is read from the image @@ -218,9 +255,7 @@ wary.it 'should emit state events when initializing a raspberry pi', random: RANDOM , (images) -> - drive = - raw: images.random - size: fs.statSync(images.random).size + drive = mockBlockDeviceFromFile(images.random) spy = m.sinon.spy() @@ -243,9 +278,7 @@ wary.it 'should emit burn events when initializing a raspberry pi', random: RANDOM , (images) -> - drive = - raw: images.random - size: fs.statSync(images.random).size + drive = mockBlockDeviceFromFile(images.random) spy = m.sinon.spy()