Skip to content
Snippets Groups Projects
Select Git revision
  • f70fb71c85484e5069a933adeaf9ce6344eee711
  • master default protected
  • docs-improve_user_path_description
  • fix-pipeline
  • ci-change_exercises_image_registry
  • feat-merge_recorder_in_extension
  • feat-default_folder
  • feat-change_user
  • develop protected
  • refactor-mission
  • feat-exercise_automatic_save
  • docs-improve_documentation
  • feat-create_little_container_for_developer
  • feat-local-dev
  • 0.1.12
  • 0.1.11
  • 0.1.10
  • 0.1.5
18 results

gitMission.ts

Blame
  • gitMission.ts 4.48 KiB
    import { exec as execCallback } from 'child_process';
    import simpleGit, { SimpleGit, SimpleGitOptions } from 'simple-git';
    import { GITEA_PATH_IC } from './config';
    import { log as customizableLog, error as customizableError } from '../recorder/utils/log';
    import { promisify } from 'util';
    import ApiService from './api.service';
    import UserMission from './mission/model/userMission';
    
    const exec = promisify(execCallback);
    
    const defaultRemote = 'origin';
    
    type Branch = 'master' | 'live';
    
    export default class GitMission {
      private static _instance: GitMission;
      public static get instance(): GitMission {
        if (!GitMission._instance) {
          GitMission._instance = new GitMission();
        }
        return GitMission._instance;
      }
    
      private prefix = 'DEADLOCK-RECORDER';
      private git: SimpleGit;
    
      private constructor() {
        const options: Partial<SimpleGitOptions> = {
          baseDir: GITEA_PATH_IC,
          binary: 'git',
          maxConcurrentProcesses: 2,
        };
    
        this.git = simpleGit(options);
      }
    
      log(message: any, ...args: any[]) {
        customizableLog(this.prefix, message, ...args);
      }
    
      error(message: any, ...args: any[]) {
        customizableError(this.prefix, message, ...args);
      }
    
      async setupSshAgent() {
        try {
          const gitea = await ApiService.instance.getGiteaPublicProperties();
          await exec(`ssh-add /tmp/.ssh/id_rsa`);
          await exec(`eval "$(ssh-agent -s)" && ssh-keyscan -p ${gitea.sshPort} -H ${gitea.sshHost} >> ~/.ssh/known_hosts`);
        } catch (err) {
          this.log(err);
          if (err instanceof Error) {
            if (err) {
              this.error(err.message);
              throw err;
            }
          } else {
            this.log(`Unhandled error: ${err}`);
            throw err;
          }
        }
      }
    
      async forgetSshKeys() {
        await exec(`ssh-add -d /tmp/.ssh/id_rsa`);
      }
    
      async getAuthor(): Promise<string> {
        return (await UserMission.instance.getGiteaUser()).username;
      }
    
      async init() {
        try {
          await this.setupSshAgent();
    
          await this.git.init();
    
          const remote = await this.readRemote();
    
          if (remote === defaultRemote) {
            return Promise.resolve(this);
          }
    
          const giteaUser = await UserMission.instance.getGiteaUser();
    
          await this.git.addRemote(defaultRemote, await this.getRemotePath());
          await this.git.addConfig('user.email', await UserMission.instance.getEmail(), false, 'local');
          await this.git.addConfig(
            'user.name',
            `${giteaUser.details.lastName} ${giteaUser.details.firstName}`,
            false,
            'local',
          );
          await this.git.addConfig('core.excludesFile', `user-git-${giteaUser.username}/\n`, true, 'local');
    
          return Promise.resolve(this);
        } catch (e) {
          this.error(e);
          return Promise.reject(e);
        }
      }
    
      private async getRemotePath() {
        const giteaConfig = await ApiService.instance.getGiteaPublicProperties();
        return `ssh://git@${giteaConfig.sshHost}:${giteaConfig.sshPort}/${
          (await UserMission.instance.getGiteaUser()).username
        }/${UserMission.instance.missionId}`;
      }
    
      async readRemote() {
        try {
          return ((await this.git.remote([])) || '').replace(/(\r\n|\n|\r)/gm, '');
        } catch (e) {
          this.error(e);
        }
        return '';
      }
    
      fetch() {
        return this.git.fetch(defaultRemote);
      }
    
      pull(branch: Branch = 'master') {
        return this.git.pull(defaultRemote, branch, { '--rebase': 'true' });
      }
    
      addAll() {
        return this.git.add('.');
      }
    
      commit(message: string, options: string[] = []) {
        return this.git.commit(message, options);
      }
    
      push() {
        return this.git.push(defaultRemote);
      }
    
      createLocalBranch(branch: Branch = 'master') {
        return this.git.checkout(['-b', branch]);
      }
    
      createRemoteBranch(branch: Branch = 'master') {
        return this.git.push(['-u', defaultRemote, branch]);
      }
    
      setUpstream(branch: Branch = 'master') {
        return this.git.branch(['-u', defaultRemote, branch]);
      }
    
      createBranch(branch: Branch = 'master') {
        const createBranchLocally = this.createLocalBranch(branch);
        const createRemoteBranch = this.createRemoteBranch(branch);
    
        return Promise.all([createBranchLocally, createRemoteBranch]);
      }
    
      checkout(branch: Branch = 'master') {
        return this.git.checkout(branch);
      }
    
      merge(options?: string[]) {
        return this.git.merge(options ?? []);
      }
    
      async isRemoteRepoExist() {
        try {
          const remotes = await this.git.listRemote();
          return remotes.length !== 0;
        } catch {
          // error, Gitea throws Gitea: Unauthorized when not found
          return false;
        }
      }
    }