Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions app/Http/Controllers/BuildController.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ public function build(Request $request, int $build_id): View
{
$this->setBuildById($build_id);

$project = Project::findOrFail((int) $this->project->Id);

$params = [
'build-id' => $this->build->Id,
'repository-type' => $this->project->CvsViewerType,
'repository-url' => $this->project->CvsUrl,
'repository-type' => $project->cvsviewertype,
'repository-url' => $project->cvsurl,
'repository-cmake-project-root' => $project->cmakeprojectroot,
];

$onlyNewErrors = $request->has('onlydeltap');
Expand Down
2 changes: 2 additions & 0 deletions app/Models/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
* @property ?string $ldapfilter
* @property ?string $banner
* @property ?string $logoUrl
* @property ?string $cmakeprojectroot
*
* @method Builder<Project> forUser()
* @method Builder<Project> administeredByUser()
Expand Down Expand Up @@ -97,6 +98,7 @@ class Project extends Model
'viewsubprojectslink',
'ldapfilter',
'banner',
'cmakeprojectroot',
];

protected $casts = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

return new class extends Migration {
public function up(): void
{
DB::statement('ALTER TABLE project ADD COLUMN cmakeprojectroot text');
}

public function down(): void
{
}
};
5 changes: 5 additions & 0 deletions graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ type Project {
"Example: https://github.com/Kitware/CDash"
vcsUrl: Url @rename(attribute: "cvsurl")

"Relative path to the root of the CMake project in the repository."
cmakeProjectRoot: String @rename(attribute: "cmakeprojectroot")

bugTracker: BugTracker @rename(attribute: "bugtrackertype")

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

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

cmakeProjectRoot: String @rename(attribute: "cmakeprojectroot")

bugTracker: BugTracker @rename(attribute: "bugtrackertype")

bugTrackerUrl: Url @rename(attribute: "bugtrackerurl")
Expand Down
7 changes: 7 additions & 0 deletions resources/js/vue/components/BuildBuildPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
:show-fixed-errors="showFixedErrors"
:repository-type="repositoryType"
:repository-url="repositoryUrl"
:repository-cmake-project-root="repositoryCmakeProjectRoot"
/>
</div>
</details>
Expand All @@ -116,6 +117,7 @@
:show-fixed-errors="showFixedErrors"
:repository-type="repositoryType"
:repository-url="repositoryUrl"
:repository-cmake-project-root="repositoryCmakeProjectRoot"
/>
</div>
</loading-indicator>
Expand Down Expand Up @@ -200,6 +202,11 @@ export default {
type: [String, null],
required: true,
},

repositoryCmakeProjectRoot: {
type: [String, null],
required: true,
},
},

apollo: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ export default {
required: true,
},

repositoryCmakeProjectRoot: {
type: [String, null],
required: true,
},

revision: {
type: String,
required: false,
Expand Down Expand Up @@ -174,7 +179,7 @@ export default {
];

const matches = text.match(new RegExp(`(${regexPrefixes.join('|')})[^:]*:[0-9]+:[0-9]+`, 'g'));
const repository = getRepository(this.repositoryType, this.repositoryUrl);
const repository = getRepository(this.repositoryType, this.repositoryUrl, this.repositoryCmakeProjectRoot);

if (!repository || !matches) {
return new Map();
Expand Down
7 changes: 7 additions & 0 deletions resources/js/vue/components/BuildBuildPage/BuildErrorList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
:source-directory="build.sourceDirectory"
:repository-type="repositoryType"
:repository-url="repositoryUrl"
:repository-cmake-project-root="repositoryCmakeProjectRoot"
:revision="build.updateStep?.revision"
/>
</div>
Expand All @@ -48,6 +49,7 @@
:source-directory="build.sourceDirectory"
:repository-type="repositoryType"
:repository-url="repositoryUrl"
:repository-cmake-project-root="repositoryCmakeProjectRoot"
:revision="build.updateStep?.revision"
/>
</div>
Expand Down Expand Up @@ -153,6 +155,11 @@ export default {
type: [String, null],
required: true,
},

repositoryCmakeProjectRoot: {
type: [String, null],
required: true,
},
},

apollo: {
Expand Down
10 changes: 10 additions & 0 deletions resources/js/vue/components/ProjectSettings/GeneralTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,14 @@
placeholder="https://example.com"
test-id="vcs-url-input"
/>

<InputField
v-model="form.cmakeProjectRoot"
:validation-error="validationErrors?.cmakeProjectRoot?.[0]"
label="CMake Project Root "
placeholder="/src"
test-id="cmake-project-root-input"
/>
</div>

<div class="tw-flex tw-flex-row tw-gap-4">
Expand Down Expand Up @@ -519,6 +527,7 @@ export default {
homeUrl: '',
vcsViewer: null,
vcsUrl: '',
cmakeProjectRoot: '',
bugTracker: null,
bugTrackerUrl: '',
bugTrackerNewIssueUrl: '',
Expand Down Expand Up @@ -562,6 +571,7 @@ export default {
homeUrl
vcsViewer
vcsUrl
cmakeProjectRoot
bugTracker
bugTrackerUrl
bugTrackerNewIssueUrl
Expand Down
18 changes: 11 additions & 7 deletions resources/js/vue/components/shared/RepositoryIntegrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
* @param {...String} components
*/
function makeUrlFromComponents(...components) {
return components.map(part => part.replace(/\/+$/, '')).join('/');
return components.filter(component => component !== null)
.map(part => part.replace(/\/+$|^\/+/, ''))
.join('/');
}

export class Repository {
constructor(repositoryUrl) {
constructor(repositoryUrl, repositoryCmakeProjectRoot) {
this.repositoryUrl = repositoryUrl;
this.repositoryCmakeProjectRoot = repositoryCmakeProjectRoot;
}

/**
Expand Down Expand Up @@ -49,7 +52,7 @@ export class GitHub extends Repository {
}

getFileUrl(commit, path) {
return makeUrlFromComponents(this.repositoryUrl, 'blob', commit, path);
return makeUrlFromComponents(this.repositoryUrl, 'blob', commit, this.repositoryCmakeProjectRoot, path);
}
}

Expand All @@ -62,21 +65,22 @@ export class GitLab extends Repository {
return makeUrlFromComponents(this.repositoryUrl, '-', 'compare', `${commit1}...${commit2}`);
}
getFileUrl(commit, path) {
return makeUrlFromComponents(this.repositoryUrl, '-', 'blob', commit, path);
return makeUrlFromComponents(this.repositoryUrl, '-', 'blob', commit, this.repositoryCmakeProjectRoot, path);
}
}

/**
* @param {String} repositoryType
* @param {String} repositoryUrl
* @param {String} repositoryCmakeProjectRoot
* @return ?Repository
*/
export function getRepository(repositoryType, repositoryUrl) {
export function getRepository(repositoryType, repositoryUrl, repositoryCmakeProjectRoot) {
switch (repositoryType.toLowerCase()) {
case 'github':
return new GitHub(repositoryUrl);
return new GitHub(repositoryUrl, repositoryCmakeProjectRoot);
case 'gitlab':
return new GitLab(repositoryUrl);
return new GitLab(repositoryUrl, repositoryCmakeProjectRoot);
default:
return null;
}
Expand Down
35 changes: 35 additions & 0 deletions tests/Browser/Pages/BuildBuildPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,41 @@ public function testLinksToMainBranchWhenRepositoryConfiguredAndNoUpdateStep():
});
}

public function testLinksCorrectlyWhenNotRootOfRepository(): void
{
$this->project->cvsviewertype = 'github';
$this->project->cvsurl = 'https://example.com/org/repo';
$this->project->cmakeprojectroot = '/source';
$this->project->save();

$stdOutPart1 = Str::uuid()->toString();
$stdOutPart2 = Str::uuid()->toString();
$sourceDirectory = '/absolute/path/to/source';
$filePath = $sourceDirectory . '/foo/bar.cpp:10:20';

/** @var Build $build */
$build = $this->project->builds()->create([
'siteid' => $this->site->id,
'name' => Str::uuid()->toString(),
'uuid' => Str::uuid()->toString(),
'sourcedirectory' => $sourceDirectory,
]);

$build->buildErrors()->save(BuildError::factory()->make([
'stdoutput' => $stdOutPart1 . $filePath . $stdOutPart2,
]));

$this->browse(function (Browser $browser) use ($filePath, $stdOutPart2, $stdOutPart1, $build): void {
$browser->visit("/builds/{$build->id}/build")
->waitForText('1 ERROR')
->assertSee($stdOutPart1)
->assertSee($stdOutPart2)
->assertSeeLink($filePath)
->assertPresent('a[href="https://example.com/org/repo/blob/main/source/foo/bar.cpp"]')
;
});
}

public function testLinksToUpdateRevisionWhenRepositoryConfiguredAndHasUpdateStep(): void
{
$this->project->cvsviewertype = 'github';
Expand Down
3 changes: 3 additions & 0 deletions tests/Browser/Pages/ProjectSettingsPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public static function canChangeGeneralTabFieldCases(): array
$documentationurl = fake()->url();
$testdataurl = fake()->url();
$vcsurl = fake()->url();
$cmakeprojectroot = Str::uuid()->toString();
$bugtrackerurl = fake()->url();
$bugtrackernewissueurl = fake()->url();
$emailmaxitems = fake()->numberBetween(1, 100);
Expand Down Expand Up @@ -138,6 +139,8 @@ public static function canChangeGeneralTabFieldCases(): array
['@vcs-viewer-input', 'GITLAB', 'cvsviewertype', 'gitlab', 'select'],
['@vcs-url-input', $vcsurl, 'cvsurl', $vcsurl, 'string'],
['@vcs-url-input', '', 'cvsurl', null, 'string'],
['@cmake-project-root-input', $cmakeprojectroot, 'cmakeprojectroot', $cmakeprojectroot, 'string'],
['@cmake-project-root-input', '', 'cmakeprojectroot', null, 'string'],
['@bug-tracker-input', 'None', 'bugtrackertype', null, 'select'],
['@bug-tracker-input', 'GITHUB', 'bugtrackertype', 'GitHub', 'select'],
['@bug-tracker-input', 'JIRA', 'bugtrackertype', 'JIRA', 'select'],
Expand Down
1 change: 1 addition & 0 deletions tests/Feature/GraphQL/Mutations/UpdateProjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public static function fieldValues(): array
['homeUrl', 'https://kitware.com', 'homeurl', 'https://kitware.com'],
['vcsViewer', 'GITLAB', 'cvsviewertype', 'gitlab'],
['vcsUrl', 'https://gitlab.kitware.com/kitware/cdash', 'cvsurl', 'https://gitlab.kitware.com/kitware/cdash'],
['cmakeProjectRoot', '/abc', 'cmakeprojectroot', '/abc'],
['bugTracker', 'JIRA', 'bugtrackertype', 'JIRA'],
['bugTrackerUrl', 'https://jira.kitware.com', 'bugtrackerurl', 'https://jira.kitware.com'],
['bugTrackerNewIssueUrl', 'https://jira.kitware.com/new', 'bugtrackernewissueurl', 'https://jira.kitware.com/new'],
Expand Down
2 changes: 2 additions & 0 deletions tests/Feature/GraphQL/ProjectTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ public static function fieldValues(): array
...$vcsViewerValues,
['cvsurl', 'https://github.com/Kitware/CDash', 'vcsUrl', 'https://github.com/Kitware/CDash'],
['cvsurl', null, 'vcsUrl', null],
['cmakeprojectroot', '/abc', 'cmakeProjectRoot', '/abc'],
['cmakeprojectroot', null, 'cmakeProjectRoot', null],
...$bugTrackerValues,
['bugtrackerurl', 'https://github.com/Kitware/CDash/issues', 'bugTrackerUrl', 'https://github.com/Kitware/CDash/issues'],
['bugtrackerurl', null, 'bugTrackerUrl', null],
Expand Down
24 changes: 12 additions & 12 deletions tests/Spec/repository-integrations.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@ import {
describe('RepositoryIntegrations', () => {
describe('getRepository', () => {
it('returns a GitHub instance for "github" type', () => {
const repo = getRepository('github', 'https://github.com/foo/bar');
const repo = getRepository('github', 'https://github.com/foo/bar', '');
expect(repo).toBeInstanceOf(GitHub);
expect(repo.repositoryUrl).toBe('https://github.com/foo/bar');
});

it('returns a GitLab instance for "gitlab" type', () => {
const repo = getRepository('gitlab', 'https://gitlab.com/foo/bar');
const repo = getRepository('gitlab', 'https://gitlab.com/foo/bar', '');
expect(repo).toBeInstanceOf(GitLab);
expect(repo.repositoryUrl).toBe('https://gitlab.com/foo/bar');
});

it('is case insensitive for repository type', () => {
const repo = getRepository('GitHub', 'https://github.com/foo/bar');
const repo = getRepository('GitHub', 'https://github.com/foo/bar', '');
expect(repo).toBeInstanceOf(GitHub);
});

it('returns null for unknown repository types', () => {
const repo = getRepository('bitbucket', 'https://bitbucket.org/foo/bar');
const repo = getRepository('bitbucket', 'https://bitbucket.org/foo/bar', '');
expect(repo).toBeNull();
});
});

describe('GitHub', () => {
const repoUrl = 'https://github.com/foo/bar';
const repo = new GitHub(repoUrl);
const repo = new GitHub(repoUrl, '/src');

it('generates correct commit URL', () => {
const commit = 'abcdef123456';
Expand All @@ -47,20 +47,20 @@ describe('RepositoryIntegrations', () => {

it('generates correct file URL', () => {
const commit = 'abcdef123456';
const path = 'src/main.cpp';
expect(repo.getFileUrl(commit, path)).toBe(`${repoUrl}/blob/${commit}/${path}`);
const path = 'main.cpp';
expect(repo.getFileUrl(commit, path, '')).toBe(`${repoUrl}/blob/${commit}/src/${path}`);
});

it('handles trailing slashes in repository URL', () => {
const repoWithSlash = new GitHub('https://github.com/foo/bar/');
const repoWithSlash = new GitHub('https://github.com/foo/bar/', '');
const commit = '123';
expect(repoWithSlash.getCommitUrl(commit)).toBe('https://github.com/foo/bar/commit/123');
});
});

describe('GitLab', () => {
const repoUrl = 'https://gitlab.com/foo/bar';
const repo = new GitLab(repoUrl);
const repo = new GitLab(repoUrl, '/src');

it('generates correct commit URL', () => {
const commit = 'abcdef123456';
Expand All @@ -75,12 +75,12 @@ describe('RepositoryIntegrations', () => {

it('generates correct file URL', () => {
const commit = 'abcdef123456';
const path = 'src/main.cpp';
expect(repo.getFileUrl(commit, path)).toBe(`${repoUrl}/-/blob/${commit}/${path}`);
const path = 'main.cpp';
expect(repo.getFileUrl(commit, path, '')).toBe(`${repoUrl}/-/blob/${commit}/src/${path}`);
});

it('handles trailing slashes in repository URL', () => {
const repoWithSlash = new GitLab('https://gitlab.com/foo/bar/');
const repoWithSlash = new GitLab('https://gitlab.com/foo/bar/', '');
const commit = '123';
expect(repoWithSlash.getCommitUrl(commit)).toBe('https://gitlab.com/foo/bar/-/commit/123');
});
Expand Down