refactor: 💡 Migrated to a monorepo structure

Gitbeaker has been split up into 5 subpackages: gitbeaker-core, gitbeaker-node, gitbeaker-cli, gitbeaker-browser and gitbeaker-requester-utils.

gitbeaker-[node,cli,browser] are enviroment
specific sub packages. For example, if you want to use gitbeaker in a NodeJS environment, use gitbeaker-node. gitbeaker-core is where all the
base logic exists, and gitbeaker-requester-utils is a collection of utility functions for making custom requester libraries.

BREAKING CHANGE: 🧨 This migration requires users to import specific subpackages. For NodeJS
usage, that would be @gitbeaker/node.
This commit is contained in:
Justin Dalrymple 2020-02-01 10:55:31 +01:00
parent a66d708c8f
commit d9cd4c9a91
141 changed files with 1743 additions and 386 deletions

View File

@ -0,0 +1,54 @@
{
"name": "@gitbeaker/browser",
"description": "Full Browser implementation of the GitLab API. Supports Promises, Async/Await.",
"version": "15.0.0",
"author": {
"name": "Justin Dalrymple"
},
"bugs": {
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/core": "^15.0.0",
"@gitbeaker/requester-utils": "^15.0.0",
"ky": "^0.16.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^11.0.1",
"@rollup/plugin-node-resolve": "^7.0.0",
"@rollup/plugin-replace": "^2.3.0",
"@types/node": "^13.7.0",
"node-fetch": "^2.6.0",
"rollup": "^1.31.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-terser": "^5.2.0",
"rollup-plugin-typescript2": "^0.25.3",
"ts-node": "^8.6.2",
"typescript": "^3.7.5"
},
"engines": {
"node": ">=10.0.0"
},
"files": [
"dist"
],
"homepage": "https://github.com/jdalrymple/gitbeaker#readme",
"keywords": [
"api",
"es5",
"es6",
"gitlab",
"gitbeaker",
"ky"
],
"license": "MIT",
"browser": "dist/index.js",
"repository": {
"type": "git",
"url": "https://github.com/jdalrymple/gitbeaker"
},
"scripts": {
"build": "tsc && rollup -c"
}
}

View File

@ -0,0 +1,19 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
import pkg from './package.json';
import { commonConfig, commonPlugins } from '../../rollup.config';
export default [
{
...commonConfig,
output: {
file: pkg.browser,
name: 'gitbeaker',
format: 'umd',
exports: 'named',
},
plugins: [globals(), builtins(), resolve({ browser: true }), commonjs(), ...commonPlugins],
},
];

View File

@ -0,0 +1,66 @@
import Ky from 'ky';
import {
Service,
DefaultRequestOptions,
createInstance,
defaultRequest as baseDefaultRequest,
} from '@gitbeaker/requester-utils';
function responseHeadersAsObject(response): Record<string, string> {
const headers = {};
const keyVals = [...response.headers.entries()];
keyVals.forEach(([key, val]) => {
headers[key] = val;
});
return headers;
}
export function defaultRequest(service: Service, options: DefaultRequestOptions = {}) {
const opts = baseDefaultRequest(service, options);
return { ...opts, headers: new Headers(service.headers as Record<string, string>) };
}
export function processBody(response) {
const contentType = response.headers.get('content-type') || '';
switch (contentType) {
case 'application/json': {
return response.json().then(v => v || {});
}
case 'application/octet-stream':
case 'binary/octet-stream':
case 'application/gzip': {
return response.blob().then(Buffer.from);
}
default: {
return response.text().then(t => t || '');
}
}
}
export async function handler(endpoint, options) {
let response;
try {
response = await Ky(endpoint, options);
} catch (e) {
if (e.response) {
const output = await e.response.json();
e.description = output.error || output.message;
}
throw e;
}
const { status } = response;
const headers = responseHeadersAsObject(response);
const body = await processBody(response);
return { body, headers, status };
}
export const Requester = createInstance(defaultRequest, handler);

View File

@ -0,0 +1,15 @@
import * as Gitbeaker from '@gitbeaker/core';
import { Requester } from './KyRequester';
const output = {};
Object.keys(Gitbeaker).forEach(name => {
output[name] = args =>
new Gitbeaker[name]({
requester: Requester,
...args,
});
});
/* eslint-disable */
export default output;

View File

@ -0,0 +1,176 @@
import ky from 'ky';
import fetch from 'node-fetch';
import { processBody, handler, defaultRequest } from '../../src/KyRequester';
// Set globals for testing purposes
if (!global.fetch) {
global.fetch = fetch;
}
if (!global.Headers) {
global.Headers = fetch.Headers;
}
jest.mock('ky');
describe('processBody', () => {
it('should return a json object if type is application/json', async () => {
const output = await processBody({
json() {
return Promise.resolve({ test: 5 });
},
headers: {
get() {
return 'application/json';
},
},
});
expect(output).toMatchObject({ test: 5 });
});
it('should return a buffer if type is octet-stream, binary, or gzip', async () => {
const output = [
processBody({
blob() {
return Promise.resolve('test');
},
headers: {
get() {
return 'application/octet-stream';
},
},
}),
processBody({
blob() {
return Promise.resolve('test');
},
headers: {
get() {
return 'binary/octet-stream';
},
},
}),
processBody({
blob() {
return Promise.resolve('test');
},
headers: {
get() {
return 'application/gzip';
},
},
}),
];
const fulfilled = await Promise.all(output);
fulfilled.forEach(o => expect(o).toBeInstanceOf(Buffer));
});
it('should return a text body given when presented with an unknown content-type', async () => {
const output = await processBody({
text() {
return Promise.resolve('6');
},
headers: {
get() {
return 'fake';
},
},
});
expect(output).toBe('6');
});
it('should return a empty string when presented with an unknown content-type and undefined body', async () => {
const output = await processBody({
text() {
return Promise.resolve(null);
},
headers: {
get() {
return 'fake';
},
},
});
expect(output).toBe('');
});
});
describe('handler', () => {
it('should return an error with a description when response has an error prop', async () => {
ky.mockImplementationOnce(() => {
const e = {
response: {
json() {
return Promise.resolve({ error: 'msg' });
},
},
};
return Promise.reject(e);
});
await expect(handler('http://test.com', {})).rejects.toContainEntry(['description', 'msg']);
});
it('should return an error with a description when response has an message prop', async () => {
ky.mockImplementationOnce(() => {
const e = {
response: {
json() {
return Promise.resolve({ message: 'msg' });
},
},
};
return Promise.reject(e);
});
await expect(handler('http://test.com', {})).rejects.toContainEntry(['description', 'msg']);
});
it('should return correct properties if request is valid', async () => {
ky.mockImplementationOnce(() => ({
status: 404,
headers: {
get() {
return 'application/json';
},
entries() {
return [['token', '1234']];
},
},
json() {
return Promise.resolve({});
},
}));
const output = await handler('http://test.com', {});
expect(output).toMatchObject({
body: {},
headers: {},
status: 404,
});
});
});
describe('defaultRequest', () => {
const service = {
headers: { test: '5' },
url: 'testurl',
rejectUnauthorized: false,
requestTimeout: 50,
};
it('should stringify body if it isnt of type FormData', async () => {
const testBody = { test: 6 };
const { body, headers } = defaultRequest(service, {
body: testBody,
});
expect(headers).toBeInstanceOf(Headers);
expect(body).toBe(JSON.stringify(testBody));
});
});

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"declaration": true,
"declarationDir": "dist/types"
},
"include": ["src"]
}

View File

@ -0,0 +1,53 @@
{
"name": "@gitbeaker/cli",
"description": "Full NodeJS CLI implementation of the GitLab API.",
"version": "15.0.0",
"author": {
"name": "Justin Dalrymple"
},
"bin": {
"gitbeaker": "dist/index.js"
},
"bugs": {
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/core": "15.0.0",
"@gitbeaker/node": "15.0.0",
"chalk": "^3.0.0",
"ora": "^4.0.3",
"sywac": "^1.2.2",
"xcase": "^2.0.1"
},
"devDependencies": {
"@rollup/plugin-json": "^4.0.1",
"rollup": "^1.31.0",
"rollup-plugin-preserve-shebangs": "^0.1.2",
"rollup-plugin-terser": "^5.2.0",
"rollup-plugin-typescript2": "^0.25.3",
"strip-ansi": "^6.0.0",
"typescript": "^3.7.5"
},
"engines": {
"node": ">=10.0.0"
},
"files": [
"dist"
],
"homepage": "https://github.com/jdalrymple/gitbeaker#readme",
"keywords": [
"api",
"cli",
"gitbeaker",
"gitlab",
"got"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/jdalrymple/gitbeaker"
},
"scripts": {
"build": "tsc && rollup -c"
}
}

View File

@ -0,0 +1,14 @@
import json from '@rollup/plugin-json';
import { preserveShebangs } from 'rollup-plugin-preserve-shebangs';
import pkg from './package.json';
import { commonConfig, commonPlugins } from '../../rollup.config.js';
export default {
...commonConfig,
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})],
output: {
file: pkg.bin.gitbeaker,
format: 'cjs',
},
plugins: [...commonPlugins, json(), preserveShebangs()],
};

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src"]
}

View File

@ -0,0 +1,54 @@
{
"name": "@gitbeaker/core",
"description": "Core API implementation of the GitLab API. Supports Promises, Async/Await.",
"version": "15.0.0",
"author": {
"name": "Justin Dalrymple"
},
"bugs": {
"url": "https://github.com/jdalrymple/gitbeaker/issues"
},
"dependencies": {
"@gitbeaker/requester-utils": "15.0.0",
"form-data": "^3.0.0",
"li": "^1.3.0",
"xcase": "^2.0.1"
},
"devDependencies": {
"@types/node": "^13.7.0",
"esm": "^3.2.25",
"fs-extra": "^8.1.0",
"get-param-names": "github:jdalrymple/get-param-names#1-improve-functionality",
"rollup": "^1.31.0",
"rollup-plugin-terser": "^5.2.0",
"rollup-plugin-typescript2": "^0.25.3",
"ts-node": "^8.6.2",
"typescript": "^3.7.5"
},
"engines": {
"node": ">=10.0.0"
},
"files": [
"dist"
],
"homepage": "https://github.com/jdalrymple/gitbeaker#readme",
"keywords": [
"api",
"es5",
"es6",
"gitlab"
],
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.es.js",
"repository": {
"type": "git",
"url": "https://github.com/jdalrymple/gitbeaker"
},
"scripts": {
"build:self": "tsc && rollup -c",
"build": "yarn run generate-map && yarn run build:self",
"generate-map": "ESM_DISABLE_CACHE=true TS_NODE_PROJECT=scripts/tsconfig.json node -r esm -r ts-node/register scripts/generate.ts"
},
"types": "dist/types/index.d.ts"
}

View File

@ -0,0 +1,18 @@
import pkg from './package.json';
import { commonConfig, commonPlugins } from '../../rollup.config';
export default {
...commonConfig,
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})],
output: [
{
file: pkg.main, // CommonJS (for Node) (for bundlers) build.
format: 'cjs',
},
{
file: pkg.module, // ES module (for bundlers) build.
format: 'es',
},
],
plugins: commonPlugins,
};

View File

@ -1,7 +1,7 @@
import getParamNames from 'get-param-names';
import { outputJsonSync, removeSync } from 'fs-extra';
import * as core from '../core';
import { BaseService } from '../core/infrastructure';
import { outputJsonSync } from 'fs-extra';
import * as Gitbeaker from '../src';
import { BaseService } from '../src/infrastructure';
function isGetter(x, name) {
return (Object.getOwnPropertyDescriptor(x, name) || {}).get;
@ -39,10 +39,10 @@ function buildMap() {
const map = {};
const baseArgs = Object.keys(getParamNames(BaseService)[0]);
for (const [name, service] of Object.entries(core)) {
for (const [name, service] of Object.entries(Gitbeaker as object)) {
if (name.includes('Bundle') || name === 'Gitlab') continue;
const s = new service();
const s = new service({ requester: {} });
map[name] = [{ name: 'constructor', args: baseArgs }];
@ -59,5 +59,3 @@ function buildMap() {
// Generate the services map
outputJsonSync('./dist/map.json', buildMap());
removeSync('./temp');

View File

@ -1,8 +1,6 @@
{
"files": ["src/bin/generate.ts"],
"compilerOptions": {
"esModuleInterop": true,
"outDir": "temp",
"allowJs": true,
"target": "es6",
"module": "esnext",

View File

@ -1,9 +1,11 @@
import { bundler } from './infrastructure';
import * as APIServices from './services';
// All separately
/* -------------- Single Services ------------- */
export * from './services';
/* ------------------ Bundles ----------------- */
// Groups
export const GroupsBundle = bundler({
Groups: APIServices.Groups,
@ -81,12 +83,13 @@ export const ProjectsBundle = bundler({
Services: APIServices.Services,
Tags: APIServices.Tags,
Triggers: APIServices.Triggers,
VulnerabilityFindings: APIServices.VulnerabilityFindings,
});
// All initialized
export const Gitlab = bundler(APIServices);
// Types
/* ---------------- Bundles Types-------------- */
export type UsersBundle = InstanceType<typeof UsersBundle>;
export type GroupsBundle = InstanceType<typeof GroupsBundle>;
export type ProjectsBundle = InstanceType<typeof ProjectsBundle>;

View File

@ -1,12 +1,4 @@
import { KyRequester } from './KyRequester';
export interface Requester {
get: Function;
post: Function;
put: Function;
delete: Function;
stream?: Function;
}
import { RequesterType } from '@gitbeaker/requester-utils';
export interface BaseServiceOptions {
oauthToken?: string;
@ -17,7 +9,7 @@ export interface BaseServiceOptions {
version?: 3 | 4;
rejectUnauthorized?: boolean;
camelize?: boolean;
requester?: Requester;
requester?: RequesterType;
requestTimeout?: number;
profileToken?: string;
sudo?: string | number;
@ -27,7 +19,7 @@ export interface BaseServiceOptions {
export class BaseService {
public readonly url: string;
public readonly requester: Requester;
public readonly requester: RequesterType;
public readonly requestTimeout: number;
@ -43,17 +35,21 @@ export class BaseService {
oauthToken,
sudo,
profileToken,
requester,
profileMode = 'execution',
host = 'https://gitlab.com',
url = '',
version = 4,
camelize = false,
rejectUnauthorized = true,
requester = KyRequester as Requester,
requestTimeout = 300000,
}: BaseServiceOptions = {}) {
if (!requester) throw new ReferenceError('Requester must be passed');
this.url = [host, 'api', `v${version}`, url].join('/');
this.headers = {};
this.headers = {
'user-agent': 'gitbeaker',
};
this.rejectUnauthorized = rejectUnauthorized;
this.camelize = camelize;
this.requester = requester;
@ -67,8 +63,7 @@ export class BaseService {
// Profiling
if (profileToken) {
this.headers['X-Profile-Token'] = profileToken;
if (profileMode) this.headers['X-Profile-Mode'] = profileMode;
this.headers['X-Profile-Mode'] = profileMode;
}
// Set sudo

View File

@ -6,6 +6,10 @@ export interface Sudo {
sudo?: string | number;
}
export interface ShowExpanded {
showExpanded?: boolean;
}
export interface PaginationOptions {
total: number;
next: number | null;
@ -20,31 +24,40 @@ export interface BaseRequestOptions extends Sudo {
[key: string]: any;
}
export interface PaginatedRequestOptions extends BaseRequestOptions {
showPagination?: boolean;
export interface PaginatedRequestOptions extends BaseRequestOptions, ShowExpanded {
maxPages?: number;
page?: number;
perPage?: number;
}
export type PaginationResponse = { data: object[]; pagination: PaginationOptions };
export type GetResponse = PaginationResponse | object | object[];
export type PostResponse = object;
export type PutResponse = object;
export type DelResponse = object;
export interface ExpandedResponse {
data: object;
headers: object;
status: number;
}
export interface PaginationResponse {
data: object[];
pagination: PaginationOptions;
}
export type GetResponse = PaginationResponse | ExpandedResponse | object | object[];
export type PostResponse = ExpandedResponse | object;
export type PutResponse = ExpandedResponse | object;
export type DelResponse = ExpandedResponse | object;
async function get(
service: BaseService,
endpoint: string,
options: PaginatedRequestOptions = {},
): Promise<GetResponse> {
const { showPagination, maxPages, sudo, ...query } = options;
const { showExpanded, maxPages, sudo, ...query } = options;
const response = await service.requester.get(service, endpoint, {
query: query || {},
sudo,
});
const { headers } = response;
const { headers, status } = response;
let { body } = response;
let pagination = {
total: parseInt(headers['x-total'], 10),
@ -68,14 +81,27 @@ async function get(
const more = (await get(service, next.replace(regex, ''), {
maxPages,
sudo,
showPagination: true,
showExpanded: true,
})) as PaginationResponse;
pagination = more.pagination;
body = [...body, ...more.data];
}
return (query.page || body.length > 0) && showPagination ? { data: body, pagination } : body;
// If expanded version is not requested, return body
if (!showExpanded) return body;
// Else build the expanded response
const output = { data: body } as Record<string, any>;
if (body.length > 0 || query.page) {
output.pagination = pagination;
} else {
output.headers = headers;
output.status = status;
}
return output;
}
function stream(service: BaseService, endpoint: string, options: BaseRequestOptions = {}) {
@ -93,14 +119,14 @@ async function post(
endpoint: string,
options: BaseRequestOptions = {},
): Promise<PostResponse> {
const { sudo, form, ...body } = options;
const { sudo, form, showExpanded, ...body } = options;
const response = await service.requester.post(service, endpoint, {
const r = await service.requester.post(service, endpoint, {
body: form || body,
sudo,
});
return response.body;
return showExpanded ? { data: r.body, status: r.status, headers: r.headers } : r.body;
}
async function put(
@ -108,13 +134,13 @@ async function put(
endpoint: string,
options: BaseRequestOptions = {},
): Promise<PutResponse> {
const { sudo, ...body } = options;
const response = await service.requester.put(service, endpoint, {
const { sudo, showExpanded, ...body } = options;
const r = await service.requester.put(service, endpoint, {
body,
sudo,
});
return response.body;
return showExpanded ? { data: r.body, status: r.status, headers: r.headers } : r.body;
}
async function del(
@ -122,13 +148,13 @@ async function del(
endpoint: string,
options: BaseRequestOptions = {},
): Promise<DelResponse> {
const { sudo, ...query } = options;
const response = await service.requester.delete(service, endpoint, {
const { sudo, showExpanded, ...query } = options;
const r = await service.requester.delete(service, endpoint, {
query,
sudo,
});
return response.body;
return showExpanded ? { data: r.body, status: r.status, headers: r.headers } : r.body;
}
export const RequestHelper = {

View File

@ -1,5 +1,4 @@
/* eslint @typescript-eslint/no-explicit-any: 0 */
interface Constructor {
new (...args: any): any;
}
@ -19,3 +18,12 @@ export function bundler<T extends { [name: string]: Constructor }, P extends key
});
} as any) as Bundle<T, P>;
}
export function appendFormFromObject(object) {
const form = new FormData();
Object.entries(object).forEach(([k, v]) => {
if (Array.isArray(v)) form.append(k, v[0], v[1]);
else form.append(k, v as any);
});
}

View File

@ -1,4 +1,3 @@
export * from './BaseService';
export { bundler } from './Utils';
export { KyRequester } from './KyRequester';
export * from './RequestHelper';

View File

@ -2,7 +2,7 @@ import { ResourceDiscussions } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class CommitDiscussions extends ResourceDiscussions {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'commits', options);
}
}

View File

@ -6,6 +6,39 @@ import {
Sudo,
} from '../infrastructure';
export type CommitSchema = CommitSchemaDefault | CommitSchemaCamelized;
// As of GitLab v12.6.2
export interface CommitSchemaDefault {
id: string;
short_id: string;
created_at: Date;
parent_ids?: string[];
title: string;
message: string;
author_name: string;
author_email: string;
authored_date?: Date;
committer_name?: string;
committer_email?: string;
committed_date?: Date;
}
export interface CommitSchemaCamelized {
id: string;
shortId: string;
createdAt: Date;
parentIds?: string[];
title: string;
message: string;
authorName: string;
authorEmail: string;
authoredDate?: Date;
committerName?: string;
committerEmail?: string;
committedDate?: Date;
}
interface CommitAction {
/** The action to perform */
action: 'create' | 'delete' | 'move' | 'update';

View File

@ -0,0 +1,73 @@
import { BaseService, RequestHelper, PaginatedRequestOptions, Sudo } from '../infrastructure';
import { CommitSchema } from './Commits';
import { PipelineSchema } from './Pipelines';
import { UserSchema } from './Users';
import { RunnerSchema } from './Runners';
export type DeploymentStatus = 'created' | 'running' | 'success' | 'failed' | 'canceled';
// Ref: https://docs.gitlab.com/12.6/ee/api/deployments.html#list-project-deployments
export interface DeploymentSchema {
id: number;
iid: number;
ref: string;
sha: string;
user: UserSchema;
}
export type Deployable = DeployableDefault | DeployableCamelized;
export interface DeployableDefault {
id: number;
ref: string;
name: string;
runner?: RunnerSchema;
stage?: string;
started_at?: Date;
status?: DeploymentStatus;
tag: boolean;
commit?: CommitSchema;
coverage?: string;
created_at?: Date;
finished_at?: Date;
user?: UserSchema;
pipeline?: PipelineSchema;
}
export interface DeployableCamelized {
id: number;
ref: string;
name: string;
runner?: RunnerSchema;
stage?: string;
startedAt?: Date;
status?: DeploymentStatus;
tag: boolean;
commit?: CommitSchema;
coverage?: string;
createdAt?: Date;
finishedAt?: Date;
user?: UserSchema;
pipeline?: PipelineSchema;
}
export class Deployments extends BaseService {
all(projectId: string | number, options?: PaginatedRequestOptions) {
const pId = encodeURIComponent(projectId);
return RequestHelper.get(this, `projects/${pId}/deployments`, options);
}
show(projectId: string | number, deploymentId: number, options?: Sudo) {
const [pId, dId] = [projectId, deploymentId].map(encodeURIComponent);
return RequestHelper.get(this, `projects/${pId}/deployments/${dId}`, options);
}
mergeRequests(projectId: string | number, deploymentId: number, options?: Sudo) {
const [pId, dId] = [projectId, deploymentId].map(encodeURIComponent);
return RequestHelper.get(this, `projects/${pId}/deployments/${dId}/merge_requests`, options);
}
}

View File

@ -5,18 +5,62 @@ import {
RequestHelper,
Sudo,
} from '../infrastructure';
import { DeploymentSchema } from './Deployments';
import { ProjectSchemaDefault, ProjectSchemaCamelized } from './Projects';
// ref: https://docs.gitlab.com/12.6/ee/api/environments.html#list-environments
export type EnvironmentSchema = EnvironmentSchemaDefault | EnvironmentSchemaCamelized;
export interface EnvironmentSchemaDefault {
id: number;
name: string;
slug?: string;
external_url?: string;
project?: ProjectSchemaDefault;
state?: string;
}
export interface EnvironmentSchemaCamelized {
id: number;
name: string;
slug?: string;
externalUrl?: string;
project?: ProjectSchemaCamelized;
state?: string;
}
export type EnvironmentDetailSchema =
| EnvironmentDetailSchemaDefault
| EnvironmentDetailSchemaCamelized;
export interface EnvironmentDetailSchemaDefault extends EnvironmentSchemaDefault {
last_deployment?: DeploymentSchema;
deployable?: DeploymentSchema;
}
export interface EnvironmentDetailSchemaCamelized extends EnvironmentSchemaCamelized {
lastDeployment?: DeploymentSchema;
deployable?: DeploymentSchema;
}
export class Environments extends BaseService {
all(projectId: string | number, options?: PaginatedRequestOptions) {
all(projectId: string | number, options?: PaginatedRequestOptions): Promise<EnvironmentSchema[]> {
const pId = encodeURIComponent(projectId);
return RequestHelper.get(this, `projects/${pId}/environments`, options);
return RequestHelper.get(this, `projects/${pId}/environments`, options) as Promise<
EnvironmentSchema[]
>;
}
show(projectId: string | number, environmentId: number, options?: Sudo) {
show(
projectId: string | number,
environmentId: number,
options?: Sudo,
): Promise<EnvironmentDetailSchema> {
const [pId, eId] = [projectId, environmentId].map(encodeURIComponent);
return RequestHelper.get(this, `projects/${pId}/environments/${eId}`, options);
return RequestHelper.get(this, `projects/${pId}/environments/${eId}`, options) as Promise<
EnvironmentDetailSchema
>;
}
create(projectId: string | number, options?: BaseRequestOptions) {

View File

@ -2,7 +2,7 @@ import { ResourceDiscussions } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class EpicDiscussions extends ResourceDiscussions {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', 'epics', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceNotes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class EpicNotes extends ResourceNotes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', 'epics', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceTemplates } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GitLabCIYMLTemplates extends ResourceTemplates {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('gitlab_ci_ymls', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceTemplates } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GitignoreTemplates extends ResourceTemplates {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('gitignores', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceAccessRequests } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupAccessRequests extends ResourceAccessRequests {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceBadges } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupBadges extends ResourceBadges {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceCustomAttributes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupCustomAttributes extends ResourceCustomAttributes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceIssueBoards } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupIssueBoards extends ResourceIssueBoards {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { BaseServiceOptions } from '../infrastructure';
import { ResourceLabels } from '../templates';
export class GroupLabels extends ResourceLabels {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceMembers } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupMembers extends ResourceMembers {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceMilestones } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupMilestones extends ResourceMilestones {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceVariables } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class GroupVariables extends ResourceVariables {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('groups', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceAwardEmojis } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class IssueAwardEmojis extends ResourceAwardEmojis {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('issues', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceDiscussions } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class IssueDiscussions extends ResourceDiscussions {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'issues', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceNotes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class IssueNotes extends ResourceNotes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'issues', options);
}
}

View File

@ -6,6 +6,8 @@ import {
Sudo,
} from '../infrastructure';
type ProjectOrGroup = { projectId: string | number } | { groupId: string | number } | {};
export class Issues extends BaseService {
addSpentTime(projectId: string | number, issueId: number, duration: string, options?: Sudo) {
const [pId, iId] = [projectId, issueId].map(encodeURIComponent);
@ -25,12 +27,7 @@ export class Issues extends BaseService {
});
}
all({
projectId,
groupId,
...options
}: ({ projectId?: string | number } | { groupId?: string | number } | {}) &
PaginatedRequestOptions = {}) {
all({ projectId, groupId, ...options }: ProjectOrGroup & PaginatedRequestOptions = {}) {
let url;
if (projectId) {

View File

@ -1,12 +1,9 @@
import { BaseService, RequestHelper, BaseRequestOptions } from '../infrastructure';
type ProjectOrGroup = { projectId: string | number } | { groupId: string | number } | {};
export class IssuesStatistics extends BaseService {
all({
projectId,
groupId,
...options
}: ({ projectId?: string | number } | { groupId?: string | number } | {}) &
BaseRequestOptions = {}) {
all({ projectId, groupId, ...options }: ProjectOrGroup & BaseRequestOptions = {}) {
let url;
if (projectId) {

View File

@ -5,6 +5,10 @@ import {
RequestHelper,
Sudo,
} from '../infrastructure';
import { CommitSchemaDefault, CommitSchemaCamelized } from './Commits';
import { PipelineSchemaDefault, PipelineSchemaCamelized } from './Pipelines';
import { RunnerSchemaDefault, RunnerSchemaCamelized } from './Runners';
import { UserSchemaDefault, UserSchemaCamelized } from './Users';
export type JobScope =
| 'created'
@ -16,6 +20,70 @@ export type JobScope =
| 'skipped'
| 'manual';
// As of GitLab v12.6.2
export type ArtifactSchema = ArtifactSchemaDefault | ArtifactSchemaCamelized;
export interface ArtifactSchemaDefault {
file_type: string;
size: number;
filename: string;
file_format?: string;
}
export interface ArtifactSchemaCamelized {
fileType: string;
size: number;
filename: string;
fileFormat?: string;
}
// As of GitLab v12.6.2
export type JobSchema = JobSchemaDefault | JobSchemaCamelized;
export interface JobSchemaDefault {
id: number;
status: string;
stage: string;
name: string;
ref: string;
tag: boolean;
coverage?: string;
allow_failure: boolean;
created_at: Date;
started_at?: Date;
finished_at?: Date;
duration?: number;
user: UserSchemaDefault;
commit: CommitSchemaDefault;
pipeline: PipelineSchemaDefault;
web_url: string;
artifacts: ArtifactSchemaDefault[];
runner: RunnerSchemaDefault;
artifacts_expire_at?: Date;
}
export interface JobSchemaCamelized {
id: number;
status: string;
stage: string;
name: string;
ref: string;
tag: boolean;
coverage?: string;
allowFailure: boolean;
createdAt: Date;
startedAt?: Date;
finishedAt?: Date;
duration?: number;
user: UserSchemaCamelized;
commit: CommitSchemaCamelized;
pipeline: PipelineSchemaCamelized;
webUrl: string;
artifacts: ArtifactSchemaCamelized[];
runner: RunnerSchemaCamelized;
artifactsExpireAt?: Date;
}
export class Jobs extends BaseService {
all(projectId: string | number, options?: PaginatedRequestOptions) {
const pId = encodeURIComponent(projectId);

View File

@ -2,7 +2,7 @@ import { BaseServiceOptions } from '../infrastructure';
import { ResourceLabels } from '../templates';
export class Labels extends ResourceLabels {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceTemplates } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class LicenceTemplates extends ResourceTemplates {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('licences', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceAwardEmojis } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class MergeRequestAwardEmojis extends ResourceAwardEmojis {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('merge_requests', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceDiscussions } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class MergeRequestDiscussions extends ResourceDiscussions {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'merge_requests', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceNotes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class MergeRequestNotes extends ResourceNotes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'merge_requests', options);
}
}

View File

@ -141,7 +141,7 @@ export class MergeRequests extends BaseService {
) {
const [pId, mIId] = [projectId, mergerequestIId].map(encodeURIComponent);
return RequestHelper.post(
return RequestHelper.get(
this,
`projects/${pId}/merge_requests/${mIId}/approval_state`,
options,

View File

@ -5,9 +5,31 @@ import {
RequestHelper,
Sudo,
} from '../infrastructure';
import { JobScope } from './Jobs';
// As of GitLab v12.6.2
export type PipelineSchema = PipelineSchemaDefault | PipelineSchemaCamelized;
export interface PipelineSchemaDefault {
id: number;
sha: string;
ref: string;
status: string;
created_at: Date;
updated_at: Date;
web_url: string;
}
export interface PipelineSchemaCamelized {
id: number;
sha: string;
ref: string;
status: string;
createdAt: Date;
updatedAt: Date;
webUrl: string;
}
export class Pipelines extends BaseService {
all(projectId: string | number, options?: PaginatedRequestOptions) {
const pId = encodeURIComponent(projectId);

View File

@ -2,7 +2,7 @@ import { ResourceAccessRequests } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectAccessRequests extends ResourceAccessRequests {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceBadges } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectBadges extends ResourceBadges {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceCustomAttributes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectCustomAttributes extends ResourceCustomAttributes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -23,7 +23,7 @@ export class ProjectImportExport extends BaseService {
const form = new FormData();
const defaultMetadata: UploadMetadata = {
filename: Date.now().toString(),
filename: `${Date.now().toString()}.tar.gz`,
contentType: 'application/octet-stream',
};

View File

@ -2,7 +2,7 @@ import { ResourceIssueBoards } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectIssueBoards extends ResourceIssueBoards {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceMembers } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectMembers extends ResourceMembers {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceMilestones } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectMilestones extends ResourceMilestones {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceAwardEmojis } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectSnippetAwardEmojis extends ResourceAwardEmojis {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('issues', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceDiscussions } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectSnippetDiscussions extends ResourceDiscussions {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'snippets', options);
}
}

View File

@ -2,7 +2,7 @@ import { ResourceNotes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class ProjectSnippetNotes extends ResourceNotes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', 'snippets', options);
}
}

View File

@ -1,8 +1,10 @@
import { ResourceVariables } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export { ResourceVariableSchema } from '../templates';
export class ProjectVariables extends ResourceVariables {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('projects', options);
}
}

View File

@ -9,7 +9,9 @@ import {
import { EventOptions } from './Events';
import { UploadMetadata } from './ProjectImportExport';
export interface NamespaceInfoSchema {
export type NamespaceInfoSchema = NamespaceInfoSchemaDefault | NamespaceInfoSchemaCamelize;
export interface NamespaceInfoSchemaDefault {
id: number;
name: string;
path: string;
@ -17,21 +19,40 @@ export interface NamespaceInfoSchema {
full_path: string;
}
export interface ProjectSchema {
export interface NamespaceInfoSchemaCamelize {
id: number;
name: string;
path: string;
kind: string;
fullPath: string;
}
export type ProjectSchema = ProjectSchemaDefault | ProjectSchemaCamelized;
export interface ProjectSchemaDefault {
id: number;
name: string;
name_with_namespace: string;
path: string;
path_with_namespace: string;
namespace: NamespaceInfoSchema;
ssh_url_to_repo: string;
http_url_to_repo: string;
archived: boolean;
}
export interface ProjectSchemaCamelized {
id: number;
name: string;
nameWithNamespace: string;
path: string;
pathWithNamespace: string;
namespace: NamespaceInfoSchema;
sshUrlToRepo: string;
httpUrlToRepo: string;
archived: boolean;
}
export class Projects extends BaseService {
all(options?: PaginatedRequestOptions) {
return RequestHelper.get(this, 'projects', options);

View File

@ -1,6 +1,8 @@
import { BaseService, RequestHelper, BaseRequestOptions, Sudo } from '../infrastructure';
export interface RepositoryFileSchema {
export type RepositoryFileSchema = RepositoryFileSchemaDefault | RepositoryFileSchemaCamelized;
export interface RepositoryFileSchemaDefault {
file_name: string;
file_path: string;
size: number;
@ -13,6 +15,19 @@ export interface RepositoryFileSchema {
last_commit_id: string;
}
export interface RepositoryFileSchemaCamelized {
fileName: string;
filePath: string;
size: number;
encoding: string;
content: string;
contentSha256: string;
ref: string;
blobId: string;
commitId: string;
lastCommitId: string;
}
export class RepositoryFiles extends BaseService {
create(
projectId: string | number,

View File

@ -6,6 +6,31 @@ import {
Sudo,
} from '../infrastructure';
// As of GitLab v12.6.2
export type RunnerSchema = RunnerSchemaDefault | RunnerSchemaCamelized;
export interface RunnerSchemaDefault {
id: number;
description: string;
ip_address: string;
active: boolean;
is_shared: boolean;
name: string;
online: boolean;
status: string;
}
export interface RunnerSchemaCamelized {
id: number;
description: string;
ipAddress: string;
active: boolean;
isShared: boolean;
name: string;
online: boolean;
status: string;
}
export class Runners extends BaseService {
all({ projectId, ...options }: { projectId: string | number } & PaginatedRequestOptions) {
const url = projectId ? `projects/${encodeURIComponent(projectId)}/runners` : 'runners/all';

View File

@ -2,7 +2,7 @@ import { ResourceCustomAttributes } from '../templates';
import { BaseServiceOptions } from '../infrastructure';
export class UserCustomAttributes extends ResourceCustomAttributes {
constructor(options: BaseServiceOptions) {
constructor(options: BaseServiceOptions = {}) {
super('users', options);
}
}

Some files were not shown because too many files have changed in this diff Show More