Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #139 from seokju-na/geeks-diary-137
Browse files Browse the repository at this point in the history
Keep directory when note label included
  • Loading branch information
seokju-na authored Dec 31, 2018
2 parents 90a9eb2 + 1c61d13 commit 548401a
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/browser/app/app-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const AppVcsHistoryChangedEffectActionsProvider: Provider = {
provide: VCS_HISTORY_CHANGED_EFFECT_ACTIONS,
useValue: [
NoteCollectionActionTypes.LOAD_COLLECTION_COMPLETE, // Initial load
NoteCollectionActionTypes.ADD_NOTE,
],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { makeNoteContentFileName } from '../../../../core/note';
import { SharedModule, WORKSPACE_DEFAULT_CONFIG, WorkspaceConfig } from '../../../shared';
import { DialogRef } from '../../../ui/dialog';
import { UiModule } from '../../../ui/ui.module';
import { VcsService } from '../../../vcs';
import { NoteContentFileAlreadyExistsError, NoteOutsideWorkspaceError } from '../../note-errors';
import { NoteCollectionService } from '../note-collection.service';
import { CreateNewNoteDialogComponent } from './create-new-note-dialog.component';
Expand All @@ -20,6 +21,7 @@ describe('browser.note.noteCollection.CreateNewNoteDialogComponent', () => {
let collection: NoteCollectionService;
let mockDialog: MockDialog;
let mockDialogRef: MockDialogRef<CreateNewNoteDialogComponent>;
let vcs: VcsService;

const workspaceConfigs: WorkspaceConfig = {
rootDirPath: '/test/workspace/',
Expand Down Expand Up @@ -67,6 +69,10 @@ describe('browser.note.noteCollection.CreateNewNoteDialogComponent', () => {
CreateNewNoteDialogComponent,
);

vcs = jasmine.createSpyObj('vcs', [
'keepDirectory',
]);

await TestBed
.configureTestingModule({
imports: [
Expand All @@ -77,6 +83,7 @@ describe('browser.note.noteCollection.CreateNewNoteDialogComponent', () => {
{ provide: NoteCollectionService, useValue: collection },
{ provide: WORKSPACE_DEFAULT_CONFIG, useValue: workspaceConfigs },
{ provide: DialogRef, useValue: mockDialogRef },
{ provide: VcsService, useValue: vcs },
],
declarations: [
CreateNewNoteDialogComponent,
Expand Down Expand Up @@ -213,4 +220,23 @@ describe('browser.note.noteCollection.CreateNewNoteDialogComponent', () => {
expect(callback).toHaveBeenCalled();
subscription.unsubscribe();
});

it('should call \'keepDirectory\' if label exists.', fakeAsync(() => {
typeInElement('some title', getTitleInputEl());
typeInElement('label', getLabelInputEl());
getTitleInputEl().blur();
getLabelInputEl().blur();

fixture.detectChanges();

(collection.createNewNote as jasmine.Spy).and.returnValue(Promise.resolve(null));
(vcs.keepDirectory as jasmine.Spy).and.returnValue(Promise.resolve(null));

submitForm();
flush();

expect(vcs.keepDirectory).toHaveBeenCalledWith(
path.resolve(workspaceConfigs.rootDirPath, 'label'),
);
}));
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { FormControl, FormGroup, Validators } from '@angular/forms';
import * as path from 'path';
import { Subscription } from 'rxjs';
import { startWith } from 'rxjs/operators';
import { ErrorWithMetadata } from '../../../../core/error-with-metadata';
import { makeNoteContentFileName } from '../../../../core/note';
import { datetime } from '../../../../libs/datetime';
import { WorkspaceService } from '../../../shared';
import { DialogRef } from '../../../ui/dialog';
import { ConfirmDialogComponent, ConfirmDialogData } from '../../../shared/confirm-dialog';
import { Dialog, DialogRef } from '../../../ui/dialog';
import { VcsService } from '../../../vcs';
import { NoteContentFileAlreadyExistsError, NoteOutsideWorkspaceError } from '../../note-errors';
import { NoteCollectionService } from '../note-collection.service';

Expand All @@ -15,6 +18,7 @@ import { NoteCollectionService } from '../note-collection.service';
selector: 'gd-create-new-note-dialog',
templateUrl: './create-new-note-dialog.component.html',
styleUrls: ['./create-new-note-dialog.component.scss'],
providers: [Dialog],
})
export class CreateNewNoteDialogComponent implements OnInit, OnDestroy {
private _createNewNoteProcessing = false;
Expand All @@ -34,6 +38,8 @@ export class CreateNewNoteDialogComponent implements OnInit, OnDestroy {
private dialogRef: DialogRef<CreateNewNoteDialogComponent, void>,
private workspace: WorkspaceService,
private collection: NoteCollectionService,
private vcs: VcsService,
private dialog: Dialog,
) {
}

Expand All @@ -54,6 +60,13 @@ export class CreateNewNoteDialogComponent implements OnInit, OnDestroy {

try {
await this.collection.createNewNote(title, label);

if (label) {
await this.vcs.keepDirectory(
path.resolve(this.workspace.configs.rootDirPath, label),
);
}

this.handleCreateNewNoteSuccess();
} catch (error) {
this.handleCreateNewNoteFail(error);
Expand Down Expand Up @@ -87,7 +100,18 @@ export class CreateNewNoteDialogComponent implements OnInit, OnDestroy {
} else if (error instanceof NoteOutsideWorkspaceError) {
this.createNewNoteFormGroup.get('label').setErrors({ outsideWorkspace: true });
} else {
// TODO : Handle unknown error. What should we do in here?
this.dialog.open<ConfirmDialogComponent, ConfirmDialogData>(
ConfirmDialogComponent,
{
maxWidth: '320px',
data: {
body: error && (error as any).errorDescription
? (error as ErrorWithMetadata).errorDescription
: error.message,
isAlert: true,
},
},
);
}
}
}
5 changes: 5 additions & 0 deletions src/browser/shared/fs.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
readdir,
readFile,
readJson,
remove,
writeFile,
writeJson,
} from 'fs-extra';
Expand Down Expand Up @@ -64,4 +65,8 @@ export class FsService {
return from(move(oldFileName, newFileName, { overwrite: false }))
.pipe(enterZone(this.ngZone));
}

removeFile(fileName: string): Observable<void> {
return from(remove(fileName)).pipe(enterZone(this.ngZone));
}
}
74 changes: 72 additions & 2 deletions src/browser/vcs/vcs.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { fakeAsync, flush, TestBed } from '@angular/core/testing';
import { Observable, of, throwError } from 'rxjs';
import { fastTestSetup } from '../../../test/helpers';
import { MockFsService } from '../../../test/mocks/browser';
import { VcsAccountDummy } from '../../core/dummies';
import {
GitFindRemoteOptions,
GitRemoteNotFoundError,
GitSetRemoteOptions,
GitSyncWithRemoteOptions,
} from '../../core/git';
import { VcsAccount, VcsAuthenticationInfo, VcsAuthenticationTypes, VcsRemoteRepository } from '../../core/vcs';
import {
VcsAccount,
VcsAuthenticationInfo,
VcsAuthenticationTypes,
VcsFileChange,
VcsFileChangeStatusTypes,
VcsRemoteRepository,
} from '../../core/vcs';
import { toPromise } from '../../libs/rx';
import { GitService, SharedModule, WORKSPACE_DEFAULT_CONFIG, WorkspaceConfig } from '../shared';
import { FsService, GitService, SharedModule, WORKSPACE_DEFAULT_CONFIG, WorkspaceConfig } from '../shared';
import { VCS_ACCOUNT_DATABASE, VcsAccountDatabase, VcsAccountDatabaseProvider } from './vcs-account-database';
import { VcsRemoteModule, VcsRemoteProvider, VcsRemoteProviderFactory } from './vcs-remote';
import { VcsService } from './vcs.service';
Expand Down Expand Up @@ -49,6 +57,7 @@ describe('browser.vcs.VcsService', () => {
let removeProviderFactory: VcsRemoteProviderFactory;
let accountDB: VcsAccountDatabase;
let git: GitService;
let mockFs: MockFsService;

const accountDummy = new VcsAccountDummy();
const workspaceConfig: WorkspaceConfig = {
Expand All @@ -68,6 +77,7 @@ describe('browser.vcs.VcsService', () => {
VcsAccountDatabaseProvider,
VcsService,
{ provide: WORKSPACE_DEFAULT_CONFIG, useValue: workspaceConfig },
...MockFsService.providers(),
],
});
});
Expand All @@ -77,6 +87,7 @@ describe('browser.vcs.VcsService', () => {
removeProviderFactory = TestBed.get(VcsRemoteProviderFactory);
accountDB = TestBed.get(VCS_ACCOUNT_DATABASE);
git = TestBed.get(GitService);
mockFs = TestBed.get(FsService);

spyOn(removeProviderFactory, 'create').and.returnValue(new TestVcsRemoteProvider());
vcs.setRemoveProvider('test' as any);
Expand All @@ -85,6 +96,8 @@ describe('browser.vcs.VcsService', () => {
afterEach(async () => {
await accountDB.accounts.clear();
await accountDB.metadata.clear();

mockFs.verify();
});

describe('loginRemoteWithBasicAuthorization', () => {
Expand Down Expand Up @@ -236,6 +249,63 @@ describe('browser.vcs.VcsService', () => {
describe('fetchMoreCommitHistory', () => {
});

describe('keepDirectory', () => {
it('should do nothing if keep file already exists.', fakeAsync(() => {
spyOn(git, 'commit');

vcs.keepDirectory('/test/workspace/label').then();

mockFs
.expect({
methodName: 'isPathExists',
args: ['/test/workspace/label/.gitkeep'],
})
.flush(true);

expect(git.commit).not.toHaveBeenCalled();
}));

it('should create keep file and commit if keep file is not exists.', fakeAsync(() => {
const keepFilePath = '/test/workspace/label/.gitkeep';

spyOn(git, 'commit').and.returnValue(of(null));

vcs.keepDirectory('/test/workspace/label').then();

mockFs
.expect({
methodName: 'isPathExists',
args: [keepFilePath],
})
.flush(false);

mockFs
.expect({
methodName: 'writeFile',
args: [keepFilePath, ''],
})
.flush(null);

expect(git.commit).toHaveBeenCalledWith(
'/test/workspace',
{
name: 'Geeks Diary',
email: '(BLANK)',
authentication: null,
} as VcsAccount,
{ summary: 'Keep Directory', description: '' },
[
{
status: VcsFileChangeStatusTypes.NEW,
filePath: 'label/.gitkeep',
absoluteFilePath: keepFilePath,
workingDirectoryPath: '/test/workspace',
},
] as VcsFileChange[],
);
}));
});

describe('canSyncRepository', () => {
it('should return true if fetch account and remote exists.', async () => {
const fetchAccount = accountDummy.create();
Expand Down
44 changes: 42 additions & 2 deletions src/browser/vcs/vcs.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { Inject, Injectable } from '@angular/core';
import * as path from 'path';
import { from, Observable, of, throwError, zip } from 'rxjs';
import { catchError, filter, map, mapTo, switchMap, tap } from 'rxjs/operators';
import { GitError, GitErrorCodes, GitGetHistoryOptions, GitSyncWithRemoteResult } from '../../core/git';
import { VcsAccount, VcsAuthenticationInfo, VcsCommitItem, VcsFileChange, VcsRemoteRepository } from '../../core/vcs';
import {
VcsAccount,
VcsAuthenticationInfo,
VcsCommitItem,
VcsFileChange,
VcsFileChangeStatusTypes,
VcsRemoteRepository,
} from '../../core/vcs';
import { toPromise } from '../../libs/rx';
import { GitService, WorkspaceService } from '../shared';
import { FsService, GitService, WorkspaceService } from '../shared';
import { VCS_ACCOUNT_DATABASE, VcsAccountDatabase } from './vcs-account-database';
import { VcsRemoteProvider, VcsRemoteProviderFactory, VcsRemoteProviderType } from './vcs-remote';

Expand Down Expand Up @@ -37,6 +45,7 @@ export class VcsService {
private git: GitService,
@Inject(VCS_ACCOUNT_DATABASE) private accountDB: VcsAccountDatabase,
private workspace: WorkspaceService,
private fs: FsService,
) {
}

Expand Down Expand Up @@ -139,6 +148,37 @@ export class VcsService {
);
}

async keepDirectory(directoryPath: string): Promise<void> {
const workspaceDirPath = this.workspace.configs.rootDirPath;
const keepFilePath = path.resolve(directoryPath, '.gitkeep');

if (await toPromise(this.fs.isPathExists(keepFilePath))) {
return;
}

try {
await toPromise(this.fs.writeFile(keepFilePath, ''));
await toPromise(this.git.commit(
workspaceDirPath,
{
name: 'Geeks Diary',
email: '(BLANK)',
authentication: null,
},
{ summary: 'Keep Directory', description: '' },
[{
status: VcsFileChangeStatusTypes.NEW,
filePath: path.relative(workspaceDirPath, keepFilePath),
absoluteFilePath: keepFilePath,
workingDirectoryPath: workspaceDirPath,
}],
));
} catch (error) {
await toPromise(this.fs.removeFile(keepFilePath));
throw error;
}
}

cloneRepository(
sourceUrl: string,
distLocalPath: string,
Expand Down
Loading

0 comments on commit 548401a

Please sign in to comment.