Skip to content

Commit 280037c

Browse files
Add support for build error links when project not repo root (#3633)
Not all projects have the root of their CMake project at the root of the repository. CDash currently assumes the project is at the top level of the repository, meaning that all build error links are broken for projects where this is not the case. This PR adds the ability to specify the repository-relative path to the top-level CMakeLists.txt.
1 parent a6125bd commit 280037c

14 files changed

Lines changed: 121 additions & 22 deletions

File tree

app/Http/Controllers/BuildController.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ public function build(Request $request, int $build_id): View
3434
{
3535
$this->setBuildById($build_id);
3636

37+
$project = Project::findOrFail((int) $this->project->Id);
38+
3739
$params = [
3840
'build-id' => $this->build->Id,
39-
'repository-type' => $this->project->CvsViewerType,
40-
'repository-url' => $this->project->CvsUrl,
41+
'repository-type' => $project->cvsviewertype,
42+
'repository-url' => $project->cvsurl,
43+
'repository-cmake-project-root' => $project->cmakeprojectroot,
4144
];
4245

4346
$onlyNewErrors = $request->has('onlydeltap');

app/Models/Project.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* @property ?string $ldapfilter
5050
* @property ?string $banner
5151
* @property ?string $logoUrl
52+
* @property ?string $cmakeprojectroot
5253
*
5354
* @method Builder<Project> forUser()
5455
* @method Builder<Project> administeredByUser()
@@ -97,6 +98,7 @@ class Project extends Model
9798
'viewsubprojectslink',
9899
'ldapfilter',
99100
'banner',
101+
'cmakeprojectroot',
100102
];
101103

102104
protected $casts = [
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Support\Facades\DB;
5+
6+
return new class extends Migration {
7+
public function up(): void
8+
{
9+
DB::statement('ALTER TABLE project ADD COLUMN cmakeprojectroot text');
10+
}
11+
12+
public function down(): void
13+
{
14+
}
15+
};

graphql/schema.graphql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ type Project {
214214
"Example: https://github.com/Kitware/CDash"
215215
vcsUrl: Url @rename(attribute: "cvsurl")
216216

217+
"Relative path to the root of the CMake project in the repository."
218+
cmakeProjectRoot: String @rename(attribute: "cmakeprojectroot")
219+
217220
bugTracker: BugTracker @rename(attribute: "bugtrackertype")
218221

219222
"Example: https://github.com/Kitware/CDash/issues"
@@ -420,6 +423,8 @@ input UpdateProjectInput @validator {
420423

421424
vcsUrl: Url @rename(attribute: "cvsurl")
422425

426+
cmakeProjectRoot: String @rename(attribute: "cmakeprojectroot")
427+
423428
bugTracker: BugTracker @rename(attribute: "bugtrackertype")
424429

425430
bugTrackerUrl: Url @rename(attribute: "bugtrackerurl")

resources/js/vue/components/BuildBuildPage.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
:show-fixed-errors="showFixedErrors"
105105
:repository-type="repositoryType"
106106
:repository-url="repositoryUrl"
107+
:repository-cmake-project-root="repositoryCmakeProjectRoot"
107108
/>
108109
</div>
109110
</details>
@@ -116,6 +117,7 @@
116117
:show-fixed-errors="showFixedErrors"
117118
:repository-type="repositoryType"
118119
:repository-url="repositoryUrl"
120+
:repository-cmake-project-root="repositoryCmakeProjectRoot"
119121
/>
120122
</div>
121123
</loading-indicator>
@@ -200,6 +202,11 @@ export default {
200202
type: [String, null],
201203
required: true,
202204
},
205+
206+
repositoryCmakeProjectRoot: {
207+
type: [String, null],
208+
required: true,
209+
},
203210
},
204211
205212
apollo: {

resources/js/vue/components/BuildBuildPage/BuildErrorItem.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ export default {
129129
required: true,
130130
},
131131
132+
repositoryCmakeProjectRoot: {
133+
type: [String, null],
134+
required: true,
135+
},
136+
132137
revision: {
133138
type: String,
134139
required: false,
@@ -174,7 +179,7 @@ export default {
174179
];
175180
176181
const matches = text.match(new RegExp(`(${regexPrefixes.join('|')})[^:]*:[0-9]+:[0-9]+`, 'g'));
177-
const repository = getRepository(this.repositoryType, this.repositoryUrl);
182+
const repository = getRepository(this.repositoryType, this.repositoryUrl, this.repositoryCmakeProjectRoot);
178183
179184
if (!repository || !matches) {
180185
return new Map();

resources/js/vue/components/BuildBuildPage/BuildErrorList.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
:source-directory="build.sourceDirectory"
2626
:repository-type="repositoryType"
2727
:repository-url="repositoryUrl"
28+
:repository-cmake-project-root="repositoryCmakeProjectRoot"
2829
:revision="build.updateStep?.revision"
2930
/>
3031
</div>
@@ -48,6 +49,7 @@
4849
:source-directory="build.sourceDirectory"
4950
:repository-type="repositoryType"
5051
:repository-url="repositoryUrl"
52+
:repository-cmake-project-root="repositoryCmakeProjectRoot"
5153
:revision="build.updateStep?.revision"
5254
/>
5355
</div>
@@ -153,6 +155,11 @@ export default {
153155
type: [String, null],
154156
required: true,
155157
},
158+
159+
repositoryCmakeProjectRoot: {
160+
type: [String, null],
161+
required: true,
162+
},
156163
},
157164
158165
apollo: {

resources/js/vue/components/ProjectSettings/GeneralTab.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@
253253
placeholder="https://example.com"
254254
test-id="vcs-url-input"
255255
/>
256+
257+
<InputField
258+
v-model="form.cmakeProjectRoot"
259+
:validation-error="validationErrors?.cmakeProjectRoot?.[0]"
260+
label="CMake Project Root "
261+
placeholder="/src"
262+
test-id="cmake-project-root-input"
263+
/>
256264
</div>
257265

258266
<div class="tw-flex tw-flex-row tw-gap-4">
@@ -519,6 +527,7 @@ export default {
519527
homeUrl: '',
520528
vcsViewer: null,
521529
vcsUrl: '',
530+
cmakeProjectRoot: '',
522531
bugTracker: null,
523532
bugTrackerUrl: '',
524533
bugTrackerNewIssueUrl: '',
@@ -562,6 +571,7 @@ export default {
562571
homeUrl
563572
vcsViewer
564573
vcsUrl
574+
cmakeProjectRoot
565575
bugTracker
566576
bugTrackerUrl
567577
bugTrackerNewIssueUrl

resources/js/vue/components/shared/RepositoryIntegrations.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
* @param {...String} components
55
*/
66
function makeUrlFromComponents(...components) {
7-
return components.map(part => part.replace(/\/+$/, '')).join('/');
7+
return components.filter(component => component !== null)
8+
.map(part => part.replace(/\/+$|^\/+/, ''))
9+
.join('/');
810
}
911

1012
export class Repository {
11-
constructor(repositoryUrl) {
13+
constructor(repositoryUrl, repositoryCmakeProjectRoot) {
1214
this.repositoryUrl = repositoryUrl;
15+
this.repositoryCmakeProjectRoot = repositoryCmakeProjectRoot;
1316
}
1417

1518
/**
@@ -49,7 +52,7 @@ export class GitHub extends Repository {
4952
}
5053

5154
getFileUrl(commit, path) {
52-
return makeUrlFromComponents(this.repositoryUrl, 'blob', commit, path);
55+
return makeUrlFromComponents(this.repositoryUrl, 'blob', commit, this.repositoryCmakeProjectRoot, path);
5356
}
5457
}
5558

@@ -62,21 +65,22 @@ export class GitLab extends Repository {
6265
return makeUrlFromComponents(this.repositoryUrl, '-', 'compare', `${commit1}...${commit2}`);
6366
}
6467
getFileUrl(commit, path) {
65-
return makeUrlFromComponents(this.repositoryUrl, '-', 'blob', commit, path);
68+
return makeUrlFromComponents(this.repositoryUrl, '-', 'blob', commit, this.repositoryCmakeProjectRoot, path);
6669
}
6770
}
6871

6972
/**
7073
* @param {String} repositoryType
7174
* @param {String} repositoryUrl
75+
* @param {String} repositoryCmakeProjectRoot
7276
* @return ?Repository
7377
*/
74-
export function getRepository(repositoryType, repositoryUrl) {
78+
export function getRepository(repositoryType, repositoryUrl, repositoryCmakeProjectRoot) {
7579
switch (repositoryType.toLowerCase()) {
7680
case 'github':
77-
return new GitHub(repositoryUrl);
81+
return new GitHub(repositoryUrl, repositoryCmakeProjectRoot);
7882
case 'gitlab':
79-
return new GitLab(repositoryUrl);
83+
return new GitLab(repositoryUrl, repositoryCmakeProjectRoot);
8084
default:
8185
return null;
8286
}

tests/Browser/Pages/BuildBuildPageTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,41 @@ public function testLinksToMainBranchWhenRepositoryConfiguredAndNoUpdateStep():
364364
});
365365
}
366366

367+
public function testLinksCorrectlyWhenNotRootOfRepository(): void
368+
{
369+
$this->project->cvsviewertype = 'github';
370+
$this->project->cvsurl = 'https://example.com/org/repo';
371+
$this->project->cmakeprojectroot = '/source';
372+
$this->project->save();
373+
374+
$stdOutPart1 = Str::uuid()->toString();
375+
$stdOutPart2 = Str::uuid()->toString();
376+
$sourceDirectory = '/absolute/path/to/source';
377+
$filePath = $sourceDirectory . '/foo/bar.cpp:10:20';
378+
379+
/** @var Build $build */
380+
$build = $this->project->builds()->create([
381+
'siteid' => $this->site->id,
382+
'name' => Str::uuid()->toString(),
383+
'uuid' => Str::uuid()->toString(),
384+
'sourcedirectory' => $sourceDirectory,
385+
]);
386+
387+
$build->buildErrors()->save(BuildError::factory()->make([
388+
'stdoutput' => $stdOutPart1 . $filePath . $stdOutPart2,
389+
]));
390+
391+
$this->browse(function (Browser $browser) use ($filePath, $stdOutPart2, $stdOutPart1, $build): void {
392+
$browser->visit("/builds/{$build->id}/build")
393+
->waitForText('1 ERROR')
394+
->assertSee($stdOutPart1)
395+
->assertSee($stdOutPart2)
396+
->assertSeeLink($filePath)
397+
->assertPresent('a[href="https://example.com/org/repo/blob/main/source/foo/bar.cpp"]')
398+
;
399+
});
400+
}
401+
367402
public function testLinksToUpdateRevisionWhenRepositoryConfiguredAndHasUpdateStep(): void
368403
{
369404
$this->project->cvsviewertype = 'github';

0 commit comments

Comments
 (0)