diff --git a/src/app.module.ts b/src/app.module.ts index 1f307c8..d77d6c8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,6 +7,7 @@ import { AppResolver } from './app.resolver'; import { AppService } from './app.service'; import { ProjectsModule } from './projects/projects.module'; import { ReposModule } from './repos/repos.module'; +import { PipelinesModule } from './pipelines/pipelines.module'; import configuration from './commons/config/configuration'; @Module({ @@ -39,6 +40,7 @@ import configuration from './commons/config/configuration'; }), ProjectsModule, ReposModule, + PipelinesModule, ], controllers: [AppController], providers: [AppService, AppResolver], diff --git a/src/pipelines/dtos/create-pipeline.input.ts b/src/pipelines/dtos/create-pipeline.input.ts new file mode 100644 index 0000000..100a4fe --- /dev/null +++ b/src/pipelines/dtos/create-pipeline.input.ts @@ -0,0 +1,26 @@ +import { InputType } from '@nestjs/graphql'; +import { + IsObject, + IsOptional, + IsString, + IsUUID, + MaxLength, +} from 'class-validator'; + +@InputType({ isAbstract: true }) +export class CreatePipelineInput { + @IsUUID() + projectId: string; + + @IsString() + @MaxLength(100) + branch: string; + + @IsString() + @MaxLength(32) + name: string; + + @IsOptional() + @IsObject() + workUnitMetadata = {}; +} diff --git a/src/pipelines/dtos/list-pipelines.args.ts b/src/pipelines/dtos/list-pipelines.args.ts new file mode 100644 index 0000000..d46fcb4 --- /dev/null +++ b/src/pipelines/dtos/list-pipelines.args.ts @@ -0,0 +1,8 @@ +import { ArgsType } from '@nestjs/graphql'; +import { IsUUID } from 'class-validator'; + +@ArgsType() +export class ListPipelineArgs { + @IsUUID() + projectId?: string; +} diff --git a/src/pipelines/dtos/update-pipeline.input.ts b/src/pipelines/dtos/update-pipeline.input.ts new file mode 100644 index 0000000..b64f8ba --- /dev/null +++ b/src/pipelines/dtos/update-pipeline.input.ts @@ -0,0 +1,5 @@ +import { InputType } from '@nestjs/graphql'; +import { CreatePipelineInput } from './create-pipeline.input'; + +@InputType() +export class UpdatePipelineInput extends CreatePipelineInput {} diff --git a/src/pipelines/pipeline.entity.ts b/src/pipelines/pipeline.entity.ts new file mode 100644 index 0000000..b0c2d85 --- /dev/null +++ b/src/pipelines/pipeline.entity.ts @@ -0,0 +1,22 @@ +import { Column, Entity, ManyToOne } from 'typeorm'; +import { AppBaseEntity } from '../commons/entities/app-base-entity'; +import { Project } from '../projects/project.entity'; +import { ObjectType } from '@nestjs/graphql'; + +@ObjectType() +@Entity() +export class Pipeline extends AppBaseEntity { + @ManyToOne(() => Project) + project: Project; + @Column() + projectId: string; + + @Column({ comment: 'eg: remotes/origin/master' }) + branch: string; + + @Column() + name: string; + + @Column({ type: 'jsonb' }) + workUnitMetadata: any; +} diff --git a/src/pipelines/pipelines.module.ts b/src/pipelines/pipelines.module.ts new file mode 100644 index 0000000..59f1df1 --- /dev/null +++ b/src/pipelines/pipelines.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { PipelinesResolver } from './pipelines.resolver'; +import { PipelinesService } from './pipelines.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Pipeline } from './pipeline.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Pipeline])], + providers: [PipelinesResolver, PipelinesService], +}) +export class PipelinesModule {} diff --git a/src/pipelines/pipelines.resolver.spec.ts b/src/pipelines/pipelines.resolver.spec.ts new file mode 100644 index 0000000..0c26a65 --- /dev/null +++ b/src/pipelines/pipelines.resolver.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PipelinesResolver } from './pipelines.resolver'; +import { PipelinesService } from './pipelines.service'; + +describe('PipelinesResolver', () => { + let resolver: PipelinesResolver; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + PipelinesResolver, + { + provide: PipelinesService, + useValue: {}, + }, + ], + }).compile(); + + resolver = module.get(PipelinesResolver); + }); + + it('should be defined', () => { + expect(resolver).toBeDefined(); + }); +}); diff --git a/src/pipelines/pipelines.resolver.ts b/src/pipelines/pipelines.resolver.ts new file mode 100644 index 0000000..6c65fd6 --- /dev/null +++ b/src/pipelines/pipelines.resolver.ts @@ -0,0 +1,44 @@ +import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; +import { CreatePipelineInput } from './dtos/create-pipeline.input'; +import { UpdatePipelineInput } from './dtos/update-pipeline.input'; +import { Pipeline } from './pipeline.entity'; +import { PipelinesService } from './pipelines.service'; +import { ListPipelineArgs } from './dtos/list-pipelines.args'; + +@Resolver() +export class PipelinesResolver { + constructor(private readonly service: PipelinesService) {} + @Query(() => [Pipeline]) + async findPipelines(@Args('listPipelineArgs') dto: ListPipelineArgs) { + return await this.service.list(dto); + } + + @Query(() => Pipeline) + async findPipeline(@Args('id', { type: () => String }) id: string) { + return await this.service.findOne(id); + } + + @Mutation(() => Pipeline) + async createPipeline( + @Args('Pipeline', { type: () => CreatePipelineInput }) + dto: UpdatePipelineInput, + ) { + return await this.service.create(dto); + } + + @Mutation(() => Pipeline) + async modifyPipeline( + @Args('id', { type: () => String }) id: string, + @Args('Pipeline', { type: () => UpdatePipelineInput }) + dto: UpdatePipelineInput, + ) { + const tmp = await this.service.update(id, dto); + console.log(tmp); + return tmp; + } + + @Mutation(() => Number) + async deletePipeline(@Args('id', { type: () => String }) id: string) { + return await this.service.remove(id); + } +} diff --git a/src/pipelines/pipelines.service.spec.ts b/src/pipelines/pipelines.service.spec.ts new file mode 100644 index 0000000..c0816cc --- /dev/null +++ b/src/pipelines/pipelines.service.spec.ts @@ -0,0 +1,26 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PipelinesService } from './pipelines.service'; +import { Pipeline } from './pipeline.entity'; +import { getRepositoryToken } from '@nestjs/typeorm'; + +describe('PipelinesService', () => { + let service: PipelinesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + PipelinesService, + { + provide: getRepositoryToken(Pipeline), + useValue: {}, + }, + ], + }).compile(); + + service = module.get(PipelinesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/pipelines/pipelines.service.ts b/src/pipelines/pipelines.service.ts new file mode 100644 index 0000000..6d7316d --- /dev/null +++ b/src/pipelines/pipelines.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Pipeline } from './pipeline.entity'; +import { Repository } from 'typeorm'; +import { BaseDbService } from '../commons/services/base-db.service'; +import { CreatePipelineInput } from './dtos/create-pipeline.input'; +import { UpdatePipelineInput } from './dtos/update-pipeline.input'; +import { ListPipelineArgs } from './dtos/list-pipelines.args'; + +@Injectable() +export class PipelinesService extends BaseDbService { + readonly uniqueFields: Array = ['branch', 'projectId']; + constructor( + @InjectRepository(Pipeline) + readonly repository: Repository, + ) { + super(repository); + } + async list(dto: ListPipelineArgs) { + return this.repository.find(dto); + } + + async create(dto: CreatePipelineInput) { + await this.isDuplicateEntity(dto); + return await this.repository.save(this.repository.create(dto)); + } + + async update(id: string, dto: UpdatePipelineInput) { + await this.isDuplicateEntityForUpdate(id, dto); + const old = await this.findOne(id); + return await this.repository.save(this.repository.merge(old, dto)); + } + + async remove(id: string) { + return (await this.repository.softDelete({ id })).affected; + } +} diff --git a/src/projects/projects.service.ts b/src/projects/projects.service.ts index a8bfe2d..9ae02d1 100644 --- a/src/projects/projects.service.ts +++ b/src/projects/projects.service.ts @@ -4,6 +4,7 @@ import { BaseDbService } from '../commons/services/base-db.service'; import { Repository } from 'typeorm'; import { CreateProjectInput } from './dtos/create-project.input'; import { Project } from './project.entity'; +import { UpdateProjectInput } from './dtos/update-project.input'; @Injectable() export class ProjectsService extends BaseDbService { @@ -24,7 +25,7 @@ export class ProjectsService extends BaseDbService { return await this.repository.save(this.repository.create(dto)); } - async update(id: string, dto: CreateProjectInput) { + async update(id: string, dto: UpdateProjectInput) { await this.isDuplicateEntityForUpdate(id, dto); const old = await this.findOne(id); return await this.repository.save(this.repository.merge(old, dto));