INTO-CPS-Association/DTaaS

View on GitHub
client/src/preview/util/DTAssets.ts

Summary

Maintainability
A
3 hrs
Test Coverage
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */

import { FileState } from 'preview/store/file.slice';
import GitlabInstance from './gitlab';
import FileHandler from './fileHandler';

export enum FileType {
  DESCRIPTION = 'description',
  CONFIGURATION = 'configuration',
  LIFECYCLE = 'lifecycle',
}

export function getFilePath(
  file: FileState,
  mainFolderPath: string,
  lifecycleFolderPath: string,
): string {
  return file.type === 'lifecycle' ? lifecycleFolderPath : mainFolderPath;
}

class DTAssets {
  public DTName: string;

  public gitlabInstance: GitlabInstance;

  public fileHandler: FileHandler;

  constructor(DTName: string, gitlabInstance: GitlabInstance) {
    this.DTName = DTName;
    this.gitlabInstance = gitlabInstance;
    this.fileHandler = new FileHandler(DTName, gitlabInstance);
  }

  async createFiles(
    files:
      | FileState[]
      | Array<{
          name: string;
          content: string;
          isNew: boolean;
          isFromCommonLibrary: boolean;
        }>,
    mainFolderPath: string,
    lifecycleFolderPath: string,
  ): Promise<void> {
    for (const file of files) {
      const fileType = (file as FileState).type || 'asset';

      if (file.isNew) {
        const mainFolderPathUpdated = file.isFromCommonLibrary
          ? `${mainFolderPath}/common`
          : mainFolderPath;
        const lifecycleFolderPathUpdated = file.isFromCommonLibrary
          ? `${mainFolderPathUpdated}/lifecycle`
          : lifecycleFolderPath;
        const filePath =
          fileType === 'lifecycle'
            ? lifecycleFolderPathUpdated
            : mainFolderPathUpdated;
        const commitMessage = `Add ${file.name} to ${fileType} folder`;
        await this.fileHandler.createFile(file, filePath, commitMessage);
      }
    }
  }

  async getFilesFromAsset(assetPath: string, isPrivate: boolean) {
    try {
      const fileNames = await this.fileHandler.getLibraryFileNames(
        assetPath,
        isPrivate,
      );

      const files: Array<{
        name: string;
        content: string;
        path: string;
        isPrivate: boolean;
      }> = [];

      for (const fileName of fileNames) {
        const fileContent = await this.fileHandler.getFileContent(
          `${assetPath}/${fileName}`,
          isPrivate,
        );

        files.push({
          name: fileName,
          content: fileContent,
          path: assetPath,
          isPrivate,
        });
      }

      return files;
    } catch (error) {
      throw new Error(
        `Error fetching files from asset at ${assetPath}: ${error}`,
      );
    }
  }

  async updateFileContent(
    fileName: string,
    fileContent: string,
  ): Promise<void> {
    const hasExtension = fileName.includes('.');

    const filePath = hasExtension
      ? `digital_twins/${this.DTName}/${fileName}`
      : `digital_twins/${this.DTName}/lifecycle/${fileName}`;

    const commitMessage = `Update ${fileName} content`;

    await this.fileHandler.updateFile(filePath, fileContent, commitMessage);
  }

  async updateLibraryFileContent(
    fileName: string,
    fileContent: string,
    assetPath: string,
  ): Promise<void> {
    const filePath = `${assetPath}/${fileName}`;
    const commitMessage = `Update ${fileName} content`;

    await this.fileHandler.updateFile(filePath, fileContent, commitMessage);
  }

  async appendTriggerToPipeline(): Promise<string> {
    const filePath = `.gitlab-ci.yml`;

    try {
      const fileContent = await this.fileHandler.getFileContent(filePath);

      const triggerKey = `trigger_${this.DTName}`;
      if (fileContent.includes(triggerKey)) {
        return `Trigger already exists in the pipeline for ${this.DTName}`;
      }

      const triggerContent = `
${triggerKey}:
  stage: triggers
  trigger:
    include: digital_twins/${this.DTName}/.gitlab-ci.yml
  rules:
    - if: '$DTName == "${this.DTName}"'
      when: always
  variables:
    RunnerTag: $RunnerTag
`;

      const updatedContent = `${fileContent.trimEnd()}\n${triggerContent}`;

      const commitMessage = `Add trigger for ${this.DTName} to .gitlab-ci.yml`;
      await this.fileHandler.updateFile(
        filePath,
        updatedContent,
        commitMessage,
      );

      return `Trigger appended to pipeline for ${this.DTName}`;
    } catch (error) {
      return `Error appending trigger to pipeline: ${error}`;
    }
  }

  async removeTriggerFromPipeline(): Promise<string> {
    const filePath = `.gitlab-ci.yml`;

    try {
      const fileContent = await this.fileHandler.getFileContent(filePath);

      const triggerPattern = new RegExp(
        `\\n?\\s*trigger_${this.DTName}:.*?(?=\\n\\s*trigger_|$)`,
        'gs',
      );

      const updatedContent = fileContent.replace(triggerPattern, '');

      if (updatedContent !== fileContent) {
        const commitMessage = `Remove trigger for ${this.DTName} from .gitlab-ci.yml`;
        await this.fileHandler.updateFile(
          filePath,
          updatedContent,
          commitMessage,
        );
      } else {
        return `No trigger found for ${this.DTName} in ${filePath}`;
      }
      return `Trigger removed from pipeline for ${this.DTName}`;
    } catch (error) {
      return `Error removing trigger from pipeline: ${error}`;
    }
  }

  async delete(): Promise<void> {
    await this.removeTriggerFromPipeline();
    await this.fileHandler.deleteDT(`digital_twins/${this.DTName}`);

    const libraryDTs =
      await this.fileHandler.getFolders(`common/digital_twins`);
    if (libraryDTs.includes(`common/digital_twins/${this.DTName}`)) {
      await this.fileHandler.deleteDT(`common/digital_twins/${this.DTName}`);
    }
  }

  async getFileContent(fileName: string): Promise<string> {
    const isFileWithoutExtension = !fileName.includes('.');

    const filePath = isFileWithoutExtension
      ? `digital_twins/${this.DTName}/lifecycle/${fileName}`
      : `digital_twins/${this.DTName}/${fileName}`;

    const fileContent = await this.fileHandler.getFileContent(filePath);

    return fileContent;
  }

  async getLibraryFileContent(
    assetPath: string,
    fileName: string,
  ): Promise<string> {
    const filePath = `${assetPath}/${fileName}`;
    return this.fileHandler.getFileContent(filePath);
  }

  async getFileNames(fileType: FileType): Promise<string[]> {
    return this.fileHandler.getFileNames(fileType);
  }

  async getLibraryConfigFileNames(filePath: string): Promise<string[]> {
    return this.fileHandler.getLibraryConfigFileNames(filePath, true);
  }

  async getFolders(path: string): Promise<string[]> {
    return this.fileHandler.getFolders(path);
  }
}

export default DTAssets;