Skip to content

Commit

Permalink
Deploy Applications from Enterprise GitHub and GitLab (#4782)
Browse files Browse the repository at this point in the history
* Frontend for new yaml based git endpoints
- register github.com and gitlab.com endpoints and connect with credentials
- register and connect to github and gitlan enterprise instances
- select these as sources when deploying a cf application

* Add proxy single request API endpoint

* Add endpoint plugin generation from a YAML file

* Deploy to CF from private GitHub and GitLab repos

* Use subtypes for YAML generated endpoints

* Nicer YAML format; ignore unknown endpoint types in the DB

* Fix merge issues and add icon indicator for private repositories

* Fix lint issues

* Add details component to show username and avatar on endpoint card

* Various fixes and improvements

* Fix lint issue

* Fix merge issues

* Unit test fixes

* Unit test fix following merge

* One more unit test fix

* Fix backend unit tests

* Fix the deploy types todo (in a verbose way)

* Ignore commit id when possible

* Fix redeploy stepper

* Fix minor bugs in new register git stepper

* multiple fixes, remaining todos

* update github/gitlab connect readme's, including scope info

* In connect helper remove duped header

* Fix multiple gitlab issues

* Fix deploy app home screen link for github/gitlab with credentials

* Ensure app git tab only shows if we have access to repo
- can happen if others view app deployed via private repo

* Fix clone url & improve error messaging

* Improve cf app summary page git info

* Fix issue where...
- we're waiting for an endpoint that doesn't exist.. in an effect
- that endpoint then is created
- the effect then fires off the request... long after it should have stopped

* Fix multiple gitlab enterprise issues
- enterprise gits weren't showing as deploy source types
- enterprise gits that weren't connected failed to work (fetching data & deploying)

* Fix git enterprise ssl setting, provide hint at time of url required

* Show private repo indicator on app git tab

* app git tab: handle git fetch failure beter
- also rework observables in page

* Changes following quick self review

* Fix linting

* Fixes following testing

* Use enum for github string

* Ensure Git entities associated with an endpoint are removed on endpoint unregister/disconnect

* Fix unit test

* Tidy up backend changes

* Update app summary page

* Show no content message if app git tab cannot show info

* display password field instead of text area for token

* other changes following review

* Fix other issues raised in review (all from single comment)

* Fix frontend after updated backend

* Apply path escaping fix when url is recreated

* Fix some of the e2e tests

* Fixes after testing

* Fix more e2e tests

* Changes following review

Co-authored-by: Richard Cox <richard.cox@suse.com>
Co-authored-by: Ivan Kapelyukhin <ikapelyukhin@suse.com>
  • Loading branch information
3 people authored Dec 3, 2020
1 parent 8fb79dd commit 3363703
Show file tree
Hide file tree
Showing 98 changed files with 2,528 additions and 1,167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
(stratProject.deploySource.type === 'github' || stratProject.deploySource.type === 'gitscm')
) {
const gitscm = stratProject.deploySource.scm || stratProject.deploySource.type;
const scm = scmService.getSCM(gitscm as GitSCMType);
const scm = scmService.getSCM(gitscm as GitSCMType, stratProject.deploySource.endpointGuid);
const iconInfo = scm.getIcon();
// Add tab or update existing tab
const tab = this.tabLinks.find(t => t.link === 'gitscm');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface EnvVarStratosProjectSource {
timestamp: number;
project?: string;
scm?: string;
endpointGuid: string;
branch?: string;
url?: string;
commit?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,41 @@
{{(applicationService.applicationStratProject$| async)?.deploySource.url}}
</div>
</app-metadata-item>
<app-metadata-item *ngSwitchCase="'gitscm'" [iconFont]="deploySource.icon.fontName"
[icon]="deploySource.icon.iconName" [label]="deploySource.label">
<a href="{{ deploySource.commitURL }}" rel="noopener noreferrer" target="_blank">
{{ deploySource.commit | slice:0:8 }}
</a>
</app-metadata-item>
<div *ngSwitchCase="'gitscm'" class="summary__gitscm">
<div>
<app-metadata-item [iconFont]="deploySource.icon.fontName" [icon]="deploySource.icon.iconName"
label="SCM">
{{deploySource.label}}
</app-metadata-item>
<app-metadata-item iconFont="stratos-icons" icon="repositories" label="Repository">
<a *ngIf="!!(gitRepo$ | async); else displayRepo" href="{{ (gitRepo$ | async)?.html_url }}"
rel="noopener noreferrer" target="_blank">
<ng-container *ngTemplateOutlet="displayRepo">
</ng-container>
</a>
<ng-template #displayRepo>{{ deploySource.project }}</ng-template>
</app-metadata-item>
</div>
<div>
<app-metadata-item icon="call_split" label="Branch">
<a *ngIf="!!(gitRepo$ | async) as repo; else displayBranch"
href="{{ (gitRepo$ | async)?.html_url }}/tree/{{ deploySource.branch }}" rel="noopener noreferrer"
target="_blank">
<ng-container *ngTemplateOutlet="displayBranch">
</ng-container>
</a>
<ng-template #displayBranch>{{ deploySource.branch}}</ng-template>
</app-metadata-item>
<app-metadata-item icon="show_chart" label="Commit">
<a *ngIf="!!deploySource.commitURL; else displayCommit" href="{{ deploySource.commitURL }}"
rel="noopener noreferrer" target="_blank">
<ng-container *ngTemplateOutlet="displayCommit">
</ng-container>
</a>
<ng-template #displayCommit>{{ deploySource.commit | slice:0:8 }}</ng-template>
</app-metadata-item>
</div>
</div>
<app-metadata-item *ngSwitchCase="'filefolder'" icon="folder" label="Folder">
Deployed from local folder
</app-metadata-item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@
margin-right: 8px;
}
}

&__gitscm {
display: flex;
div {
flex: 1;
app-metadata-item:first-of-type {
margin-top: 0;
}
}
}
}

.app-metadata {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { GitSCMService, GitSCMType } from '@stratosui/git';
import { GitCommit, gitEntityCatalog, GitRepo, GitSCMService, GitSCMType, SCMIcon } from '@stratosui/git';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, of } from 'rxjs';
import { combineLatest, delay, distinct, filter, first, map, mergeMap, startWith, switchMap, tap } from 'rxjs/operators';

Expand All @@ -23,6 +23,7 @@ import { CfCurrentUserPermissions } from '../../../../../../user-permissions/cf-
import { ApplicationMonitorService } from '../../../../application-monitor.service';
import { ApplicationData, ApplicationService } from '../../../../application.service';
import { DEPLOY_TYPES_IDS } from '../../../../deploy-application/deploy-application-steps.types';
import { EnvVarStratosProjectSource } from './application-env-vars.service';

const isDockerHubRegEx = /^([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_-]+):([a-zA-Z0-9_.-]+)/g;

Expand All @@ -48,6 +49,12 @@ const appRestageConfirmation = new ConfirmationDialogConfig(
'Restage'
);

interface CustomEnvVarStratosProjectSource extends EnvVarStratosProjectSource {
label?: string;
icon?: SCMIcon;
commitURL?: string;
}

@Component({
selector: 'app-build-tab',
templateUrl: './build-tab.component.html',
Expand All @@ -57,7 +64,7 @@ const appRestageConfirmation = new ConfirmationDialogConfig(
]
})
export class BuildTabComponent implements OnInit {
public isBusyUpdating$: Observable<{ updating: boolean }>;
public isBusyUpdating$: Observable<{ updating: boolean, }>;
public manageAppPermission = CfCurrentUserPermissions.APPLICATION_MANAGE;

constructor(
Expand All @@ -78,7 +85,9 @@ export class BuildTabComponent implements OnInit {

sshStatus$: Observable<string>;

deploySource$: Observable<{ type: string, [name: string]: any }>;
deploySource$: Observable<CustomEnvVarStratosProjectSource>;

public gitRepo$: Observable<GitRepo>;

ngOnInit() {
this.cardTwoFetching$ = this.applicationService.application$.pipe(
Expand Down Expand Up @@ -117,28 +126,30 @@ export class BuildTabComponent implements OnInit {
)
);

this.gitRepo$ = this.applicationService.applicationStratProject$.pipe(
map(project => {
const scmType = project.deploySource.scm || project.deploySource.type;
const scm = this.scmService.getSCM(scmType as GitSCMType, project.deploySource.endpointGuid);
return gitEntityCatalog.repo.store.getRepoInfo.getEntityService({ projectName: project.deploySource.project, scm });
}),
switchMap(repoService => repoService.waitForEntity$),
map(p => p.entity)
);

const deploySource$ = observableCombineLatest(
this.applicationService.applicationStratProject$,
this.applicationService.application$
).pipe(
map(([project, app]) => {
if (!!project) {
const deploySource = { ...project.deploySource } as any;
const deploySource: CustomEnvVarStratosProjectSource = { ...project.deploySource };

// Legacy
if (deploySource.type === 'github') {
deploySource.type = 'gitscm';
deploySource.scm = 'github';
}

if (deploySource.type === 'gitscm') {
const scmType = deploySource.scm as GitSCMType;
const scm = this.scmService.getSCM(scmType);
deploySource.label = scm.getLabel();
deploySource.commitURL = scm.getCommitURL(deploySource.project, deploySource.commit);
deploySource.icon = scm.getIcon();
}

if (deploySource.type === DEPLOY_TYPES_IDS.DOCKER_IMG) {
return {
type: 'docker',
Expand All @@ -158,6 +169,32 @@ export class BuildTabComponent implements OnInit {
return null;
}
}),
switchMap((deploySource: CustomEnvVarStratosProjectSource) => {
const res: Observable<any>[] = [
of(deploySource),
];
if (deploySource && deploySource.type === 'gitscm') {
// Add gitscm info... add async info in next section
const scmType = deploySource.scm as GitSCMType;
const scm = this.scmService.getSCM(scmType, deploySource.endpointGuid);
deploySource.label = scm.getLabel();
deploySource.icon = scm.getIcon();
res.push(gitEntityCatalog.commit.store.getEntityService(null, scm.endpointGuid, {
projectName: deploySource.project,
scm,
commitSha: deploySource.commit
}).entityObs$);
} else {
res.push(of(null));
}
return observableCombineLatest(res);
}),
map(([deploySource, commit]: [CustomEnvVarStratosProjectSource, EntityInfo<GitCommit>]) => {
if (deploySource) {
deploySource.commitURL = commit?.entity?.html_url;
}
return deploySource;
}),
startWith({ type: 'loading' })
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,87 +1,109 @@
<app-tile-grid class="gitscm-tab" *ngIf="stratosProject$ | async as stratosProject">
<app-tile-group>
<app-tile>
<mat-card>
<mat-card-header>
<mat-card-title>Deployment Information</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="gitscm-tab__deployment">
<app-metadata-item label="Repository">
<a href="{{(gitSCMRepo$ | async)?.html_url}}" target="_blank">{{stratosProject.deploySource.project }}</a>
</app-metadata-item>
<app-metadata-item label="Branch">
<a href="{{(gitSCMRepo$ | async)?.html_url}}/tree/{{ stratosProject.deploySource.branch}}" target="_blank">
{{ stratosProject.deploySource.branch}}
</a>
</app-metadata-item>
<div class="gitscm-tab__deployment__commit">
<div>
<app-metadata-item label="Commit">
<a href="{{(commit$ | async)?.html_url}}" target="_blank">{{ stratosProject.deploySource.commit | limitTo: 8}}</a>
<app-loading-page [isLoading]="isLoading$" text="Retrieving Git Details">
<div>
<app-tile-grid class="gitscm-tab" *ngIf="hasRepo$ | async as hasRepo">
<app-tile-group>
<app-tile *ngIf="appService.applicationStratProject$ | async as stratosProject">
<mat-card>
<mat-card-header>
<mat-card-title>Deployment Information</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="gitscm-tab__deployment">
<app-metadata-item label="Repository">
<a href="{{(gitSCMRepo$ | async)?.html_url}}"
target="_blank">{{stratosProject.deploySource.project }}</a>
</app-metadata-item>
<app-metadata-item label="Branch">
<a href="{{(gitSCMRepo$ | async)?.html_url}}/tree/{{ stratosProject.deploySource.branch}}"
target="_blank">
{{ stratosProject.deploySource.branch}}
</a>
</app-metadata-item>
<div class="gitscm-tab__deployment__commit">
<div>
<app-metadata-item label="Commit">
<a href="{{(commit$ | async)?.html_url}}"
target="_blank">{{ stratosProject.deploySource.commit | limitTo: 8}}</a>
</app-metadata-item>
</div>
<div class="gitscm-tab__deployment__commit-warning" *ngIf="(isHead$ | async) === false">
<div>
<mat-icon color="warn">warning</mat-icon>
</div>
<div class="gitscm-tab__deployment__commit-warning__msg">The
{{ stratosProject.deploySource.branch }}
branch has been updated since this app was deployed. Redeploy to update</div>
</div>
</div>
<app-metadata-item label="Deployed:">{{ stratosProject.deploySource.timestamp * 1000 | date:'medium' }}
</app-metadata-item>
</div>
<div class="gitscm-tab__deployment__commit-warning" *ngIf="!(isHead$ | async) && (initialised$ | async)">
</mat-card-content>
</mat-card>
</app-tile>
<app-tile *ngIf="gitSCMRepo$ | async as gitSCMRepo">
<mat-card>
<mat-card-header>
<mat-card-title>Repository Details</mat-card-title>
</mat-card-header>
<mat-card-content>
<div>
<div class="gitscm-tab__avatar">
<img src={{gitSCMRepo.owner.avatar_url}}>
</div>
<div>
<app-metadata-item label="Full Name">
<div class="gitscm-tab__repo__name">
<a href="{{ gitSCMRepo.html_url }}" target="_blank">{{ gitSCMRepo.full_name }}</a>
<mat-icon class="gitscm-tab__repo__name--icon" *ngIf="gitSCMRepo.private"
matTooltip="Private Repo">
lock</mat-icon>
</div>
</app-metadata-item>
<app-metadata-item label="Owner">{{ gitSCMRepo.owner.login || gitSCMRepo.owner.name }}
</app-metadata-item>
<app-metadata-item label="Description">{{ gitSCMRepo.description || '-' }}</app-metadata-item>
<app-metadata-item label="Created:">{{ gitSCMRepo.created_at | date:'medium' }}</app-metadata-item>
<app-metadata-item *ngIf="gitSCMRepo.pushed_at" label="Last Pushed:">
{{ gitSCMRepo.pushed_at | date:'medium' }}</app-metadata-item>
<app-metadata-item *ngIf="gitSCMRepo.last_activity_at" label="Last Actvity:">
{{ gitSCMRepo.last_activity_at | date:'medium' }}</app-metadata-item>
</div>
</div>
</mat-card-content>
</mat-card>
</app-tile>
<app-tile *ngIf="commit$ | async as commitInfo">
<mat-card>
<mat-card-header>
<mat-card-title>Commit Details</mat-card-title>
</mat-card-header>
<mat-card-content>
<div>
<div class="gitscm-tab__avatar">
<img src={{commitInfo.author.avatar_url}}>
</div>
<div>
<mat-icon color="warn">warning</mat-icon>
<app-metadata-item label="Message">{{ commitInfo.commit.message }}</app-metadata-item>
<app-metadata-item label="SHA">
<a href={{commitInfo.html_url}} target="_blank">{{ commitInfo.sha | limitTo: 8}}</a>
</app-metadata-item>
<app-metadata-item label="Author">
<app-github-commit-author [commit]="commitInfo" [showAvatar]="false"></app-github-commit-author>
</app-metadata-item>
<app-metadata-item label="Date:">{{ commitInfo.commit.author.date | date:'medium' }}
</app-metadata-item>
</div>
<div class="gitscm-tab__deployment__commit-warning__msg">The {{ stratosProject.deploySource.branch}} branch has been updated since this app was deployed. Redeploy to update</div>
</div>
</div>
<app-metadata-item label="Deployed:">{{ stratosProject.deploySource.timestamp * 1000 | date:'medium' }}</app-metadata-item>
</div>
</mat-card-content>
</mat-card>
</app-tile>
<app-tile>
<mat-card>
<mat-card-header>
<mat-card-title>Repository Details</mat-card-title>
</mat-card-header>
<mat-card-content>

<div *ngIf="gitSCMRepo$ | async as gitSCMRepo">
<div class="gitscm-tab__avatar">
<img src={{gitSCMRepo.owner.avatar_url}}>
</div>
<div>
<app-metadata-item label="Full Name">
<a href="{{ gitSCMRepo.html_url }}" target="_blank">{{ gitSCMRepo.full_name }}</a>
</app-metadata-item>
<app-metadata-item label="Owner">{{ gitSCMRepo.owner.login || gitSCMRepo.owner.name }}</app-metadata-item>
<app-metadata-item label="Description">{{ gitSCMRepo.description }}</app-metadata-item>
<app-metadata-item label="Created:">{{ gitSCMRepo.created_at | date:'medium' }}</app-metadata-item>
<app-metadata-item *ngIf="gitSCMRepo.pushed_at" label="Last Pushed:">{{ gitSCMRepo.pushed_at | date:'medium' }}</app-metadata-item>
<app-metadata-item *ngIf="gitSCMRepo.last_activity_at" label="Last Actvity:">{{ gitSCMRepo.last_activity_at | date:'medium' }}</app-metadata-item>
</div>
</div>
</mat-card-content>
</mat-card>
</app-tile>
<app-tile>
<mat-card>
<mat-card-header>
<mat-card-title>Commit Details</mat-card-title>
</mat-card-header>
<mat-card-content>
<div *ngIf="commit$ | async as commitInfo">
<div class="gitscm-tab__avatar">
<img src={{commitInfo.author.avatar_url}}>
</div>
<div>
<app-metadata-item label="Message">{{ commitInfo.commit.message }}</app-metadata-item>
<app-metadata-item label="SHA">
<a href={{commitInfo.html_url}} target="_blank">{{ commitInfo.sha | limitTo: 8}}</a>
</app-metadata-item>
<app-metadata-item label="Author">
<app-github-commit-author [commit]="commitInfo" [showAvatar]="false"></app-github-commit-author>
</app-metadata-item>
<app-metadata-item label="Date:">{{ commitInfo.commit.author.date | date:'medium' }}</app-metadata-item>
</div>
</div>
</mat-card-content>
</mat-card>
</app-tile>
</app-tile-group>
<app-list *ngIf="gitSCMRepo$ | async as gitSCMRepo"></app-list>
</app-tile-grid>
</mat-card-content>
</mat-card>
</app-tile>
</app-tile-group>
<app-list *ngIf="gitSCMRepo$ | async as gitSCMRepo"></app-list>
</app-tile-grid>
<app-no-content-message *ngIf="(hasRepo$ | async) === false" [iconFont]="(icon$ | async)?.fontName"
[icon]="(icon$ | async)?.iconName" [firstLine]="noContentFirstLine" [secondLine]="noContentSecondLine"
[otherLines]="noContentOtherLines">
</app-no-content-message>
</div>
</app-loading-page>
Loading

0 comments on commit 3363703

Please sign in to comment.