Skip to content

Commit

Permalink
feat(ui): add repository views ( show/add/delete ) (#6386)
Browse files Browse the repository at this point in the history
  • Loading branch information
sguiheux authored Dec 14, 2022
1 parent 73759e3 commit b1d7fe1
Show file tree
Hide file tree
Showing 37 changed files with 787 additions and 53 deletions.
2 changes: 1 addition & 1 deletion engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ func (api *API) InitRouter() {
r.Handle("/v2/project/{projectKey}/vcs", nil, r.POSTv2(api.postVCSProjectHandler), r.GETv2(api.getVCSProjectAllHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}", nil, r.PUTv2(api.putVCSProjectHandler), r.DELETEv2(api.deleteVCSProjectHandler), r.GETv2(api.getVCSProjectHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}/repository", nil, r.POSTv2(api.postProjectRepositoryHandler), r.GETv2(api.getVCSProjectRepositoryAllHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}/repository/{repositoryIdentifier}", nil, r.DELETEv2(api.deleteProjectRepositoryHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}/repository/{repositoryIdentifier}", nil, r.GETv2(api.getProjectRepositoryHandler), r.DELETEv2(api.deleteProjectRepositoryHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}/repository/{repositoryIdentifier}/analysis", nil, r.GETv2(api.getProjectRepositoryAnalysesHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}/repository/{repositoryIdentifier}/analysis/{analysisID}", nil, r.GETv2(api.getProjectRepositoryAnalysisHandler))
r.Handle("/v2/project/{projectKey}/vcs/{vcsIdentifier}/repository/{repositoryIdentifier}/entities", nil, r.GETv2(api.getEntitiesHandler))
Expand Down
16 changes: 16 additions & 0 deletions engine/api/event/publish_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,19 @@ func PublishDeleteProjectIntegration(ctx context.Context, p *sdk.Project, pf sdk
}
PublishProjectEvent(ctx, e, p.Key, u)
}

func PublishRemoveProjectRepository(ctx context.Context, pKey string, vcs sdk.VCSProject, r sdk.ProjectRepository, u sdk.Identifiable) {
e := sdk.EventProjectRepositoryDelete{
Repository: r,
VCS: vcs,
}
PublishProjectEvent(ctx, e, pKey, u)
}

func PublishAddProjectRepository(ctx context.Context, pKey string, vcs sdk.VCSProject, r sdk.ProjectRepository, u sdk.Identifiable) {
e := sdk.EventProjectRepositoryAdd{
Repository: r,
VCS: vcs,
}
PublishProjectEvent(ctx, e, pKey, u)
}
33 changes: 33 additions & 0 deletions engine/api/v2_project_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/gorilla/mux"

"github.com/ovh/cds/engine/api/event"
"github.com/ovh/cds/engine/api/repositoriesmanager"
"github.com/ovh/cds/engine/api/repository"
"github.com/ovh/cds/engine/api/services"
Expand All @@ -30,6 +31,34 @@ func (api *API) getRepositoryByIdentifier(ctx context.Context, vcsID string, rep
return repo, nil
}

func (api *API) getProjectRepositoryHandler() ([]service.RbacChecker, service.Handler) {
return service.RBAC(api.projectRead),
func(ctx context.Context, w http.ResponseWriter, req *http.Request) error {
vars := mux.Vars(req)
pKey := vars["projectKey"]
vcsIdentifier, err := url.PathUnescape(vars["vcsIdentifier"])
if err != nil {
return sdk.NewError(sdk.ErrWrongRequest, err)
}
repositoryIdentifier, err := url.PathUnescape(vars["repositoryIdentifier"])
if err != nil {
return sdk.WithStack(err)
}

vcsProject, err := api.getVCSByIdentifier(ctx, pKey, vcsIdentifier)
if err != nil {
return err
}

repo, err := api.getRepositoryByIdentifier(ctx, vcsProject.ID, repositoryIdentifier)
if err != nil {
return err
}

return service.WriteJSON(w, repo, http.StatusOK)
}
}

// deleteProjectRepositoryHandler Delete a repository from a project
func (api *API) deleteProjectRepositoryHandler() ([]service.RbacChecker, service.Handler) {
return service.RBAC(api.projectManage),
Expand Down Expand Up @@ -81,6 +110,8 @@ func (api *API) deleteProjectRepositoryHandler() ([]service.RbacChecker, service
if err := tx.Commit(); err != nil {
return sdk.WithStack(err)
}

event.PublishRemoveProjectRepository(ctx, pKey, sdk.VCSProject{ID: vcsProject.ID, Name: vcsProject.Name}, *repo, getUserConsumer(ctx))
return service.WriteMarshal(w, req, vcsProject, http.StatusOK)
}
}
Expand Down Expand Up @@ -171,6 +202,8 @@ func (api *API) postProjectRepositoryHandler() ([]service.RbacChecker, service.H
if err := tx.Commit(); err != nil {
return sdk.WithStack(err)
}

event.PublishAddProjectRepository(ctx, pKey, sdk.VCSProject{ID: vcsProjectWithSecret.ID, Name: vcsProjectWithSecret.Name}, repoDB, getUserConsumer(ctx))
return service.WriteMarshal(w, req, repoDB, http.StatusCreated)
}
}
Expand Down
9 changes: 9 additions & 0 deletions engine/api/v2_project_vcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ func (api *API) getVCSProjectHandler() ([]service.RbacChecker, service.Handler)
if err != nil {
return err
}

vcsClear, err := vcs.LoadVCSByID(ctx, api.mustDB(), pKey, vcsProject.ID, gorpmapping.GetOptions.WithDecryption)
if err != nil {
return err
}
vcsProject.Auth.Username = vcsClear.Auth.Username
vcsProject.Auth.SSHKeyName = vcsClear.Auth.SSHKeyName
vcsProject.Auth.SSHUsername = vcsClear.Auth.SSHUsername
vcsProject.Auth.SSHPort = vcsClear.Auth.SSHPort
return service.WriteMarshal(w, r, vcsProject, http.StatusOK)
}
}
3 changes: 2 additions & 1 deletion engine/api/v2_project_vcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ auth:
vcsProject := sdk.VCSProject{}
require.NoError(t, json.Unmarshal(w3.Body.Bytes(), &vcsProject))
require.Equal(t, "my_vcs_server", vcsProject.Name)
require.Empty(t, vcsProject.Auth)
require.Empty(t, vcsProject.Auth.SSHPrivateKey)
require.Empty(t, vcsProject.Auth.Token)

// delete the vcs project
uriDelete := api.Router.GetRouteV2("DELETE", api.deleteVCSProjectHandler, vars)
Expand Down
10 changes: 10 additions & 0 deletions sdk/event_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,13 @@ type EventProjectIntegrationUpdate struct {
type EventProjectIntegrationDelete struct {
Integration ProjectIntegration `json:"integration"`
}

type EventProjectRepositoryDelete struct {
Repository ProjectRepository `json:"repository"`
VCS VCSProject `json:"vcs"`
}

type EventProjectRepositoryAdd struct {
Repository ProjectRepository `json:"repository"`
VCS VCSProject `json:"vcs"`
}
14 changes: 7 additions & 7 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"modernizr": "3.12.0",
"moment": "2.29.4",
"ng-event-source": "1.0.14",
"ng-zorro-antd": "13.1.1",
"ng-zorro-antd": "13.4.0",
"ng2-codemirror-typescript": "3.13.1",
"ng2-completer": "2.0.8",
"ng2-dragula-sgu": "3.0.2",
Expand Down
2 changes: 2 additions & 0 deletions ui/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { FetchCurrentAuth } from './store/authentication.action';
import { NgxsStoreModule } from './store/store.module';
import { NavbarModule } from './views/navbar/navbar.module';
import { NzNotificationModule } from 'ng-zorro-antd/notification';
import { SidebarService } from 'app/service/services.module';

describe('App: CDS', () => {

Expand All @@ -49,6 +50,7 @@ describe('App: CDS', () => {
],
providers: [
Store,
SidebarService,
WorkflowService,
WorkflowRunService,
UserService,
Expand Down
18 changes: 14 additions & 4 deletions ui/src/app/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Event, EventType } from './model/event.model';
import { LoadOpts } from './model/project.model';
import { TimelineFilter } from './model/timeline.model';
import { NavbarService } from './service/navbar/navbar.service';
import { RouterService, TimelineStore } from './service/services.module';
import { RouterService, SidebarService, TimelineStore } from './service/services.module';
import { WorkflowRunService } from './service/workflow/run/workflow.run.service';
import { ToastService } from './shared/toast/ToastService';
import {
Expand All @@ -37,6 +37,8 @@ import {
UpdateWorkflowRunList
} from './store/workflow.action';
import { WorkflowState } from './store/workflow.state';
import { SidebarEvent } from 'app/service/sidebar/sidebar.service';
import { FlatNodeItem } from 'app/shared/tree/tree.component';

@Injectable()
export class AppService {
Expand All @@ -56,6 +58,7 @@ export class AppService {
private _workflowRunService: WorkflowRunService,
private _store: Store,
private _navbarService: NavbarService,
private _sidebarService: SidebarService
) {
this.routeParams = this._routerService.getRouteParams({}, this._routeActivated);
}
Expand Down Expand Up @@ -110,10 +113,17 @@ export class AppService {
event.type_event === EventType.WORKFLOW_DELETE) {
await this.updateProjectCache(event);

if (event.type_event === EventType.APPLICATION_UPDATE || event.type_event === EventType.WORKFLOW_UPDATE) {
this._navbarService.refreshData();
switch (event.type_event) {
case EventType.APPLICATION_UPDATE:
case EventType.WORKFLOW_UPDATE:
this._navbarService.refreshData();
break;
case EventType.PROJECT_REPOSITORY_REMOVE:
let removeParent = <FlatNodeItem>{id: event?.payload['vcs']?.id, type: 'vcs'}
let removeEvent = new SidebarEvent(event?.payload['repository']?.id, event?.payload['repository']?.name, 'repository', 'remove', removeParent);
this._sidebarService.sendEvent(removeEvent);
break;
}

}
if (event.type_event.indexOf(EventType.APPLICATION_PREFIX) === 0) {
await this.updateApplicationCache(event);
Expand Down
13 changes: 13 additions & 0 deletions ui/src/app/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ export class EventService {
break;
}
break;
case 'projectv2':
if (urlSplitted.length === 1) {
break;
}
let projectV2Key = urlSplitted[1].split('?')[0];
if (urlSplitted.length >= 2) { // Project page
fs.push(<WebsocketFilter>{
type: WebsocketFilterType.PROJECT,
project_key: projectV2Key
});
break;
}
break;
case 'project':
if (urlSplitted.length === 1) { // Ignore project creation page
break;
Expand Down
2 changes: 2 additions & 0 deletions ui/src/app/model/event.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export class EventType {
static PROJECT_PERMISSION_PREFIX = 'sdk.EventProjectPermission';
static PROJECT_KEY_PREFIX = 'sdk.EventProjectKey';
static PROJECT_INTEGRATION_PREFIX = 'sdk.EventProjectIntegration';
static PROJECT_REPOSITORY_ADD = 'sdk.EventProjectRepositoryAdd';
static PROJECT_REPOSITORY_REMOVE = 'sdk.EventProjectRepositoryDelete';

static ENVIRONMENT_PREFIX = 'sdk.EventEnvironment';

Expand Down
17 changes: 16 additions & 1 deletion ui/src/app/model/project.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,26 @@ export class Label {
export class VCSProject {
id: string;
name: string;
auth: VCSProjectAuth;
}

export class Repository {
export class VCSProjectAuth {
username: string;
token: string;
sshKeyName: string;

// Use for gerrit
sshUsername: string;
sshPort: number;
sshPrivateKey: string;
}

export class ProjectRepository {
id: string;
name: string;
clone_url: string;
created: Date;
created_by: string;
}

export class Entity {
Expand Down
18 changes: 18 additions & 0 deletions ui/src/app/service/project/project.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ import { ProjectState, ProjectStateModel } from 'app/store/project.state';
import { Observable } from 'rxjs';
import { flatMap, map } from 'rxjs/operators';

@Injectable()
export class Projectv2Resolver implements Resolve<Project> {
constructor(private store: Store, private routerService: RouterService) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any {
let params = this.routerService.getRouteSnapshotParams({}, state.root);
let opts = [];

return this.store.dispatch(new FetchProject({
projectKey: params['key'],
opts
})).pipe(
flatMap(() => this.store.selectOnce(ProjectState)),
map((projectState: ProjectStateModel) => projectState.project)
);
}
}

@Injectable()
export class ProjectResolver implements Resolve<Project> {

Expand Down
26 changes: 22 additions & 4 deletions ui/src/app/service/project/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ProjectIntegration } from 'app/model/integration.model';
import { Key } from 'app/model/keys.model';
import { Entity, LoadOpts, Project, Repository, VCSProject } from 'app/model/project.model';
import { Entity, LoadOpts, Project, ProjectRepository, VCSProject } from 'app/model/project.model';
import { Observable } from 'rxjs';

/**
Expand Down Expand Up @@ -96,12 +96,30 @@ export class ProjectService {
* Get the list of VCS attached to the given project from the API
* @param key
*/
getVCSProject(key: string): Observable<Array<VCSProject>> {
listVCSProject(key: string): Observable<Array<VCSProject>> {
return this._http.get<Array<VCSProject>>(`/v2/project/${key}/vcs`);
}

getVCSRepositories(key: string, vcsName: string): Observable<Array<Repository>> {
return this._http.get<Array<Repository>>(`/v2/project/${key}/vcs/${vcsName}/repository`);
getVCSProject(key: string, vcsName: string): Observable<VCSProject> {
return this._http.get<VCSProject>(`/v2/project/${key}/vcs/${vcsName}`);
}

getVCSRepository(key: string, vcsName: string, repoName: string): Observable<ProjectRepository> {
let encodedRepo = encodeURIComponent(repoName);
return this._http.get<ProjectRepository>(`/v2/project/${key}/vcs/${vcsName}/repository/${encodedRepo}`);
}

getVCSRepositories(key: string, vcsName: string): Observable<Array<ProjectRepository>> {
return this._http.get<Array<ProjectRepository>>(`/v2/project/${key}/vcs/${vcsName}/repository`);
}

addVCSRepository(key: string, vcsName: string, repo: ProjectRepository): Observable<ProjectRepository> {
return this._http.post<ProjectRepository>(`/v2/project/${key}/vcs/${vcsName}/repository`, repo);
}

deleteVCSRepository(key: string, vcsName: string, repoName: string): Observable<any> {
let encodedRepo = encodeURIComponent(repoName);
return this._http.delete(`/v2/project/${key}/vcs/${vcsName}/repository/${encodedRepo}`);
}

getRepoEntities(key: string, vcsName: string, repo: string): Observable<Array<Entity>> {
Expand Down
Loading

0 comments on commit b1d7fe1

Please sign in to comment.