Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autocomplete git repository name #3372

Merged
merged 13 commits into from
Feb 14, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import { generateTestEntityServiceProvider } from '../../../../test-framework/en
import { createBasicStoreModule } from '../../../../test-framework/store-test-helper';
import { ApplicationEnvVarsHelper } from './../application-tabs-base/tabs/build-tab/application-env-vars.service';
import { ApplicationTabsBaseComponent } from './application-tabs-base.component';
import { HttpModule, Http, ConnectionBackend } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../core/github.helpers';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('ApplicationTabsBaseComponent', () => {
let component: ApplicationTabsBaseComponent;
Expand All @@ -38,7 +38,8 @@ describe('ApplicationTabsBaseComponent', () => {
RouterTestingModule,
MDAppModule,
createBasicStoreModule(),
HttpModule
HttpClientModule,
HttpClientTestingModule
],
providers: [
generateTestEntityServiceProvider(
Expand All @@ -49,11 +50,6 @@ describe('ApplicationTabsBaseComponent', () => {
generateTestApplicationServiceProvider(cfId, appId),
ApplicationStateService,
ApplicationEnvVarsHelper,
Http,
{
provide: ConnectionBackend,
useClass: MockBackend
},
{ provide: GITHUB_API_URL, useFactory: getGitHubAPIURL }
]
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { ApplicationService } from '../../../../application.service';
import { ApplicationEnvVarsHelper } from './application-env-vars.service';
import { BuildTabComponent } from './build-tab.component';
import { ViewBuildpackComponent } from './view-buildpack/view-buildpack.component';
import { HttpModule, Http, ConnectionBackend } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../../../core/github.helpers';
import { GITHUB_API_URL } from '../../../../../../core/github.helpers';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('BuildTabComponent', () => {
let component: BuildTabComponent;
Expand All @@ -41,18 +41,14 @@ describe('BuildTabComponent', () => {
initialState
}
),
HttpModule
HttpClientModule,
HttpClientTestingModule
],
providers: [
{ provide: ApplicationService, useClass: ApplicationServiceMock },
AppStoreModule,
ApplicationStateService,
ApplicationEnvVarsHelper,
Http,
{
provide: ConnectionBackend,
useClass: MockBackend
},
{ provide: GITHUB_API_URL, useValue: null }
]
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { GitSCMTabComponent } from './gitscm-tab.component';
import { DatePipe } from '@angular/common';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../../../core/github.helpers';
import { HttpModule, Http, ConnectionBackend } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('GitSCMTabComponent', () => {
let component: GitSCMTabComponent;
Expand All @@ -34,17 +34,13 @@ describe('GitSCMTabComponent', () => {
}
),
NoopAnimationsModule,
HttpModule
HttpClientModule,
HttpClientTestingModule
],
providers: [
{ provide: ApplicationService, useClass: ApplicationServiceMock },
{ provide: GITHUB_API_URL, useFactory: getGitHubAPIURL },
DatePipe,
Http,
{
provide: ConnectionBackend,
useClass: MockBackend
}
]
})
.compileComponents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { CommonModule, DatePipe } from '@angular/common';
import { CoreModule } from '../../../../../core/core.module';
import { SharedModule } from '../../../../../shared/shared.module';
import { createBasicStoreModule } from '../../../../../test-framework/store-test-helper';
import { HttpModule, Http, ConnectionBackend } from '@angular/http';
import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../../core/github.helpers';
import { MockBackend } from '@angular/http/testing';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('CommitListWrapperComponent', () => {
let component: CommitListWrapperComponent;
Expand All @@ -21,16 +21,12 @@ describe('CommitListWrapperComponent', () => {
CoreModule,
SharedModule,
createBasicStoreModule(),
HttpModule
HttpClientModule,
HttpClientTestingModule
],
providers: [
DatePipe,
{ provide: GITHUB_API_URL, useFactory: getGitHubAPIURL },
Http,
{
provide: ConnectionBackend,
useClass: MockBackend
}
]
})
.compileComponents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
<div class="github-project-details">
<div>
<mat-form-field>
<input matInput [disabled]="isRedeploy" [(ngModel)]="repository" placeholder="Project" name="projectName" [appGithubProjectExists]="sourceType.id" required>
<input type="text" matInput [matAutocomplete]="auto" [disabled]="isRedeploy" [(ngModel)]="repository" placeholder="Project" name="projectName" [appGithubProjectExists]="sourceType.id" required>
<!-- Repository auto complete helper -->
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let repo of suggestedRepos$ | async" [value]="repo">{{repo}}</mat-option>
</mat-autocomplete>

<mat-error *ngIf="sourceSelectionForm.controls.projectName?.errors?.githubProjectDoesNotExist && !sourceSelectionForm.controls.projectName?.errors?.githubProjectError">
Project does not exist
</mat-error>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { GitSCMService } from './../../../../shared/data-services/scm/scm.service';
import { CoreModule } from '../../../../core/core.module';
import { SharedModule } from '../../../../shared/shared.module';
import { inject, TestBed, ComponentFixture, async, fakeAsync, tick } from '@angular/core/testing';
import { Store, StoreModule } from '@ngrx/store';
import { TestBed, ComponentFixture, async } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { createBasicStoreModule } from '../../../../test-framework/store-test-helper';
import { RouterTestingModule } from '@angular/router/testing';
import { MatDialogModule } from '@angular/material';

import { DeployApplicationStep2Component } from './deploy-application-step2.component';
import { DeployApplicationFsComponent } from './deploy-application-fs/deploy-application-fs.component';
import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../core/github.helpers';
import { HttpModule, Http, ConnectionBackend } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { GithubProjectExistsDirective } from '../github-project-exists.directive';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('DeployApplicationStep2Component', () => {
let component: DeployApplicationStep2Component;
Expand All @@ -33,15 +31,11 @@ describe('DeployApplicationStep2Component', () => {
RouterTestingModule,
createBasicStoreModule(),
BrowserAnimationsModule,
HttpModule
HttpClientModule,
HttpClientTestingModule
],
providers: [
{ provide: GITHUB_API_URL, useFactory: getGitHubAPIURL },
Http,
{
provide: ConnectionBackend,
useClass: MockBackend
},
GitSCMService
]
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { AfterContentInit, Component, Inject, Input, OnDestroy, OnInit, ViewChil
import { NgForm } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
import { filter, map, take, tap, withLatestFrom } from 'rxjs/operators';
import { combineLatest as observableCombineLatest, Observable, timer as observableTimer, of as observableOf, Subscription } from 'rxjs';
import { filter, map, take, tap, withLatestFrom, switchMap, startWith, pairwise, catchError } from 'rxjs/operators';

import { EntityServiceFactory } from '../../../../core/entity-service-factory.service';
import { StepOnNextFunction } from '../../../../shared/components/stepper/step/step.component';
Expand Down Expand Up @@ -76,6 +76,11 @@ export class DeployApplicationStep2Component

scm: GitSCM;

// We don't have any repositories to suggest initially - need user to start typing
suggestedRepos$: Observable<string[]>;

cachedSuggestions = {};

// Local FS data when file or folder upload
// @Input('fsSourceData') fsSourceData;

Expand Down Expand Up @@ -274,6 +279,32 @@ export class DeployApplicationStep2Component
this.subscriptions.push(setInitialSourceType$.subscribe());
this.subscriptions.push(setSourceTypeModel$.subscribe());
this.subscriptions.push(setProjectName.subscribe());

this.suggestedRepos$ = this.sourceSelectionForm.valueChanges.pipe(
map(form => form.projectName),
startWith(''),
pairwise(),
filter(([oldName, newName]) => oldName !== newName),
switchMap(([oldName, newName]) => this.updateSuggestedRepositories(newName))
);
}

updateSuggestedRepositories(name: string): Observable<string[]> {
if (!name || name.length < 3) {
return observableOf([] as string[]);
}

const cacheName = this.scm.getType() + ':' + name;
if (this.cachedSuggestions[cacheName]) {
return observableOf(this.cachedSuggestions[cacheName]);
}

return observableTimer(500).pipe(
take(1),
switchMap(() => this.scm.getMatchingRepositories(name)),
catchError(_e => observableOf(null)),
tap(suggestions => this.cachedSuggestions[cacheName] = suggestions)
);
}

setSourceType = event => this.store.dispatch(new SetAppSourceDetails(event));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { Store } from '@ngrx/store';
import { inject, TestBed } from '@angular/core/testing';
import { CommonModule } from '@angular/common';
Expand All @@ -9,6 +9,7 @@ import { AppState } from '../../../store/app-state';
import { GitSCMService } from '../../../shared/data-services/scm/scm.service';
import { GithubProjectExistsDirective } from './github-project-exists.directive';
import { GITHUB_API_URL, getGitHubAPIURL } from '../../../core/github.helpers';
import { HttpClientTestingModule } from '@angular/common/http/testing';


describe('GithubProjectExistsDirective', () => {
Expand All @@ -19,7 +20,8 @@ describe('GithubProjectExistsDirective', () => {
CoreModule,
SharedModule,
createBasicStoreModule(),
HttpModule
HttpClientModule,
HttpClientTestingModule
],
providers: [
{ provide: GITHUB_API_URL, useFactory: getGitHubAPIURL }
Expand Down
36 changes: 21 additions & 15 deletions src/frontend/app/shared/data-services/scm/github-scm.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { GitSCM, SCMIcon } from './scm';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Http } from '@angular/http';
import { map, filter } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { GitSCMType } from './scm.service';
import { GitRepo, GitCommit, GitBranch } from '../../../store/types/git.types';

export class GitHubSCM implements GitSCM {

constructor(public http: Http, public gitHubURL: string) {}
constructor(public httpClient: HttpClient, public gitHubURL: string) {}

getType(): GitSCMType {
return 'github';
Expand All @@ -25,27 +25,19 @@ export class GitHubSCM implements GitSCM {
}

getRepository(projectName: string): Observable<GitRepo> {
return this.http.get(`${this.gitHubURL}/repos/${projectName}`).pipe(
map(response => response.json())
);
return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}`) as Observable<GitRepo>;
}

getBranches(projectName: string): Observable<GitBranch[]> {
return this.http.get(`${this.gitHubURL}/repos/${projectName}/branches`).pipe(
map(response => response.json())
);
return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}/branches`) as Observable<GitBranch[]>;
}

getCommit(projectName: string, commitSha: string): Observable<GitCommit> {
return this.http.get(`${this.gitHubURL}/repos/${projectName}/commits/${commitSha}`).pipe(
map(response => response.json())
);
return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}/commits/${commitSha}`) as Observable<GitCommit>;
}

getCommits(projectName: string, commitSha: string): Observable<GitCommit[]> {
return this.http.get(`${this.gitHubURL}/repos/${projectName}/commits?sha=${commitSha}`).pipe(
map(response => response.json())
);
return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}/commits?sha=${commitSha}`) as Observable<GitCommit[]>;
}

getCloneURL(projectName: string): string {
Expand All @@ -60,4 +52,18 @@ export class GitHubSCM implements GitSCM {
return `https://github.com/${projectName}/compare/${commitSha1}...${commitSha2}`;
}

getMatchingRepositories(projectName: string): Observable<string[]> {
const prjParts = projectName.split('/');
let url = `${this.gitHubURL}/search/repositories?q=${projectName}+in:name`;
if (prjParts.length > 1) {
url = `${this.gitHubURL}/search/repositories?q=${prjParts[1]}+in:name+user:${prjParts[0]}`;
}
return this.httpClient.get(url).pipe(
filter((repos: any) => !!repos.items),
map(repos => {
return repos.items.map(item => item.full_name);
})
);
}

}
Loading