From b7124bf114a25d36e1e01565db61350c19cfdcac Mon Sep 17 00:00:00 2001 From: Mike Donnalley Date: Thu, 30 Nov 2023 08:09:42 -0800 Subject: [PATCH] ci: run tests from oclif plugin repos (#882) --- .github/workflows/external-test.yml | 46 +++++ .github/workflows/test.yml | 45 +++++ test/integration/plugins.e2e.ts | 277 ---------------------------- test/integration/util.ts | 10 +- 4 files changed, 94 insertions(+), 284 deletions(-) create mode 100644 .github/workflows/external-test.yml delete mode 100644 test/integration/plugins.e2e.ts diff --git a/.github/workflows/external-test.yml b/.github/workflows/external-test.yml new file mode 100644 index 000000000..ace64eaa2 --- /dev/null +++ b/.github/workflows/external-test.yml @@ -0,0 +1,46 @@ +on: + workflow_call: + inputs: + os: + required: false + description: "runs-on property, ex: ubuntu-latest, windows-latest" + type: string + default: "ubuntu-latest" + repo: + required: true + description: "Repository name, ex: 'owner/repo'" + type: string + command: + required: true + description: "Command to run, ex: 'yarn test'" + type: string + other-setup: + required: false + description: "Setup command, ex: 'yarn install'" + type: string + +jobs: + external-test: + name: ${{ inputs.repo }} ${{ inputs.command }} + runs-on: ${{ inputs.os }} + steps: + - uses: actions/setup-node@v4 + - uses: actions/checkout@v4 + - uses: salesforcecli/github-workflows/.github/actions/yarnInstallWithRetries@main + - run: yarn build + - run: yarn link + - run: ${{ inputs.other-setup }} + - uses: actions/checkout@v4 + with: + repository: ${{ inputs.repo }} + ref: main + path: test + - name: Build plugin + working-directory: test + run: | + yarn install --network-timeout 600000 --ignore-scripts + yarn link @oclif/core + yarn build + - name: Run tests in plugin + working-directory: test + run: ${{ inputs.command }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 50e9f029f..91f4f9c18 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -122,3 +122,48 @@ jobs: TESTKIT_JWT_CLIENT_ID: ${{ secrets.TESTKIT_JWT_CLIENT_ID }} TESTKIT_JWT_KEY: ${{ secrets.TESTKIT_JWT_KEY }} TESTKIT_HUB_INSTANCE: ${{ secrets.TESTKIT_HUB_INSTANCE }} + external-unit-tests: + needs: linux-unit-tests + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + repo: + - oclif/plugin-autocomplete + - oclif/plugin-commands + - oclif/plugin-help + - oclif/plugin-not-found + - oclif/plugin-plugins + - oclif/plugin-update + - oclif/plugin-which + - oclif/plugin-warn-if-update-available + - oclif/plugin-version + uses: ./.github/workflows/external-test.yml + with: + repo: ${{ matrix.repo }} + os: ${{ matrix.os }} + command: "yarn mocha test/**/*.test.ts --timeout 1200000" + plugin-plugins-integration: + needs: linux-unit-tests + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + uses: ./.github/workflows/external-test.yml + with: + repo: oclif/plugin-plugins + os: ${{ matrix.os }} + command: "yarn test:integration" + # plugin-plugins integration tests depend on sf being installed globally + other-setup: npm install -g @salesforce/cli@nightly + plugin-update-integration: + needs: linux-unit-tests + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + uses: ./.github/workflows/external-test.yml + with: + repo: oclif/plugin-update + os: ${{ matrix.os }} + command: "yarn test:integration:sf" diff --git a/test/integration/plugins.e2e.ts b/test/integration/plugins.e2e.ts deleted file mode 100644 index 0a88c8c1e..000000000 --- a/test/integration/plugins.e2e.ts +++ /dev/null @@ -1,277 +0,0 @@ -import {config as chaiConfig, expect} from 'chai' -import {arch} from 'node:os' - -import {Executor, Result, setup} from './util' - -chaiConfig.truncateThreshold = 0 - -describe('oclif plugins', () => { - let executor: Executor - before(async () => { - executor = await setup(__filename, { - repo: 'https://github.com/oclif/hello-world-esm', - plugins: [ - '@oclif/plugin-autocomplete', - '@oclif/plugin-commands', - '@oclif/plugin-help', - '@oclif/plugin-not-found', - '@oclif/plugin-plugins', - '@oclif/plugin-update', - '@oclif/plugin-version', - '@oclif/plugin-which', - ], - yarnInstallArgs: ['--no-lockfile'], - }) - }) - - describe('plugin-help', () => { - describe(' help', () => { - let help: Result - before(async () => { - help = await executor.executeCommand('help') - }) - - it('should show description', () => { - expect(help.stdout).to.include('oclif example Hello World CLI (ESM)') - }) - it('should show version', () => { - expect(help.stdout).to.include('VERSION\n oclif-hello-world-esm') - }) - it('should show usage', () => { - expect(help.stdout).to.include('USAGE\n $ oclif-hello-world-esm [COMMAND]') - }) - it('should show topics', () => { - expect(help.stdout).to.include('TOPICS\n plugins') - }) - it('should show commands', () => { - const regex = /COMMANDS\n\s\sautocomplete|\s\scommands|\s\shelp|\s\splugins|\s\sversion|\s\supdate|\s\swhich/ - expect(regex.test(help.stdout!)).to.be.true - }) - }) - - describe('help ', () => { - let help: Result - before(async () => { - help = await executor.executeCommand('help plugins') - }) - - it('should show summary', () => { - expect(help.stdout).to.include('List installed plugins.') - }) - it('should show usage', () => { - expect(help.stdout).to.include('USAGE\n $ oclif-hello-world-esm plugins [--json] [--core]') - }) - it('should show description', () => { - expect(help.stdout).to.include('DESCRIPTION\n List installed plugins.') - }) - it('should show examples', () => { - expect(help.stdout).to.include('EXAMPLES\n $ oclif-hello-world-esm plugins') - }) - it('should show commands', () => { - const regex = - /COMMANDS\n\s\splugins:inspect|\s\splugins:install|\s\splugins:link|\s\splugins:uninstall|\s\splugins:update/ - expect(regex.test(help.stdout!)).to.be.true - }) - }) - - describe('help ', () => { - let help: Result - before(async () => { - help = await executor.executeCommand('help plugins:install') - }) - - it('should show summary', () => { - expect(help.stdout).to.include('Installs a plugin into the CLI.') - }) - it('should show usage', () => { - expect(help.stdout).to.include('USAGE\n $ oclif-hello-world-esm plugins:install PLUGIN...') - }) - it('should show arguments', () => { - expect(help.stdout).to.include('ARGUMENTS\n PLUGIN Plugin to install.') - }) - it('should show flags', () => { - expect(help.stdout).to.include('FLAGS\n') - expect(help.stdout).to.include('-f, --force Run yarn install with force flag.') - expect(help.stdout).to.include('-h, --help Show CLI help.') - expect(help.stdout).to.include('-v, --verbose') - }) - it('should show description', () => { - expect(help.stdout).to.include('DESCRIPTION\n Installs a plugin into the CLI.') - }) - it('should show aliases', () => { - expect(help.stdout).to.include('ALIASES\n $ oclif-hello-world-esm plugins:add') - }) - it('should show examples', () => { - expect(help.stdout).to.include('EXAMPLES\n') - expect(help.stdout).to.include('$ oclif-hello-world-esm plugins:install myplugin') - expect(help.stdout).to.include('$ oclif-hello-world-esm plugins:install https://github.com/someuser/someplugin') - expect(help.stdout).to.include('$ oclif-hello-world-esm plugins:install someuser/someplugin') - }) - }) - }) - - describe('plugin-commands', () => { - let commands: Result - - it('should show commands', async () => { - commands = await executor.executeCommand('commands') - expect(commands.stdout).to.include('commands') - expect(commands.stdout).to.include('help') - expect(commands.stdout).to.include('plugins') - expect(commands.stdout).to.include('plugins:inspect') - expect(commands.stdout).to.include('plugins:install') - expect(commands.stdout).to.include('plugins:link') - expect(commands.stdout).to.include('plugins:uninstall') - expect(commands.stdout).to.include('plugins:update') - expect(commands.stdout).to.include('version') - expect(commands.stdout).to.include('which') - }) - - it('should filter commands', async () => { - commands = await executor.executeCommand('commands --filter "command=plugins"') - expect(commands.stdout).to.include('plugins') - expect(commands.stdout).to.include('plugins:inspect') - expect(commands.stdout).to.include('plugins:install') - expect(commands.stdout).to.include('plugins:link') - expect(commands.stdout).to.include('plugins:uninstall') - expect(commands.stdout).to.include('plugins:update') - - expect(commands.stdout).to.not.include('commands') - expect(commands.stdout).to.not.include('help') - expect(commands.stdout).to.not.include('version') - expect(commands.stdout).to.not.include('which') - }) - - it('should extend columns', async () => { - commands = await executor.executeCommand('commands --extended') - expect(commands.stdout).to.include('Command') - expect(commands.stdout).to.include('Summary') - expect(commands.stdout).to.include('Description') - expect(commands.stdout).to.include('Usage') - expect(commands.stdout).to.include('Plugin') - expect(commands.stdout).to.include('Type') - expect(commands.stdout).to.include('Hidden') - }) - - it('should filter columns', async () => { - commands = await executor.executeCommand('commands --columns Command') - expect(commands.stdout).to.include('Command') - expect(commands.stdout).to.not.include('Summary') - }) - - it('should show commands in csv', async () => { - commands = await executor.executeCommand('commands --csv') - expect(commands.stdout).to.include('Command,Summary\n') - expect(commands.stdout).to.include('commands') - expect(commands.stdout).to.include('help') - expect(commands.stdout).to.include('plugins') - expect(commands.stdout).to.include('plugins:inspect') - expect(commands.stdout).to.include('plugins:install') - expect(commands.stdout).to.include('plugins:link') - expect(commands.stdout).to.include('plugins:uninstall') - expect(commands.stdout).to.include('plugins:update') - expect(commands.stdout).to.include('version') - expect(commands.stdout).to.include('which') - }) - - it('should show commands in json', async () => { - commands = await executor.executeCommand('commands --json') - const json = JSON.parse(commands.stdout!) as Array<{id: string}> - const commandIds = json.map((j) => j.id) - expect(commandIds).to.include('commands') - expect(commandIds).to.include('help') - expect(commandIds).to.include('plugins') - expect(commandIds).to.include('plugins:inspect') - expect(commandIds).to.include('plugins:install') - expect(commandIds).to.include('plugins:link') - expect(commandIds).to.include('plugins:uninstall') - expect(commandIds).to.include('plugins:update') - expect(commandIds).to.include('version') - expect(commandIds).to.include('which') - }) - }) - - describe('plugin-plugins', () => { - afterEach(async () => { - await executor.executeCommand('plugins:uninstall @oclif/plugin-warn-if-update-available') - }) - - describe('installing a plugin by name', () => { - it('should install the plugin', async () => { - const result = await executor.executeCommand('plugins:install @oclif/plugin-warn-if-update-available 2>&1') - expect(result.code).to.equal(0) - expect(result.stdout).to.include('@oclif/plugin-warn-if-update-available@latest... installed v') - - const pluginsResult = await executor.executeCommand('plugins') - expect(pluginsResult.code).to.equal(0) - expect(pluginsResult.stdout).to.include('@oclif/plugin-warn-if-update-available') - }) - }) - - describe('installing a plugin by github url', () => { - after(async () => { - await executor.executeCommand('plugins:uninstall @oclif/plugin-warn-if-update-available 2>&1') - }) - - it('should install the plugin', async () => { - const result = await executor.executeCommand( - 'plugins:install https://github.com/oclif/plugin-warn-if-update-available', - ) - expect(result.code).to.equal(0) - - const pluginsResult = await executor.executeCommand('plugins --core') - expect(pluginsResult.code).to.equal(0) - expect(pluginsResult.stdout).to.include('@oclif/plugin-warn-if-update-available') - }) - }) - - describe('forcefully installing a plugin', () => { - it('should install the plugin', async () => { - const result = await executor.executeCommand( - 'plugins:install @oclif/plugin-warn-if-update-available --force 2>&1', - ) - expect(result.code).to.equal(0) - expect(result.stdout).to.include('@oclif/plugin-warn-if-update-available@latest... installed v') - - const pluginsResult = await executor.executeCommand('plugins') - expect(pluginsResult.code).to.equal(0) - expect(pluginsResult.stdout).to.include('@oclif/plugin-warn-if-update-available') - }) - }) - - describe('uninstalling a plugin', () => { - beforeEach(async () => { - await executor.executeCommand('plugins:install @oclif/plugin-warn-if-update-available') - }) - - it('should uninstall the plugin', async () => { - const result = await executor.executeCommand('plugins:uninstall @oclif/plugin-warn-if-update-available 2>&1') - expect(result.code).to.equal(0) - expect(result.stdout).to.include('Uninstalling @oclif/plugin-warn-if-update-available... done\n') - - const pluginsResult = await executor.executeCommand('plugins') - expect(pluginsResult.code).to.equal(0) - expect(pluginsResult.stdout).to.not.include('@oclif/plugin-warn-if-update-available') - }) - }) - }) - - describe('plugin-version', () => { - let version: Result - before(async () => { - version = await executor.executeCommand('version') - }) - - it('should show version', () => expect(version.stdout).to.include('oclif-hello-world-esm')) - it('should show platform', () => expect(version.stdout).to.include(process.platform)) - it('should show arch', () => expect(version.stdout).to.include(arch())) - it('should show node version', () => expect(version.stdout).to.include(process.version)) - }) - - describe('plugin-which', () => { - it('should show the plugin that a command belongs to', async () => { - const result = await executor.executeCommand('which plugins:install') - expect(result.stdout).to.include('@oclif/plugin-plugins') - }) - }) -}) diff --git a/test/integration/util.ts b/test/integration/util.ts index 1ae0a80f0..fc2c3066e 100644 --- a/test/integration/util.ts +++ b/test/integration/util.ts @@ -24,7 +24,6 @@ export type SetupOptions = { plugins?: string[] subDir?: string noLinkCore?: boolean - yarnInstallArgs?: string[] } export type ExecutorOptions = { @@ -187,12 +186,9 @@ export async function setup(testFile: string, options: SetupOptions): Promise