Remove Gitlab Instance dependency for CLI tests (#883)

* Also added canary build if label is present
This commit is contained in:
Justin Dalrymple 2020-06-12 10:11:10 +02:00 committed by GitHub
parent 6f9dd5caae
commit 8b549da700
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1261 additions and 1136 deletions

View File

@ -17,6 +17,7 @@ stages:
- build
- lint
- test
- canary
- release
#Link and Install all required dependancies
@ -50,6 +51,10 @@ lint:docs:
script: yarn lint:doc
# Unit Tests
test:unit:cli:
stage: test
script: yarn jest cli/test/unit && yarn codecov -F cli
test:unit:core:
stage: test
script: yarn jest core/test/unit && yarn codecov -F core
@ -68,44 +73,40 @@ test:unit:utils:
script: yarn jest utils/test/unit && yarn codecov -F utils
# Integration Tests
.test:integration: &integration
image:
name: docker/compose:latest
entrypoint: ['/bin/sh', '-c']
variables:
DOCKER_HOST: tcp://docker:2375
GITLAB_URL: http://docker:8080
services:
- docker:dind
stage: test
before_script:
# Install docker compose
- apk add --no-cache nodejs yarn git
# .test:integration: &integration
# image:
# name: docker/compose:latest
# entrypoint: ['/bin/sh', '-c']
# variables:
# DOCKER_HOST: tcp://docker:2375
# GITLAB_URL: http://docker:8080
# services:
# - docker:dind
# stage: test
# before_script:
# # Install docker compose
# - apk add --no-cache nodejs yarn git
# Spin up container
- cd scripts
- docker-compose -f docker-compose.yml up -d
# # Spin up container
# - cd scripts
# - docker-compose -f docker-compose.yml up -d
# Verify Gitlab instance is up and running
- node probe.js
# # Verify Gitlab instance is up and running
# - node probe.js
# Get the personal token
- export PERSONAL_ACCESS_TOKEN=$(docker exec -i gitlab sh -c 'gitlab-rails r /mnt/init.rb')
# # Get the personal token
# - export PERSONAL_ACCESS_TOKEN=$(docker exec -i gitlab sh -c 'gitlab-rails r /mnt/init.rb')
- cd ..
- echo $PERSONAL_ACCESS_TOKEN
- echo $GITLAB_URL
- echo $CODECOV_TOKEN
# - cd ..
# - echo $PERSONAL_ACCESS_TOKEN
# - echo $GITLAB_URL
# - echo $CODECOV_TOKEN
test:integration:browser:
image: buildkite/puppeteer
stage: test
script: yarn jest browser/test/integration
test:integration:cli:
<<: *integration
script: yarn jest cli/test/integration
# test:integration:node:
# <<: *integration
# script: yarn jest node/test/integration && yarn codecov -F node
@ -122,6 +123,25 @@ test:integration:cli:
# <<: *integration
# script: yarn jest core/test/integration --runInBand --moduleNameMapper="{dist:dist/index.es.js}"
# Canary
canary:
stage: canary
only:
- external_pull_requests
before_script:
- apk add --no-cache git
- git remote set-url origin https://jdalrymple:${GITHUB_TOKEN}@github.com/jdalrymple/gitbeaker.git
- git checkout $CI_COMMIT_REF_NAME
- npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN
- npm config set always-auth=true
script: |
if yarn auto label --pr $CI_EXTERNAL_PULL_REQUEST_IID | grep 'canary'; then
echo "canary label found, starting canary deployment!"
yarn auto canary
else
echo "Skipping, canary label isn't present."
fi
# Release
release:
only:

View File

@ -655,6 +655,7 @@ This started as a fork from [node-gitlab-legacy](https://github.com/node-gitlab/
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
- [Dylan DesRosier](https://github.com/ddesrosier)

View File

@ -44,7 +44,7 @@
"test:unit": "jest test/unit",
"release": "auto shipit --verbose --verbose"
},
"version": "17.0.3",
"version": "19.7.0",
"author": "Justin Dalrymple <justin.s.dalrymple@gmail.com>",
"name": "gitbeaker"
}

View File

@ -9,28 +9,28 @@
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/core": "^19.7.0",
"@gitbeaker/requester-utils": "^19.7.0",
"@gitbeaker/core": "19.7.0",
"@gitbeaker/requester-utils": "19.7.0",
"ky": "^0.20.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-commonjs": "^12.0.0",
"@rollup/plugin-node-resolve": "^8.0.0",
"@rollup/plugin-replace": "^2.3.2",
"@types/expect-puppeteer": "^4.4.1",
"@types/expect-puppeteer": "^4.4.3",
"@types/jest-environment-puppeteer": "^4.3.1",
"@types/node": "^14.0.1",
"@types/puppeteer": "^2.0.1",
"@types/node": "^14.0.6",
"@types/puppeteer": "^3.0.0",
"jest-puppeteer": "^4.4.0",
"node-fetch": "^2.6.0",
"puppeteer": "^3.0.0",
"rollup": "^2.6.1",
"puppeteer": "3.1.0",
"rollup": "^2.12.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"ts-node": "^8.9.0",
"typescript": "^3.8.3"
"rollup-plugin-terser": "^6.1.0",
"rollup-plugin-typescript2": "^0.27.1",
"ts-node": "^8.10.2",
"typescript": "^3.9.3"
},
"engines": {
"node": ">=10.0.0"

View File

@ -2,7 +2,7 @@ import * as Gitbeaker from '@gitbeaker/core';
import { modifyServices } from '@gitbeaker/requester-utils';
import { Requester } from './KyRequester';
const APIServices = modifyServices(Gitbeaker, { requester: Requester });
const APIServices = modifyServices(Gitbeaker, [{ requester: Requester }]);
export const {
// Groups

View File

@ -3,8 +3,7 @@
"compilerOptions": {
"outDir": "./dist",
"declaration": true,
"declarationDir": "dist/types",
"types": ["puppeteer", "jest-environment-puppeteer", "expect-puppeteer"]
"declarationDir": "dist/types"
},
"include": ["src"]
}

View File

@ -12,8 +12,8 @@
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/core": "^19.7.0",
"@gitbeaker/node": "^19.7.0",
"@gitbeaker/core": "19.7.0",
"@gitbeaker/node": "19.7.0",
"chalk": "^4.0.0",
"ora": "^4.0.4",
"sywac": "^1.3.0",
@ -21,12 +21,12 @@
},
"devDependencies": {
"@rollup/plugin-json": "^4.0.3",
"rollup": "^2.6.1",
"rollup": "^2.12.0",
"rollup-plugin-preserve-shebangs": "^0.2.0",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"rollup-plugin-terser": "^6.1.0",
"rollup-plugin-typescript2": "^0.27.1",
"strip-ansi": "^6.0.0",
"typescript": "^3.8.3"
"typescript": "^3.9.3"
},
"engines": {
"node": ">=10.0.0"

View File

@ -0,0 +1,210 @@
import program, { Options } from 'sywac';
import chalk from 'chalk';
import { camelize, decamelize, depascalize } from 'xcase';
import * as Gitbeaker from '@gitbeaker/node';
import * as map from '@gitbeaker/core/dist/map.json';
// Styling settings
const commandStyle = chalk.hex('#e34329').bold;
const groupStyle = chalk.hex('#fca325').bold;
const usageStyle = chalk.hex('#fc6e26').bold;
const optionStyle = chalk.white.bold;
const descriptionStyle = chalk.hex('#848484');
const hintStyle = chalk.hex('#6a5f88');
// Globally configurable arguments
function globalConfig(env = process.env): { [name: string]: Options } {
return {
'gb-token': {
alias: 'gl-token',
desc: 'Your Gitlab Personal Token',
type: 'string',
defaultValue: env.GITBEAKER_TOKEN || env.GITLAB_TOKEN,
},
'gb-oauth-token': {
alias: 'gl-oauth-token',
desc: 'Your Gitlab OAuth Token',
type: 'string',
defaultValue: env.GITBEAKER_OAUTH_TOKEN || env.GITLAB_OAUTH_TOKEN,
},
'gb-job-token': {
alias: 'gl-job-token',
desc: 'Your Gitlab Job Token',
type: 'string',
defaultValue: env.GITBEAKER_JOB_TOKEN || env.GITLAB_JOB_TOKEN,
},
'gb-host': {
alias: 'gl-host',
desc: 'Your Gitlab API host (Defaults to https://www.gitlab.com)',
type: 'string',
defaultValue: env.GITBEAKER_HOST || env.GITLAB_HOST,
},
'gb-version': {
alias: 'gl-version',
desc: 'The targetted Gitlab API version (Defaults to 4)',
type: 'number',
defaultValue:
(env.GITBEAKER_VERSION && parseInt(env.GITBEAKER_VERSION, 10)) ||
(env.GITLAB_VERSION && parseInt(env.GITLAB_VERSION, 10)),
},
'gb-sudo': {
alias: 'gl-sudo',
desc: '[Sudo](https://docs.gitlab.com/ee/api/#sudo) query parameter',
type: 'string',
defaultValue: env.GITBEAKER_SUDO || env.GITLAB_SUDO,
},
'gb-camelize': {
alias: 'gl-camelize',
desc: 'Camelizes all response body keys',
type: 'boolean',
defaultValue:
(env.GITBEAKER_CAMELIZE && env.GITBEAKER_CAMELIZE === 'true') ||
(env.GITLAB_CAMELIZE && env.GITLAB_CAMELIZE === 'true'),
},
'gb-request-timeout': {
alias: 'gl-request-timeout',
desc: 'Timeout for API requests. Measured in ms',
type: 'number',
defaultValue:
(env.GITBEAKER_REQUEST_TIMEOUT && parseInt(env.GITBEAKER_REQUEST_TIMEOUT, 10)) ||
(env.GITBEAKER_REQUEST_TIMEOUT && parseInt(env.GITBEAKER_REQUEST_TIMEOUT, 10)),
},
'gb-profile-token': {
alias: 'gl-profile-token',
desc:
'[Requests Profiles Token](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html)',
type: 'string',
defaultValue: env.GITBEAKER_PROFILE_TOKEN || env.GITLAB_PROFILE_TOKEN,
},
'gb-profile-mode': {
alias: 'gl-profile-mode',
desc:
'[Requests Profiles Token](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html)',
type: 'string',
defaultValue: env.GITBEAKER_PROFILE_MODE || env.GITLAB_PROFILE_MODE,
},
};
}
// Options to be ignored when making an API call
const ignoreOptions = ['_', '$0', 'v', 'version', 'h', 'help', 'g', 'global-args'];
// Helper function to param case strings
function param(string) {
const attempt = decamelize(string, '-');
return attempt !== string ? attempt : depascalize(string, '-');
}
function setupAPIMethods(setupArgs, methodArgs) {
methodArgs.forEach((name) => {
if (name === 'options') return;
setupArgs.positional(`[--${param(name)}] <${param(name)}>`, {
group: 'Required Options',
type: 'string',
});
});
return setupArgs;
}
function runAPIMethod(ctx, args, apiName, method) {
const coreArgs = {};
const optionalArgs = {};
const initArgs = {};
Object.entries(args).forEach(([argName, value]) => {
if (ignoreOptions.includes(argName) || value == null) return;
const camelCased = camelize(argName.replace('gb-', '').replace('gl-', ''), '-');
if (globalConfig()[argName.replace('gl-', 'gb-')]) {
initArgs[camelCased] = value;
} else if (method.args.includes(camelCased)) coreArgs[camelCased] = value;
else optionalArgs[camelCased] = value;
});
// Create service
const s = new Gitbeaker[apiName](initArgs);
// Execute function
return s[method.name](...Object.values(coreArgs), optionalArgs)
.then((r) => {
ctx.output = JSON.stringify(r, null, 3);
})
.catch((e) => {
ctx.output = e;
});
}
function setupAPIs(setupArgs, apiName, methods) {
Object.entries(globalConfig()).forEach(([k, v]) => {
setupArgs.option(`${k} <value>`, {
group: 'Base Options',
...v,
});
});
for (let i = 1; i < methods.length; i += 1) {
const method = methods[i];
setupArgs.command(param(method.name), {
setup: (setupMethodArgs) => setupAPIMethods(setupMethodArgs, method.args),
run: (args, ctx) => runAPIMethod(ctx, args, apiName, method),
});
}
return setupArgs;
}
// Add default settings
const cli = program
.version('-v, --version')
.help('-h, --help')
.epilogue('Copyright 2019')
.style({
usagePrefix: (s) => usageStyle(s),
group: (s) => groupStyle(s),
flags: (s) => optionStyle(s),
usageCommandPlaceholder: (s) => commandStyle(s),
usageOptionsPlaceholder: (s) => optionStyle(s),
desc: (s) => descriptionStyle(s),
hints: (s) => hintStyle(s),
});
// Add Global commands
cli.boolean('-g --global-args', {
desc: 'Show global arguments currently set in the enviroment variables',
});
cli.command('*', (argv, ctx) => {
if (!argv.g) return;
const display = {};
Object.entries(globalConfig()).forEach(([k, v]) => {
if (v.defaultValue == null) return;
display[k] = {
alias: v.alias,
description: v.desc,
value: v.defaultValue,
};
});
ctx.output =
Object.keys(display).length === 0
? 'No global variables have been set!'
: JSON.stringify(display, null, 3);
});
// Add all supported API's
Object.entries(map).forEach(([apiName, methods]) => {
cli.command(param(apiName), {
desc: `The ${apiName} API`,
setup: (setupArgs) => setupAPIs(setupArgs, apiName, methods),
});
});
export { cli };

View File

@ -1,219 +1,5 @@
#!/usr/bin/env node
/* eslint no-console: 0 */
import program, { Options } from 'sywac';
import ora from 'ora';
import chalk from 'chalk';
import { camelize, decamelize, depascalize } from 'xcase';
import * as Gitbeaker from '@gitbeaker/node';
import * as map from '@gitbeaker/core/dist/map.json';
// Styling settings
const commandStyle = chalk.hex('#e34329').bold;
const groupStyle = chalk.hex('#fca325').bold;
const usageStyle = chalk.hex('#fc6e26').bold;
const optionStyle = chalk.white.bold;
const descriptionStyle = chalk.hex('#848484');
const hintStyle = chalk.hex('#6a5f88');
// Globally configurable arguments
const globalConfig: { [name: string]: Options } = {
'gb-token': {
alias: 'gl-token',
desc: 'Your Gitlab Personal Token',
type: 'string',
defaultValue: process.env.GITBEAKER_TOKEN || process.env.GITLAB_TOKEN,
},
'gb-oauth-token': {
alias: 'gl-oauth-token',
desc: 'Your Gitlab OAuth Token',
type: 'string',
defaultValue: process.env.GITBEAKER_OAUTH_TOKEN || process.env.GITLAB_OAUTH_TOKEN,
},
'gb-job-token': {
alias: 'gl-job-token',
desc: 'Your Gitlab Job Token',
type: 'string',
defaultValue: process.env.GITBEAKER_JOB_TOKEN || process.env.GITLAB_JOB_TOKEN,
},
'gb-host': {
alias: 'gl-host',
desc: 'Your Gitlab API host (Defaults to https://www.gitlab.com)',
type: 'string',
defaultValue: process.env.GITBEAKER_HOST || process.env.GITLAB_HOST,
},
'gb-version': {
alias: 'gl-version',
desc: 'The targetted Gitlab API version (Defaults to 4)',
type: 'number',
defaultValue:
(process.env.GITBEAKER_VERSION && parseInt(process.env.GITBEAKER_VERSION, 10)) ||
(process.env.GITLAB_VERSION && parseInt(process.env.GITLAB_VERSION, 10)),
},
'gb-sudo': {
alias: 'gl-sudo',
desc: '[Sudo](https://docs.gitlab.com/ee/api/#sudo) query parameter',
type: 'string',
defaultValue: process.env.GITBEAKER_SUDO || process.env.GITLAB_SUDO,
},
'gb-camelize': {
alias: 'gl-camelize',
desc: 'Camelizes all response body keys',
type: 'boolean',
defaultValue:
(process.env.GITBEAKER_CAMELIZE && process.env.GITBEAKER_CAMELIZE === 'true') ||
(process.env.GITLAB_CAMELIZE && process.env.GITLAB_CAMELIZE === 'true'),
},
'gb-request-timeout': {
alias: 'gl-request-timeout',
desc: 'Timeout for API requests. Measured in ms',
type: 'number',
defaultValue:
(process.env.GITBEAKER_REQUEST_TIMEOUT &&
parseInt(process.env.GITBEAKER_REQUEST_TIMEOUT, 10)) ||
(process.env.GITBEAKER_REQUEST_TIMEOUT &&
parseInt(process.env.GITBEAKER_REQUEST_TIMEOUT, 10)),
},
'gb-profile-token': {
alias: 'gl-profile-token',
desc:
'[Requests Profiles Token](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html)',
type: 'string',
defaultValue: process.env.GITBEAKER_PROFILE_TOKEN || process.env.GITLAB_PROFILE_TOKEN,
},
'gb-profile-mode': {
alias: 'gl-profile-mode',
desc:
'[Requests Profiles Token](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html)',
type: 'string',
defaultValue: process.env.GITBEAKER_PROFILE_MODE || process.env.GITLAB_PROFILE_MODE,
},
};
// Options to be ignored when making an API call
const ignoreOptions = ['_', '$0', 'v', 'version', 'h', 'help', 'g', 'global-args'];
// Helper function to param case strings
function param(string) {
const attempt = decamelize(string, '-');
return attempt !== string ? attempt : depascalize(string, '-');
}
function setupAPIMethods(setupArgs, methodArgs) {
methodArgs.forEach((name) => {
if (name === 'options') return;
setupArgs.positional(`[--${param(name)}] <${param(name)}>`, {
group: 'Required Options',
type: 'string',
});
});
return setupArgs;
}
function runAPIMethod(args, apiName, method) {
const coreArgs = {};
const optionalArgs = {};
const initArgs = {};
Object.entries(args).forEach(([argName, value]) => {
if (ignoreOptions.includes(argName) || value == null) return;
const camelCased = camelize(argName.replace('gb-', '').replace('gl-', ''), '-');
if (globalConfig[argName.replace('gl-', 'gb-')]) {
initArgs[camelCased] = value;
} else if (method.args.includes(camelCased)) coreArgs[camelCased] = value;
else optionalArgs[camelCased] = value;
});
// Create service
const s = new Gitbeaker[apiName](initArgs);
// Execute function
const spinner = ora({ text: 'Calling Gitlab', color: 'yellow' }).start();
return s[method.name](...Object.values(coreArgs), optionalArgs)
.then((r) => {
spinner.succeed('Success!');
console.log(JSON.stringify(r, null, 3));
})
.catch((e) => {
console.debug(e);
spinner.fail(e.description);
});
}
function setupAPIs(setupArgs, apiName, methods) {
Object.entries(globalConfig).forEach(([k, v]) => {
setupArgs.option(`${k} <value>`, {
group: 'Base Options',
...v,
});
});
for (let i = 1; i < methods.length; i += 1) {
const method = methods[i];
setupArgs.command(param(method.name), {
setup: (setupMethodArgs) => setupAPIMethods(setupMethodArgs, method.args),
run: (args) => runAPIMethod(args, apiName, method),
});
}
return setupArgs;
}
// Add default settings
program
.version('-v, --version')
.help('-h, --help')
.epilogue('Copyright 2019')
.style({
usagePrefix: (s) => usageStyle(s),
group: (s) => groupStyle(s),
flags: (s) => optionStyle(s),
usageCommandPlaceholder: (s) => commandStyle(s),
usageOptionsPlaceholder: (s) => optionStyle(s),
desc: (s) => descriptionStyle(s),
hints: (s) => hintStyle(s),
});
program.option('-g, --global-args', {
type: 'helpType',
desc: 'Show global arguments currently set in the enviroment variables',
});
// Add all supported API's
Object.entries(map).forEach(([apiName, methods]) => {
program.command(param(apiName), {
desc: `The ${apiName} API`,
setup: (setupArgs) => setupAPIs(setupArgs, apiName, methods),
});
});
import { cli } from './cli';
// Parse input
program.parse().then(({ argv, output }) => {
// Handle global args option
if (argv.g) {
const display = {};
Object.entries(globalConfig).forEach(([k, v]) => {
if (v.defaultValue === undefined) return;
display[k] = {
alias: v.alias,
description: v.desc,
value: v.defaultValue,
};
});
if (Object.keys(display).length === 0) {
console.log(optionStyle('No global variables have been set!'));
} else {
console.log(JSON.stringify(display, null, 3));
}
} else if (output) console.log(output);
});
cli.parse();

View File

@ -1,259 +0,0 @@
/* eslint no-console: 0 */
import strip from 'strip-ansi';
import { exec } from 'child_process';
import { promisify } from 'util';
import { resolve } from 'path';
import pkg from '../../package.json';
const execP = promisify(exec);
function cli(cmd, options = {}) {
const args = cmd.replace('gitbeaker', '').trim();
const binary = resolve(__dirname, '..', '..', pkg.bin.gitbeaker);
return execP(`node ${binary} ${args}`, options);
}
describe('General', () => {
it('should return the expose a gitbeaker commnad', async () => {
expect(pkg.bin).toHaveProperty('gitbeaker');
});
});
describe('gitbeaker -g -- CLI global Enviroment Variables', () => {
it('should return an object of available gitbeaker cli environment variables', async () => {
const { stdout } = await cli('gitbeaker -g');
expect(strip(stdout)).toBe('No global variables have been set!\n');
});
it('should only have the personal token set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_TOKEN: 'gbfaketoken' },
});
expect(JSON.parse(stdout)['gb-token'].value).toBe('gbfaketoken');
});
it('should only have the personal token set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_TOKEN: 'glfaketoken' },
});
expect(JSON.parse(stdout)['gb-token'].value).toBe('glfaketoken');
});
it('should only have the oauth token set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_OAUTH_TOKEN: 'gboafaketoken' },
});
expect(JSON.parse(stdout)['gb-oauth-token'].value).toBe('gboafaketoken');
});
it('should only have the oauth token set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_OAUTH_TOKEN: 'gloafaketoken' },
});
expect(JSON.parse(stdout)['gb-oauth-token'].value).toBe('gloafaketoken');
});
it('should only have the job token set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_JOB_TOKEN: 'gbjfaketoken' },
});
expect(JSON.parse(stdout)['gb-job-token'].value).toBe('gbjfaketoken');
});
it('should only have the job token set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_JOB_TOKEN: 'gljfaketoken' },
});
expect(JSON.parse(stdout)['gb-job-token'].value).toBe('gljfaketoken');
});
it('should only have the host set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_HOST: 'www.gbfakehost.com' },
});
expect(JSON.parse(stdout)['gb-host'].value).toBe('www.gbfakehost.com');
});
it('should only have the host set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_HOST: 'www.ghfakehost.com' },
});
expect(JSON.parse(stdout)['gb-host'].value).toBe('www.ghfakehost.com');
});
it('should only have the version set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_VERSION: '4' },
});
expect(JSON.parse(stdout)['gb-version'].value).toBe(4);
});
it('should only have the version set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_VERSION: '4' },
});
expect(JSON.parse(stdout)['gb-version'].value).toBe(4);
});
it('should only have sudo set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_SUDO: 'gbsudoaccount' },
});
expect(JSON.parse(stdout)['gb-sudo'].value).toBe('gbsudoaccount');
});
it('should only have sudo set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_SUDO: 'glsudoaccount' },
});
expect(JSON.parse(stdout)['gb-sudo'].value).toBe('glsudoaccount');
});
it('should only have the camelize set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_CAMELIZE: 'true' },
});
expect(JSON.parse(stdout)['gb-camelize'].value).toBe(true);
});
it('should only have the camelize set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_CAMELIZE: 'true' },
});
expect(JSON.parse(stdout)['gb-camelize'].value).toBe(true);
});
it('should only have the profile token set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_PROFILE_TOKEN: 'gbptoken' },
});
expect(JSON.parse(stdout)['gb-profile-token'].value).toBe('gbptoken');
});
it('should only have the profile token set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_PROFILE_TOKEN: 'glptoken' },
});
expect(JSON.parse(stdout)['gb-profile-token'].value).toBe('glptoken');
});
it('should only have the profile mode set', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITBEAKER_PROFILE_MODE: 'gbpmode' },
});
expect(JSON.parse(stdout)['gb-profile-mode'].value).toBe('gbpmode');
});
it('should only have the profile mode set by alias', async () => {
const { stdout } = await cli('gitbeaker -g', {
env: { ...process.env, GITLAB_PROFILE_MODE: 'glpmode' },
});
expect(JSON.parse(stdout)['gb-profile-mode'].value).toBe('glpmode');
});
});
describe('gitbeaker -v -- Package Version', () => {
it('should return the current version number of the package', async () => {
const { stdout } = await cli('gitbeaker -v');
expect(stdout.trim()).toBe(pkg.version);
});
});
describe('gitbeaker projects create', () => {
it('should create a valid project using configuration from environment variables', async () => {
const { stdout } = await cli('gitbeaker projects create --name="Project Creation CLI test1"', {
env: {
...process.env,
GITBEAKER_HOST: process.env.GITLAB_URL,
GITBEAKER_TOKEN: process.env.PERSONAL_ACCESS_TOKEN,
},
});
expect(JSON.parse(stdout).name).toEqual('Project Creation CLI test1');
});
it('should create a valid project using configuration passed in arguments', async () => {
const { stdout } = await cli(
`gitbeaker projects create --gl-token=${process.env.PERSONAL_ACCESS_TOKEN} --gb-host=${process.env.GITLAB_URL} --name="Project Creation CLI test2"`,
);
expect(JSON.parse(stdout).name).toEqual('Project Creation CLI test2');
});
it('should create a valid project using configuration passed in arguments and defined in the environment variables', async () => {
process.env.GITLAB_HOST = process.env.GITLAB_URL;
const { stdout } = await cli(
`
gitbeaker projects create --gb-token=${process.env.PERSONAL_ACCESS_TOKEN} --name="Project Creation CLI test3"`,
{
env: {
...process.env,
GITLAB_HOST: process.env.GITLAB_URL,
},
},
);
expect(JSON.parse(stdout).name).toEqual('Project Creation CLI test3');
});
it('should create a valid project using configuration passed in arguments, overriding those defined in the environment variables', async () => {
const { stdout } = await cli(
`
gitbeaker projects create --gb-host=${process.env.GITLAB_URL} --gb-token=${process.env.PERSONAL_ACCESS_TOKEN} --name="Project Creation CLI test4"`,
{
env: {
...process.env,
GITLAB_TOKEN: 'faketoken',
},
},
);
expect(JSON.parse(stdout).name).toEqual('Project Creation CLI test4');
});
});
describe('gitbeaker projects all', () => {
it('should create a valid project using configuration from environment variables', async () => {
const env = {
...process.env,
GITBEAKER_HOST: process.env.GITLAB_URL,
GITBEAKER_TOKEN: process.env.PERSONAL_ACCESS_TOKEN,
};
// Create a project first
await cli('gitbeaker projects create --name="Project Creation CLI all1"', {
env,
});
// Get all projects
const { stdout } = await cli('gitbeaker projects all --simple=true', {
env,
});
const found = JSON.parse(stdout).some((p) => p.name === 'Project Creation CLI all1');
expect(found).toBeTruthy();
});
});

View File

@ -0,0 +1,279 @@
import { Projects } from '@gitbeaker/node';
import pkg from '../../package.json';
import { cli } from '../../src/cli';
jest.mock('@gitbeaker/node');
jest.mock('ora', () => ({
start: () => ({
success: jest.fn(),
fail: jest.fn(),
}),
}));
const OLD_ENV = process.env;
beforeEach(() => {
process.env = { ...OLD_ENV };
Projects.mockClear();
});
afterEach(() => {
process.env = OLD_ENV;
});
describe('General', () => {
it('should return the expose a gitbeaker commnad', async () => {
expect(pkg.bin).toHaveProperty('gitbeaker');
});
});
describe('gitbeaker -g -- CLI global Enviroment Variables', () => {
let gcli;
beforeEach(() => {
// eslint-disable-next-line
({ cli: gcli } = require('../../src/cli'));
});
it('should return an object of available gitbeaker cli.parse environment variables -- --global-args alias', async () => {
const result = await gcli.parse('-g');
expect(result.output).toBe('No global variables have been set!');
});
it('should return an object of available gitbeaker cli.parse environment variables -- -g alias', async () => {
const { output } = await gcli.parse('-g');
expect(output).toBe('No global variables have been set!');
});
it('should only have the personal token set', async () => {
process.env.GITBEAKER_TOKEN = 'token1';
const { output } = await gcli.parse('-g');
expect(JSON.parse(output)['gb-token'].value).toBe('token1');
});
it('should only have the personal token set by alias', async () => {
process.env.GITLAB_TOKEN = 'glfaketoken';
const { output } = await gcli.parse('-g');
expect(JSON.parse(output)['gb-token'].value).toBe('glfaketoken');
});
it('should only have the oauth token set', async () => {
process.env.GITBEAKER_OAUTH_TOKEN = 'gboafaketoken';
const { output } = await gcli.parse('-g');
expect(JSON.parse(output)['gb-oauth-token'].value).toBe('gboafaketoken');
});
it('should only have the oauth token set by alias', async () => {
process.env.GITLAB_OAUTH_TOKEN = 'gloafaketoken';
const { output } = await gcli.parse('-g');
expect(JSON.parse(output)['gb-oauth-token'].value).toBe('gloafaketoken');
});
// it('should only have the job token set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_JOB_TOKEN: 'gbjfaketoken' },
// });
// expect(JSON.parse(output)['gb-job-token'].value).toBe('gbjfaketoken');
// });
// it('should only have the job token set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_JOB_TOKEN: 'gljfaketoken' },
// });
// expect(JSON.parse(output)['gb-job-token'].value).toBe('gljfaketoken');
// });
// it('should only have the host set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_HOST: 'www.gbfakehost.com' },
// });
// expect(JSON.parse(output)['gb-host'].value).toBe('www.gbfakehost.com');
// });
// it('should only have the host set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_HOST: 'www.ghfakehost.com' },
// });
// expect(JSON.parse(output)['gb-host'].value).toBe('www.ghfakehost.com');
// });
// it('should only have the version set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_VERSION: '4' },
// });
// expect(JSON.parse(output)['gb-version'].value).toBe(4);
// });
// it('should only have the version set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_VERSION: '4' },
// });
// expect(JSON.parse(output)['gb-version'].value).toBe(4);
// });
// it('should only have sudo set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_SUDO: 'gbsudoaccount' },
// });
// expect(JSON.parse(output)['gb-sudo'].value).toBe('gbsudoaccount');
// });
// it('should only have sudo set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_SUDO: 'glsudoaccount' },
// });
// expect(JSON.parse(output)['gb-sudo'].value).toBe('glsudoaccount');
// });
// it('should only have the camelize set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_CAMELIZE: 'true' },
// });
// expect(JSON.parse(output)['gb-camelize'].value).toBe(true);
// });
// it('should only have the camelize set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_CAMELIZE: 'true' },
// });
// expect(JSON.parse(output)['gb-camelize'].value).toBe(true);
// });
// it('should only have the profile token set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_PROFILE_TOKEN: 'gbptoken' },
// });
// expect(JSON.parse(output)['gb-profile-token'].value).toBe('gbptoken');
// });
// it('should only have the profile token set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_PROFILE_TOKEN: 'glptoken' },
// });
// expect(JSON.parse(output)['gb-profile-token'].value).toBe('glptoken');
// });
// it('should only have the profile mode set', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITBEAKER_PROFILE_MODE: 'gbpmode' },
// });
// expect(JSON.parse(output)['gb-profile-mode'].value).toBe('gbpmode');
// });
// it('should only have the profile mode set by alias', async () => {
// const { output } = await cli.parse('gitbeaker -g', {
// env: { ...process.env, GITLAB_PROFILE_MODE: 'glpmode' },
// });
// expect(JSON.parse(output)['gb-profile-mode'].value).toBe('glpmode');
// });
});
describe('gitbeaker -v -- Package Version', () => {
it('should return the current version number of the package', async () => {
const { output } = await cli.parse('-v');
expect(output).toBe(pkg.version);
});
});
describe('gitbeaker projects create', () => {
beforeEach(() => {
process.env.GITBEAKER_HOST = 'host';
process.env.GITBEAKER_TOKEN = 'token';
});
it('should create a valid project using configuration from environment variables', async () => {
await cli.parse('projects create --name="Project Creation CLI test"');
expect(Projects).toHaveBeenCalledWith({
host: 'host',
token: 'token',
camelize: false,
});
expect(Projects.mock.instances[0].create).toHaveBeenCalledWith({
name: 'Project Creation CLI test',
});
});
it('should create a valid project using configuration passed in arguments', async () => {
await cli.parse(
'projects create --gb-token=token1 --gb-host=host1 --name="Project Creation CLI test1"',
);
expect(Projects).toHaveBeenCalledWith({
host: 'host1',
token: 'token1',
camelize: false,
});
expect(Projects.mock.instances[0].create).toHaveBeenCalledWith({
name: 'Project Creation CLI test1',
});
});
it('should create a valid project using configuration passed in arguments and defined in the environment variables', async () => {
await cli.parse('projects create --gb-token=token2 --name="Project Creation CLI test2"');
expect(Projects).toHaveBeenCalledWith({
host: 'host',
token: 'token2',
camelize: false,
});
expect(Projects.mock.instances[0].create).toHaveBeenCalledWith({
name: 'Project Creation CLI test2',
});
});
it('should create a valid project using configuration passed in arguments, overriding those defined in the environment variables', async () => {
await cli.parse(
'projects create --gb-token=token3 --gb-host=host3 --name="Project Creation CLI test3"',
);
expect(Projects).toHaveBeenCalledWith({
host: 'host3',
token: 'token3',
camelize: false,
});
expect(Projects.mock.instances[0].create).toHaveBeenCalledWith({
name: 'Project Creation CLI test3',
});
});
});
describe('gitbeaker projects all', () => {
it('should create a valid project using configuration from environment variables', async () => {
await cli.parse('projects all --simple=true');
expect(Projects.mock.instances[0].all).toHaveBeenCalledWith({
simple: 'true',
});
});
});

View File

@ -9,21 +9,21 @@
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/requester-utils": "^19.7.0",
"@gitbeaker/requester-utils": "19.7.0",
"form-data": "^3.0.0",
"li": "^1.3.0",
"xcase": "^2.0.1"
},
"devDependencies": {
"@types/node": "^14.0.1",
"@types/node": "^14.0.6",
"esm": "^3.2.25",
"fs-extra": "^9.0.0",
"get-param-names": "github:jdalrymple/get-param-names#1-improve-functionality",
"rollup": "^2.6.1",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"ts-node": "^8.9.0",
"typescript": "^3.8.3"
"rollup": "^2.12.0",
"rollup-plugin-terser": "^6.1.0",
"rollup-plugin-typescript2": "^0.27.1",
"ts-node": "^8.10.2",
"typescript": "^3.9.3"
},
"engines": {
"node": ">=10.0.0"

View File

@ -9,20 +9,20 @@
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/core": "^19.7.0",
"@gitbeaker/requester-utils": "^19.7.0",
"@gitbeaker/core": "19.7.0",
"@gitbeaker/requester-utils": "19.7.0",
"form-data": "^3.0.0",
"got": "^11.0.1",
"got": "^11.1.4",
"xcase": "^2.0.1"
},
"devDependencies": {
"@types/node": "^14.0.1",
"openpgp": "^4.10.3",
"rollup": "^2.6.1",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"ts-node": "^8.9.0",
"typescript": "^3.8.3"
"@types/node": "^14.0.6",
"openpgp": "^4.10.4",
"rollup": "^2.12.0",
"rollup-plugin-terser": "^6.1.0",
"rollup-plugin-typescript2": "^0.27.1",
"ts-node": "^8.10.2",
"typescript": "^3.9.3"
},
"engines": {
"node": ">=10.0.0"

View File

@ -2,7 +2,7 @@ import * as Gitbeaker from '@gitbeaker/core';
import { modifyServices } from '@gitbeaker/requester-utils';
import { Requester } from './GotRequester';
const APIServices = modifyServices(Gitbeaker, { requester: Requester });
const APIServices = modifyServices(Gitbeaker, [{ requester: Requester }]);
export const {
// Groups

View File

@ -14,12 +14,12 @@
"xcase": "^2.0.1"
},
"devDependencies": {
"@types/node": "^14.0.1",
"rollup": "^2.6.1",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"ts-node": "^8.9.0",
"typescript": "^3.8.3"
"@types/node": "^14.0.6",
"rollup": "^2.12.0",
"rollup-plugin-terser": "^6.1.0",
"rollup-plugin-typescript2": "^0.27.1",
"ts-node": "^8.10.2",
"typescript": "^3.9.3"
},
"engines": {
"node": ">=10.0.0"

View File

@ -26,10 +26,6 @@ export type DefaultRequestOptions = {
method?: string;
};
export type Constructor<T = {}> = new (...args: any[]) => T;
export type DictionaryOfConstructors<T> = { [K in keyof T]: Constructor<T[K]> };
// Utility methods
export function formatQuery(options) {
return stringify(decamelizeKeys(options || {}) as object, { arrayFormat: 'bracket' });
@ -78,19 +74,27 @@ export function createInstance(optionsHandler, requestHandler): RequesterType {
return requester;
}
export function modifyServices<T>(
services: DictionaryOfConstructors<T>,
customConfig: object,
): DictionaryOfConstructors<T> {
const result: any = {};
export interface Constructable {
new (...args: any[]): any;
}
Object.keys(services).forEach((name: string) => {
result[name] = (args: { [key: string]: any }) =>
new services[name]({
...args,
...customConfig,
});
function extendClass<T extends Constructable>(Base: T, customConfig: object): T {
return class extends Base {
constructor(...options: any[]) {
super({ ...options, ...customConfig });
}
};
}
export function modifyServices<T extends { [name: string]: Constructable }>(
services: T,
customConfig: object,
) {
const updated: { [name: string]: Constructable } = {};
Object.entries(services).forEach(([k, s]) => {
updated[k] = extendClass(s, customConfig);
});
return result;
return updated as T;
}

1225
yarn.lock

File diff suppressed because it is too large Load Diff