Skip to content

Commit 6c4cd18

Browse files
committed
feat(lint): save and return linter violations
1 parent ab3ab14 commit 6c4cd18

8 files changed

+113
-21
lines changed

src/lint/dto/lint-error.dto.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export class LintErrorDTO {
2+
message: string;
3+
4+
line: number | null;
5+
6+
column: number | null;
7+
8+
offset: number | null;
9+
}

src/lint/dto/lint-result.dto.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { LintErrorDTO } from './lint-error.dto';
2+
3+
export class LintResultDTO {
4+
score: number;
5+
6+
errors: LintErrorDTO[];
7+
}

src/lint/lint.service.ts

+66-14
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import child_process from 'child_process';
77
import fs from 'fs';
88
import * as uuid from 'uuid';
99
import YAML from 'yaml';
10+
import { LintErrorDTO } from './dto/lint-error.dto';
11+
import { LintResultDTO } from './dto/lint-result.dto';
1012
import { ConvertToGolangCILintOutput } from './linters/golangcilint';
1113
import { ConvertToPylintOutput } from './linters/pylint';
1214

1315
@Injectable()
1416
export class LintService {
15-
lintPython3(code: string): number {
17+
lintPython3(code: string): LintResultDTO {
1618
const result = child_process.spawnSync(
1719
'pylint',
1820
['--from-stdin', '-f', 'json', 'module_or_package', '--'],
@@ -49,7 +51,22 @@ export class LintService {
4951
5052
Remove one point to the score per violation
5153
*/
52-
return 100 - pylintOutput.length;
54+
const score = 100 - pylintOutput.length;
55+
const errors: LintErrorDTO[] = [];
56+
57+
for (const violation of pylintOutput) {
58+
errors.push({
59+
message: violation.message,
60+
line: violation.line,
61+
column: violation.column,
62+
offset: null,
63+
});
64+
}
65+
66+
return {
67+
score,
68+
errors,
69+
};
5370
}
5471
} catch (e) {
5572
throw new InternalServerErrorException();
@@ -58,7 +75,7 @@ export class LintService {
5875
throw new InternalServerErrorException();
5976
}
6077

61-
lintGolang(code: string): number {
78+
lintGolang(code: string): LintResultDTO {
6279
// Golangci-lint doesn't support stdin
6380
const path = `/tmp/codebench_${uuid.v4()}.go`;
6481
try {
@@ -112,19 +129,35 @@ export class LintService {
112129
*/
113130
if (lintOuput.issues) {
114131
// Remove one point to the score per violation
115-
return 100 - lintOuput.issues.length;
132+
const score = 100 - lintOuput.issues.length;
133+
const errors: LintErrorDTO[] = [];
134+
135+
for (const issue of lintOuput.issues) {
136+
errors.push({
137+
message: issue.text,
138+
line: issue.pos.line,
139+
column: issue.pos.column,
140+
offset: null,
141+
});
142+
}
143+
return {
144+
score,
145+
errors,
146+
};
116147
}
117148
// Golangci-lint return `null` if there are no violation
118-
return 100;
119149
}
120150
} catch (e) {
121151
throw new InternalServerErrorException(e);
122152
}
123153

124-
throw new InternalServerErrorException();
154+
return {
155+
score: 100,
156+
errors: [],
157+
};
125158
}
126159

127-
lintCpp(code: string): number {
160+
lintCpp(code: string): LintResultDTO {
128161
// clang-tidy doesn't support stdin
129162
const path = `/tmp/codebench_${uuid.v4()}.cpp`;
130163
const outputPath = `${path}.yaml`;
@@ -152,27 +185,46 @@ export class LintService {
152185
if (fs.existsSync(outputPath)) {
153186
const file = fs.readFileSync(`${path}.yaml`, 'utf8');
154187
const fixes: any = YAML.parse(file);
188+
155189
if (fixes) {
156190
/*
157191
Example file:
158192
---
159193
MainSourceFile: /root/fib.cpp
160194
Diagnostics:
161-
- DiagnosticName: clang-diagnostic-unused-variable
162-
Message: 'unused variable ''d'''
163-
FileOffset: 142
164-
FilePath: /root/fib.cpp
165-
Replacements:
195+
- DiagnosticName: clang-diagnostic-unused-variable
196+
Message: 'unused variable ''d'''
197+
FileOffset: 142
198+
FilePath: /root/fib.cpp
199+
Replacements:
166200
...
167201
*/
168202
if (fixes.Diagnostics) {
169-
return 100 - fixes.Diagnostics.length;
203+
const score = 100 - fixes.Diagnostics.length;
204+
const errors: LintErrorDTO[] = [];
205+
206+
for (const diagnostic of fixes.Diagnostics) {
207+
errors.push({
208+
message: diagnostic.Message,
209+
line: diagnostic.FileOffset,
210+
column: null,
211+
offset: null,
212+
});
213+
}
214+
return {
215+
score,
216+
errors,
217+
};
170218
}
171219
}
172220
}
173-
return 100;
174221
} catch (e) {
175222
throw new InternalServerErrorException(e);
176223
}
224+
225+
return {
226+
score: 100,
227+
errors: [],
228+
};
177229
}
178230
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class AddSubmissionsLintReports1627337341637 implements MigrationInterface {
4+
name = 'AddSubmissionsLintReports1627337341637'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`ALTER TABLE "submissions" ADD "lintErrors" jsonb`);
8+
}
9+
10+
public async down(queryRunner: QueryRunner): Promise<void> {
11+
await queryRunner.query(`ALTER TABLE "submissions" DROP COLUMN "lintErrors"`);
12+
}
13+
14+
}

src/submissions/dto/insert-submission-dto.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { LintErrorDTO } from 'src/lint/dto/lint-error.dto';
12
import { User } from 'src/users/user.entity';
23

34
export class InsertSubmissionDTO {
@@ -8,4 +9,6 @@ export class InsertSubmissionDTO {
89
code: string;
910

1011
user: User;
12+
13+
lintErrors?: LintErrorDTO[];
1114
}

src/submissions/dto/submission-result.dto.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { QualityDTO } from 'src/code-quality/dto/quality.dto';
2+
import { LintErrorDTO } from 'src/lint/dto/lint-error.dto';
23
import { Submission } from '../submission.entity';
34

45
export class SubmissionResultDTO {
@@ -7,4 +8,6 @@ export class SubmissionResultDTO {
78
lint: { score: number };
89

910
quality: QualityDTO;
11+
12+
lintErrors?: LintErrorDTO[];
1013
}

src/submissions/submission.entity.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars */
22
import { ApiProperty } from '@nestjs/swagger';
3+
import { LintErrorDTO } from 'src/lint/dto/lint-error.dto';
34
import { User } from 'src/users/user.entity';
45
import { jsonMember, jsonObject } from 'typedjson';
56
import {
@@ -92,6 +93,9 @@ export class Submission extends BaseEntity {
9293
@Column({ nullable: true })
9394
lintScore: number;
9495

96+
@Column('jsonb', { nullable: true })
97+
lintErrors?: LintErrorDTO[];
98+
9599
@jsonMember
96100
@Column({ nullable: true })
97101
qualityScore: number;

src/submissions/submissions.controller.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { ValidatedJWTReq } from 'src/auth/dto/validated-jwt-req';
1313
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
1414
import { CodeQualityService } from 'src/code-quality/code-quality.service';
15+
import { LintResultDTO } from 'src/lint/dto/lint-result.dto';
1516
import { LintService } from 'src/lint/lint.service';
1617
import { CreateSubmissionDTO } from './dto/create-submission-dto';
1718
import { FindSubmissionDTO } from './dto/find-submission.dto';
@@ -34,32 +35,31 @@ export class SubmissionsController {
3435
@Request() req: ValidatedJWTReq,
3536
@Body() createSubmissionDTO: CreateSubmissionDTO,
3637
): Promise<SubmissionResultDTO> {
37-
let lintScore = { score: 100 };
38+
let lintScore: LintResultDTO;
3839
let qualityScore = { score: 100 };
3940
switch (createSubmissionDTO.language) {
4041
case 'python':
4142
qualityScore = this.qualityService.run(createSubmissionDTO.code, 'py');
42-
lintScore.score = this.lintService.lintPython3(
43-
createSubmissionDTO.code,
44-
);
43+
lintScore = this.lintService.lintPython3(createSubmissionDTO.code);
4544
break;
4645
case 'cpp':
4746
qualityScore = this.qualityService.run(createSubmissionDTO.code, 'cpp');
48-
lintScore.score = this.lintService.lintCpp(createSubmissionDTO.code);
47+
lintScore = this.lintService.lintCpp(createSubmissionDTO.code);
4948
break;
5049
case 'go':
5150
qualityScore = this.qualityService.run(createSubmissionDTO.code, 'go');
52-
lintScore.score = this.lintService.lintGolang(createSubmissionDTO.code);
51+
lintScore = this.lintService.lintGolang(createSubmissionDTO.code);
5352
break;
5453
default:
55-
lintScore = { score: 0 };
54+
lintScore = { score: 0, errors: [] };
5655
qualityScore = { score: 0 };
5756
}
5857

5958
const submission = await this.submissionsService.create(
6059
{
6160
...createSubmissionDTO,
6261
user: req.user,
62+
lintErrors: lintScore.errors,
6363
},
6464
lintScore.score,
6565
qualityScore.score,

0 commit comments

Comments
 (0)