Skip to content
Snippets Groups Projects
Commit 52c0cf59 authored by michael.minelli's avatar michael.minelli
Browse files

Move to Gitbeaker

parent 0beeba9c
Branches
Tags
No related merge requests found
Pipeline #30322 failed
Showing with 114 additions and 101 deletions
......@@ -2,10 +2,10 @@ import CommanderCommand from '../../CommanderCommand';
import ora from 'ora';
import AccessesHelper from '../../../helpers/AccessesHelper';
import Assignment from '../../../sharedByClients/models/Assignment';
import GitlabUser from '../../../shared/types/Gitlab/GitlabUser';
import GitlabManager from '../../../managers/GitlabManager';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import Toolbox from '../../../shared/helpers/Toolbox';
import * as Gitlab from '@gitbeaker/rest';
import GlobalHelper from '../../../helpers/GlobalHelper';
import TextStyle from '../../../types/TextStyle';
......@@ -24,7 +24,7 @@ class AssignmentCreateCommand extends CommanderCommand {
}
protected async commandAction(options: { name: string, template?: string, members_id?: Array<number>, members_username?: Array<string>, clone?: string | boolean }): Promise<void> {
let members!: Array<GitlabUser> | false;
let members!: Array<Gitlab.UserSchema> | false;
let templateIdOrNamespace: string | null = null;
let assignment!: Assignment;
......@@ -36,7 +36,7 @@ class AssignmentCreateCommand extends CommanderCommand {
return;
}
members = await GitlabManager.fetchMembers(options);
members = await GlobalHelper.gitlabManager.fetchMembers(options);
if ( !members ) {
return;
}
......@@ -89,7 +89,7 @@ class AssignmentCreateCommand extends CommanderCommand {
if ( options.clone ) {
console.log(TextStyle.BLOCK('Please wait while we are cloning the repository...'));
await GitlabManager.cloneRepository(options.clone, assignment.gitlabCreationInfo.ssh_url_to_repo, undefined, true, 0);
await GlobalHelper.gitlabManager.cloneRepository(options.clone, assignment.gitlabCreationInfo.ssh_url_to_repo, undefined, true, 0);
}
}
}
......
import CommanderCommand from '../../CommanderCommand';
import SessionManager from '../../../managers/SessionManager';
import GitlabManager from '../../../managers/GitlabManager';
import GlobalHelper from '../../../helpers/GlobalHelper';
class AuthTestCommand extends CommanderCommand {
......@@ -14,7 +14,7 @@ class AuthTestCommand extends CommanderCommand {
protected async commandAction(): Promise<void> {
await SessionManager.testSession();
await GitlabManager.testToken();
await GlobalHelper.gitlabManager.testToken();
}
}
......
import CommanderCommand from '../../CommanderCommand';
import GitlabManager from '../../../managers/GitlabManager';
import GitlabUser from '../../../shared/types/Gitlab/GitlabUser';
import chalk from 'chalk';
import ora from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper from '../../../helpers/AccessesHelper';
import Assignment from '../../../sharedByClients/models/Assignment';
import Exercise from '../../../sharedByClients/models/Exercise';
import * as Gitlab from '@gitbeaker/rest';
import GlobalHelper from '../../../helpers/GlobalHelper';
import TextStyle from '../../../types/TextStyle';
......@@ -23,7 +24,7 @@ class ExerciseCreateCommand extends CommanderCommand {
}
protected async commandAction(options: { assignment: string, members_id?: Array<number>, members_username?: Array<string>, clone?: string | boolean }): Promise<void> {
let members!: Array<GitlabUser> | false;
let members!: Array<Gitlab.UserSchema> | false;
let assignment!: Assignment | undefined;
let exercise!: Exercise;
......@@ -35,7 +36,7 @@ class ExerciseCreateCommand extends CommanderCommand {
return;
}
members = await GitlabManager.fetchMembers(options);
members = await GlobalHelper.gitlabManager.fetchMembers(options);
if ( !members ) {
return;
}
......@@ -92,7 +93,7 @@ class ExerciseCreateCommand extends CommanderCommand {
if ( options.clone ) {
console.log(TextStyle.BLOCK('Please wait while we are cloning the repository...'));
await GitlabManager.cloneRepository(options.clone, exercise.gitlabCreationInfo.ssh_url_to_repo, `DojoExercise - ${ exercise.assignmentName }`, true, 0);
await GlobalHelper.gitlabManager.cloneRepository(options.clone, exercise.gitlabCreationInfo.ssh_url_to_repo, `DojoExercise - ${ exercise.assignmentName }`, true, 0);
}
}
}
......
import SessionManager from '../managers/SessionManager';
import GitlabManager from '../managers/GitlabManager';
import GlobalHelper from './GlobalHelper';
class AccessesHelper {
......@@ -11,7 +11,7 @@ class AccessesHelper {
}
if ( testGitlab ) {
return (await GitlabManager.testToken(true)).every(result => result);
return (await GlobalHelper.gitlabManager.testToken(true)).every(result => result);
} else {
return true;
}
......@@ -25,7 +25,7 @@ class AccessesHelper {
}
if ( testGitlab ) {
return (await GitlabManager.testToken(true)).every(result => result);
return (await GlobalHelper.gitlabManager.testToken(true)).every(result => result);
} else {
return true;
}
......
......@@ -67,6 +67,7 @@ complete -f -c dojo
function isHidden(cmd: Command): boolean {
return (cmd as Command & { _hidden: boolean })._hidden;
const isDone: boolean = false;
}
......
import { Command, Option } from 'commander';
import Config from '../config/Config';
import SharedGitlabManager from '../shared/managers/SharedGitlabManager';
import SessionManager from '../managers/SessionManager';
import GitlabManager from '../managers/GitlabManager';
class GlobalHelper {
......@@ -12,6 +15,16 @@ class GlobalHelper {
return command;
}
private readonly refreshTokenFunction = async () => {
await SessionManager.refreshTokens();
return SessionManager.gitlabCredentials.accessToken ?? '';
};
readonly gitlabManager = new GitlabManager('', this.refreshTokenFunction.bind(this));
readonly sharedGitlabManager = new SharedGitlabManager('', this.refreshTokenFunction.bind(this));
}
......
import axios, { AxiosError } from 'axios';
import ora from 'ora';
import ApiRoute from '../sharedByClients/types/Dojo/ApiRoute';
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import { StatusCodes } from 'http-status-codes';
import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig';
import Assignment from '../sharedByClients/models/Assignment';
import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse';
......@@ -9,6 +9,7 @@ import Exercise from '../sharedByClients/models/Exercise';
import GitlabToken from '../shared/types/Gitlab/GitlabToken';
import User from '../sharedByClients/models/User';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import * as Gitlab from '@gitbeaker/rest';
import DojoBackendHelper from '../sharedByClients/helpers/Dojo/DojoBackendHelper';
......@@ -106,7 +107,7 @@ class DojoBackendManager {
}
}
public async createAssignment(name: string, members: Array<GitlabUser>, templateIdOrNamespace: string | null, verbose: boolean = true): Promise<Assignment> {
public async createAssignment(name: string, members: Array<Gitlab.UserSchema>, templateIdOrNamespace: string | null, verbose: boolean = true): Promise<Assignment> {
const spinner: ora.Ora = ora('Creating assignment...');
if ( verbose ) {
......@@ -131,7 +132,7 @@ class DojoBackendManager {
}
}
public async createExercise(assignmentName: string, members: Array<GitlabUser>, verbose: boolean = true): Promise<Exercise> {
public async createExercise(assignmentName: string, members: Array<Gitlab.UserSchema>, verbose: boolean = true): Promise<Exercise> {
const spinner: ora.Ora = ora('Creating exercise...');
if ( verbose ) {
......
import axios from 'axios';
import ora from 'ora';
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import GitlabRoute from '../shared/types/Gitlab/GitlabRoute';
import SharedConfig from '../shared/config/SharedConfig';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import fs from 'fs-extra';
import { spawn } from 'child_process';
import { Gitlab, UserSchema } from '@gitbeaker/rest';
import * as GitlabCore from '@gitbeaker/core';
import { EditNotificationSettingsOptions } from '@gitbeaker/core';
import { GitbeakerRequestError } from '@gitbeaker/requester-utils';
import { StatusCodes } from 'http-status-codes';
import { NotificationSettingSchema } from '@gitbeaker/core/dist';
import GlobalHelper from '../helpers/GlobalHelper';
type getGitlabUser = (param: number | string) => Promise<UserSchema | undefined>
class GitlabManager {
private getApiUrl(route: GitlabRoute): string {
return `${ SharedConfig.gitlab.apiURL }${ route }`;
private api!: GitlabCore.Gitlab<false>;
private readonly refreshTokenFunction?: () => Promise<string>;
setToken(token: string) {
this.api = new Gitlab(Object.assign({
host : SharedConfig.gitlab.URL,
token: token
}));
}
constructor(token: string, refreshTokenFunction?: () => Promise<string>) {
this.refreshTokenFunction = refreshTokenFunction;
this.setToken(token);
}
private async executeGitlabRequest<T>(request: () => Promise<T>, refreshTokenIfNeeded: boolean = true): Promise<T> {
try {
return await request();
} catch ( error ) {
if ( this.refreshTokenFunction && refreshTokenIfNeeded && error instanceof GitbeakerRequestError && error.cause?.response.status === StatusCodes.UNAUTHORIZED ) {
this.setToken(await this.refreshTokenFunction());
return this.executeGitlabRequest(request, false);
} else {
throw error;
}
}
}
public async testToken(verbose: boolean = true): Promise<[ boolean, boolean ]> {
......@@ -83,15 +114,15 @@ class GitlabManager {
return result;
}
public getNotificationSettings() {
return axios.get(this.getApiUrl(GitlabRoute.NOTIFICATION_SETTINGS));
public getNotificationSettings(): Promise<NotificationSettingSchema> {
return this.executeGitlabRequest(() => this.api.NotificationSettings.show());
}
public setNotificationSettings(newSettings: Record<string, string>) {
return axios.put(this.getApiUrl(GitlabRoute.NOTIFICATION_SETTINGS), { params: new URLSearchParams(newSettings) });
public setNotificationSettings(newSettings: EditNotificationSettingsOptions) {
return this.executeGitlabRequest(() => this.api.NotificationSettings.edit(newSettings));
}
private async getGitlabUsers(paramsToSearch: Array<string | number>, paramName: string, verbose: boolean = false, verboseIndent: number = 0): Promise<Array<GitlabUser | undefined>> {
private async getGitlabUsers(paramsToSearch: Array<string | number>, searchFunction: getGitlabUser, verbose: boolean = false, verboseIndent: number = 0): Promise<Array<UserSchema | undefined>> {
try {
return await Promise.all(paramsToSearch.map(async param => {
const spinner: ora.Ora = ora({
......@@ -101,18 +132,14 @@ class GitlabManager {
if ( verbose ) {
spinner.start();
}
const params: { [key: string]: unknown } = {};
params[paramName] = param;
const user = await axios.get<Array<GitlabUser>>(this.getApiUrl(GitlabRoute.USERS_GET), { params: params });
if ( user.data[0] ) {
const gitlabUser = user.data[0];
const user = await searchFunction(param);
if ( user ) {
if ( verbose ) {
spinner.succeed(`${ gitlabUser.username } (${ gitlabUser.id })`);
spinner.succeed(`${ user.username } (${ user.id })`);
}
return gitlabUser;
return user;
} else {
if ( verbose ) {
spinner.fail(`${ param }`);
......@@ -126,30 +153,26 @@ class GitlabManager {
}
}
public async getUsersById(ids: Array<number>, verbose: boolean = false, verboseIndent: number = 0): Promise<Array<GitlabUser | undefined>> {
return this.getGitlabUsers(ids, 'id', verbose, verboseIndent);
}
public async getUsersByUsername(usernames: Array<string>, verbose: boolean = false, verboseIndent: number = 0): Promise<Array<GitlabUser | undefined>> {
return this.getGitlabUsers(usernames, 'search', verbose, verboseIndent);
public async getUsersById(ids: Array<number>, verbose: boolean = false, verboseIndent: number = 0): Promise<Array<UserSchema | undefined>> {
return await this.getGitlabUsers(ids, GlobalHelper.sharedGitlabManager.getUserById.bind(GlobalHelper.sharedGitlabManager) as getGitlabUser, verbose, verboseIndent);
}
public async getRepository(repoId: number): Promise<GitlabRepository> {
return axios.get(this.getApiUrl(GitlabRoute.REPOSITORY_GET).replace('{{id}}', repoId.toString()));
public async getUsersByUsername(usernames: Array<string>, verbose: boolean = false, verboseIndent: number = 0): Promise<Array<UserSchema | undefined>> {
return await this.getGitlabUsers(usernames, GlobalHelper.sharedGitlabManager.getUserByUsername.bind(GlobalHelper.sharedGitlabManager) as getGitlabUser, verbose, verboseIndent);
}
public async fetchMembers(options: { members_id?: Array<number>, members_username?: Array<string> }): Promise<Array<GitlabUser> | false> {
public async fetchMembers(options: { members_id?: Array<number>, members_username?: Array<string> }): Promise<Array<UserSchema> | false> {
if ( options.members_id || options.members_username ) {
ora('Checking Gitlab members:').start().info();
}
let members: Array<GitlabUser> = [];
let members: Array<UserSchema> = [];
async function getMembers<T>(context: unknown, functionName: string, paramsToSearch: Array<T>): Promise<boolean> {
const gitlabUsers = await ((context as { [functionName: string]: (arg: Array<T>, verbose: boolean, verboseIndent: number) => Promise<Array<GitlabUser | undefined>> })[functionName])(paramsToSearch, true, 8);
const result = await ((context as { [functionName: string]: (arg: Array<T>, verbose: boolean, verboseIndent: number) => Promise<Array<UserSchema | undefined>> })[functionName])(paramsToSearch, true, 8);
if ( gitlabUsers.every(user => user) ) {
members = members.concat(gitlabUsers as Array<GitlabUser>);
if ( result.every(user => user) ) {
members = members.concat(result as Array<UserSchema>);
return true;
} else {
return false;
......@@ -225,4 +248,4 @@ class GitlabManager {
}
export default new GitlabManager();
export default GitlabManager;
......@@ -7,8 +7,9 @@ import { version } from '../c
import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import boxen from 'boxen';
import SharedConfig from '../shared/config/SharedConfig';
import Config from '../config/Config';
import { stateConfigFile } from '../config/ConfigFiles';
import SharedConfig from '../shared/config/SharedConfig';
import TextStyle from '../types/TextStyle';
......@@ -22,7 +23,6 @@ class HttpManager {
private registerRequestInterceptor() {
axios.interceptors.request.use(config => {
if ( config.data instanceof FormData ) {
config.headers = { ...config.headers, ...config.data.getHeaders() } as AxiosRequestHeaders;
}
......@@ -42,10 +42,6 @@ class HttpManager {
config.headers['client-version'] = version;
}
if ( SessionManager.gitlabCredentials.accessToken && config.url && config.url.indexOf(SharedConfig.gitlab.apiURL) !== -1 ) {
config.headers.Authorization = `Bearer ${ SessionManager.gitlabCredentials.accessToken }`;
}
return config;
});
}
......@@ -98,29 +94,6 @@ class HttpManager {
}
}
private async gitlabAuthorizationError(error: AxiosError, isFromGitlab: boolean): Promise<Promise<unknown> | undefined> {
const originalConfig = Object.assign({}, error.config, { _retry: false });
// Try to refresh the Gitlab tokens if the request have failed with a 401 error
if ( error.response && error.response.status === StatusCodes.UNAUTHORIZED && isFromGitlab && !originalConfig?._retry ) {
originalConfig._retry = true;
try {
await SessionManager.refreshTokens();
return axios(error.config as AxiosRequestConfig);
} catch ( subError ) {
if ( subError instanceof AxiosError && subError.response && subError.response.data ) {
return Promise.reject(subError.response.data);
}
return Promise.reject(subError);
}
}
return undefined;
}
private registerResponseInterceptor() {
axios.interceptors.response.use(response => {
if ( response.data && response.data.sessionToken ) {
......@@ -140,11 +113,8 @@ class HttpManager {
return response;
}, async error => {
if ( error.response ) {
const isFromApi = error.response.config.url && error.response.config.url.indexOf(ClientsSharedConfig.apiURL) !== -1;
const isFromGitlab = error.response.config.url && error.response.config.url.indexOf(SharedConfig.gitlab.URL) !== -1;
await this.gitlabAuthorizationError(error, isFromGitlab);
this.apiMethodNotAllowed(error, isFromApi);
this.apiAuthorizationError(error, isFromApi);
} else {
......
......@@ -15,11 +15,10 @@ import EventEmitter from 'events';
import SharedConfig from '../shared/config/SharedConfig';
import chalk from 'chalk';
import inquirer from 'inquirer';
import SharedGitlabManager from '../shared/managers/SharedGitlabManager';
import GitlabManager from './GitlabManager';
import GitlabToken from '../shared/types/Gitlab/GitlabToken';
import open from 'open';
import { sessionConfigFile } from '../config/ConfigFiles';
import GlobalHelper from '../helpers/GlobalHelper';
import TextStyle from '../types/TextStyle';
import DojoBackendHelper from '../sharedByClients/helpers/Dojo/DojoBackendHelper';
......@@ -116,6 +115,11 @@ class SessionManager {
set gitlabCredentials(credentials: DojoGitlabCredentials) {
sessionConfigFile.setParam(LocalConfigKeys.GITLAB, credentials);
if ( credentials.accessToken ) {
GlobalHelper.gitlabManager.setToken(credentials.accessToken);
GlobalHelper.sharedGitlabManager.setToken(credentials.accessToken);
}
}
private async getGitlabCodeFromHeadlessEnvironment(): Promise<string> {
......@@ -205,7 +209,7 @@ class SessionManager {
}).start();
let gitlabTokens: GitlabToken;
try {
gitlabTokens = await SharedGitlabManager.getTokens(gitlabCode);
gitlabTokens = await GlobalHelper.sharedGitlabManager.getTokens(gitlabCode);
this.gitlabCredentials = {
refreshToken: gitlabTokens.refresh_token,
accessToken : gitlabTokens.access_token
......@@ -216,7 +220,7 @@ class SessionManager {
throw error;
}
const isGitlabTokensValid = (await GitlabManager.testToken()).every(value => value);
const isGitlabTokensValid = (await GlobalHelper.gitlabManager.testToken()).every((value) => value);
if ( !isGitlabTokensValid ) {
throw new Error('Gitlab tokens are invalid');
}
......
Subproject commit 75fedb26c47bb6f707725307a79a45a13e62496d
Subproject commit 92e13a3dc0ca751737d782430f5e902f1ec20c14
Subproject commit c4efbcfb2a50e7108e101fb673e84f87fad8e246
Subproject commit 488f4ee9aab9fb87d198af93fdb860cc626963d8
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment