Skip to content

Commit a11fa5a

Browse files
authored
Merge pull request #8 from Visual-Regression-Tracker/35-socket
35 socket
2 parents fc78075 + a718aba commit a11fa5a

File tree

11 files changed

+644
-195
lines changed

11 files changed

+644
-195
lines changed

package-lock.json

Lines changed: 398 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"@nestjs/jwt": "^7.0.0",
2828
"@nestjs/passport": "^7.0.0",
2929
"@nestjs/platform-express": "^7.0.0",
30+
"@nestjs/platform-socket.io": "^7.1.3",
3031
"@nestjs/swagger": "^4.5.1",
32+
"@nestjs/websockets": "^7.1.3",
3133
"@prisma/client": "^2.0.0-beta.6",
3234
"bcryptjs": "^2.4.3",
3335
"class-transformer": "^0.2.3",
@@ -59,6 +61,7 @@
5961
"@types/passport-local": "^1.0.33",
6062
"@types/pixelmatch": "^5.1.0",
6163
"@types/pngjs": "^3.4.2",
64+
"@types/socket.io": "^2.1.8",
6265
"@types/supertest": "^2.0.8",
6366
"@types/uuid-apikey": "^1.4.0",
6467
"@typescript-eslint/eslint-plugin": "^2.23.0",

src/builds/builds.controller.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,23 @@
1-
import {
2-
Controller,
3-
Get,
4-
UseGuards,
5-
Post,
6-
Body,
7-
Param,
8-
ParseUUIDPipe,
9-
Delete,
10-
Query,
11-
} from '@nestjs/common';
1+
import { Controller, Get, UseGuards, Post, Body, Param, ParseUUIDPipe, Delete, Query } from '@nestjs/common';
122
import { BuildsService } from './builds.service';
133
import { JwtAuthGuard } from '../auth/guards/auth.guard';
14-
import { ApiBearerAuth, ApiTags, ApiParam, ApiSecurity, ApiQuery } from '@nestjs/swagger';
4+
import { ApiBearerAuth, ApiTags, ApiParam, ApiSecurity, ApiQuery, ApiResponse } from '@nestjs/swagger';
155
import { CreateBuildDto } from './dto/build-create.dto';
166
import { ApiGuard } from '../auth/guards/api.guard';
177
import { Build } from '@prisma/client';
8+
import { BuildDto } from './dto/build.dto';
189

1910
@Controller('builds')
2011
@ApiTags('builds')
2112
export class BuildsController {
22-
constructor(private buildsService: BuildsService) { }
13+
constructor(private buildsService: BuildsService) {}
2314

2415
@Get()
2516
@ApiQuery({ name: 'projectId', required: true })
17+
@ApiResponse({ type: [BuildDto] })
2618
@ApiBearerAuth()
2719
@UseGuards(JwtAuthGuard)
28-
get(@Query('projectId', new ParseUUIDPipe()) projectId: string): Promise<Build[]> {
20+
get(@Query('projectId', new ParseUUIDPipe()) projectId: string): Promise<BuildDto[]> {
2921
return this.buildsService.findMany(projectId);
3022
}
3123

@@ -38,9 +30,10 @@ export class BuildsController {
3830
}
3931

4032
@Post()
33+
@ApiResponse({ type: BuildDto })
4134
@ApiSecurity('api_key')
4235
@UseGuards(ApiGuard)
43-
create(@Body() createBuildDto: CreateBuildDto): Promise<Build> {
36+
create(@Body() createBuildDto: CreateBuildDto): Promise<BuildDto> {
4437
return this.buildsService.create(createBuildDto);
4538
}
4639
}

src/builds/builds.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { BuildsController } from './builds.controller';
44
import { UsersModule } from '../users/users.module';
55
import { PrismaService } from '../prisma/prisma.service';
66
import { TestRunsModule } from '../test-runs/test-runs.module';
7+
import { EventsGateway } from '../events/events.gateway';
78

89
@Module({
910
imports: [UsersModule, TestRunsModule],
10-
providers: [BuildsService, PrismaService],
11+
providers: [BuildsService, PrismaService, EventsGateway],
1112
controllers: [BuildsController],
1213
exports: [BuildsService],
1314
})

src/builds/builds.service.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ import { Test, TestingModule } from '@nestjs/testing';
22
import { BuildsService } from './builds.service';
33
import { PrismaService } from '../prisma/prisma.service';
44
import { TestRunsService } from '../test-runs/test-runs.service';
5+
import { EventsGateway } from '../events/events.gateway';
56

67
describe('BuildsService', () => {
78
let service: BuildsService;
89

910
beforeEach(async () => {
1011
const module: TestingModule = await Test.createTestingModule({
11-
providers: [BuildsService,
12+
providers: [
13+
BuildsService,
1214
{ provide: PrismaService, useValue: {} },
1315
{ provide: TestRunsService, useValue: {} },
16+
{ provide: EventsGateway, useValue: {} },
1417
],
1518
}).compile();
1619

src/builds/builds.service.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,46 @@ import { CreateBuildDto } from './dto/build-create.dto';
33
import { PrismaService } from '../prisma/prisma.service';
44
import { Build } from '@prisma/client';
55
import { TestRunsService } from '../test-runs/test-runs.service';
6+
import { EventsGateway } from '../events/events.gateway';
7+
import { BuildDto } from './dto/build.dto';
68

79
@Injectable()
810
export class BuildsService {
9-
constructor(private prismaService: PrismaService, private testRunsService: TestRunsService) {}
11+
constructor(
12+
private prismaService: PrismaService,
13+
private testRunsService: TestRunsService,
14+
private eventsGateway: EventsGateway
15+
) {}
1016

11-
async findMany(projectId: string): Promise<Build[]> {
12-
return this.prismaService.build.findMany({
17+
async findMany(projectId: string): Promise<BuildDto[]> {
18+
const buildList = await this.prismaService.build.findMany({
1319
where: { projectId },
1420
include: {
1521
testRuns: true,
1622
},
1723
orderBy: { createdAt: 'desc' },
1824
});
25+
26+
return buildList.map(build => new BuildDto(build));
1927
}
2028

21-
async create(buildDto: CreateBuildDto): Promise<Build> {
22-
return this.prismaService.build.create({
29+
async create(createBuildDto: CreateBuildDto): Promise<BuildDto> {
30+
const build = await this.prismaService.build.create({
2331
data: {
24-
branchName: buildDto.branchName,
32+
branchName: createBuildDto.branchName,
2533
project: {
2634
connect: {
27-
id: buildDto.projectId,
35+
id: createBuildDto.projectId,
2836
},
2937
},
3038
},
39+
include: {
40+
testRuns: true,
41+
},
3142
});
43+
const buildDto = new BuildDto(build);
44+
this.eventsGateway.buildCreated(buildDto);
45+
return buildDto;
3246
}
3347

3448
async remove(id: string): Promise<Build> {

src/builds/dto/build.dto.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Build, TestRun, TestStatus } from '@prisma/client';
3+
4+
export class BuildDto {
5+
@ApiProperty()
6+
id: string;
7+
8+
@ApiProperty()
9+
number: number | null;
10+
11+
@ApiProperty()
12+
branchName: string | null;
13+
14+
@ApiProperty()
15+
status: string | null;
16+
17+
@ApiProperty()
18+
projectId: string;
19+
20+
@ApiProperty()
21+
updatedAt: Date;
22+
23+
@ApiProperty()
24+
createdAt: Date;
25+
26+
@ApiProperty()
27+
userId: string | null;
28+
29+
@ApiProperty()
30+
passedCount: number;
31+
@ApiProperty()
32+
unresolvedCount: number;
33+
@ApiProperty()
34+
failedCount: number;
35+
36+
constructor(build: Build & { testRuns: TestRun[] }) {
37+
this.id = build.id;
38+
this.number = build.number;
39+
this.branchName = build.branchName;
40+
this.status = build.status;
41+
this.projectId = build.projectId;
42+
this.updatedAt = build.updatedAt;
43+
this.createdAt = build.createdAt;
44+
45+
this.passedCount = 0;
46+
this.unresolvedCount = 0;
47+
this.failedCount = 0;
48+
49+
build.testRuns.forEach(testRun => {
50+
switch (testRun.status) {
51+
case TestStatus.approved:
52+
case TestStatus.ok: {
53+
this.passedCount += 1;
54+
break;
55+
}
56+
case TestStatus.unresolved:
57+
case TestStatus.new: {
58+
this.unresolvedCount += 1;
59+
break;
60+
}
61+
case TestStatus.failed: {
62+
this.failedCount += 1;
63+
break;
64+
}
65+
}
66+
});
67+
68+
if (build.testRuns.length === 0) {
69+
this.status = 'new';
70+
} else {
71+
this.status = 'passed';
72+
}
73+
if (this.failedCount > 0) {
74+
this.status = 'failed';
75+
}
76+
if (this.unresolvedCount > 0) {
77+
this.status = 'unresolved';
78+
}
79+
}
80+
}

src/events/events.gateway.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
2+
import { Server } from 'socket.io';
3+
import { TestRun } from '@prisma/client';
4+
import { BuildDto } from '../builds/dto/build.dto';
5+
6+
@WebSocketGateway()
7+
export class EventsGateway {
8+
@WebSocketServer()
9+
server: Server;
10+
11+
buildCreated(build: BuildDto) {
12+
this.server.emit('build_created', build);
13+
}
14+
15+
newTestRun(testRun: TestRun) {
16+
this.server.emit('testRun_created', testRun);
17+
}
18+
}

src/test-runs/test-runs.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { TestRunsService } from './test-runs.service';
33
import { SharedModule } from '../shared/shared.module';
44
import { PrismaService } from '../prisma/prisma.service';
55
import { TestRunsController } from './test-runs.controller';
6+
import { EventsGateway } from '../events/events.gateway';
67

78
@Module({
89
imports: [SharedModule],
9-
providers: [TestRunsService, PrismaService],
10+
providers: [TestRunsService, PrismaService, EventsGateway],
1011
exports: [TestRunsService],
1112
controllers: [TestRunsController]
1213
})

0 commit comments

Comments
 (0)