Skip to content

Commit

Permalink
feat: adds migrations
Browse files Browse the repository at this point in the history
  • Loading branch information
Ken Howard committed Nov 29, 2018
1 parent 9ef1fba commit 7c9518e
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 11 deletions.
19 changes: 16 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ import {
import { DEBUG } from './constants';
import { insights } from './insights';
import { Levels, logger } from './logger';
import { extensionMigrations, migrations } from './migrations';
import { profiles } from './profiles';

export function activate(context: ExtensionContext): void {
logger.setLevel(DEBUG ? Levels.DEBUG : Levels.ERROR);

logger.debug('extension activated');

migrations.configure({
migrations: extensionMigrations,
state: context.globalState
});
profiles.configure({ state: context.globalState });

/**
Expand Down Expand Up @@ -46,10 +51,18 @@ export function activate(context: ExtensionContext): void {
/**
* Execute Startup Commands
*/
commands.executeCommand('extension.updateStatusBar');
commands.executeCommand('extension.updateGistAccessKey');
migrations.up((err, results) => {
commands.executeCommand('extension.updateStatusBar');
commands.executeCommand('extension.updateGistAccessKey');

insights.track('activated');
if (err) {
insights.exception('migrations', { message: err.message });
}

insights.track('activated', undefined, {
migrationCount: results.migrated.length
});
});

commands.registerCommand(
'extension.openFavoriteCodeBlock',
Expand Down
4 changes: 0 additions & 4 deletions src/insights/telemetry-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import {
TELEMETRY_WRITE_KEY
} from '../constants';

interface Extension {
packageJSON: { version: string };
}

const extensionId = 'kenhowardpdx.vscode-gist';
const extension = extensions.getExtension(extensionId) as Extension;
const extensionVersion =
Expand Down
32 changes: 32 additions & 0 deletions src/migrations/__tests__/migrate-2.0.0.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// tslint:disable:no-magic-numbers no-any

import { GISTS_BASE_URL } from '../../constants';

import { up } from '../migrate-2.0.0';

const state = {
get: jest.fn(),
update: jest.fn()
};

describe('Migrate to 2.0.0 Tests', () => {
test('should retrieve gisttoken and create a new profile', () => {
expect.assertions(3);

state.get.mockReturnValueOnce('myaccesstoken');

up(state, () => {
// return void
});

expect(state.update.mock.calls[0]).toStrictEqual(['gisttoken', undefined]);
expect(state.update.mock.calls[1]).toStrictEqual([
'gist_provider',
undefined
]);
expect(state.update.mock.calls[2]).toStrictEqual([
'profiles',
{ github: { active: true, key: 'myaccesstoken', url: GISTS_BASE_URL } }
]);
});
});
29 changes: 29 additions & 0 deletions src/migrations/__tests__/migration-service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// tslint:disable:no-magic-numbers no-any

import { migrations } from '../migration-service';

const state = {
get: jest.fn(() => ''),
update: jest.fn()
};

describe('Migrations Tests', () => {
test('should process migrations', () => {
expect.assertions(3);

const migrationCallback = jest.fn((_s, c) => {
c();
});

const migrationOne: any = ['mymigrationone', migrationCallback];
const migrationTwo: any = ['mygrationtwo', migrationCallback];
const finalCallback = jest.fn();

migrations.configure({ migrations: [migrationOne, migrationTwo], state });
migrations.up(finalCallback);

expect(finalCallback).toHaveBeenCalled();
expect(state.update.mock.calls).toHaveLength(2);
expect(migrationCallback.mock.calls).toHaveLength(2);
});
});
2 changes: 2 additions & 0 deletions src/migrations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './migration-service';
export * from './migrations';
26 changes: 26 additions & 0 deletions src/migrations/migrate-2.0.0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Memento } from 'vscode';

import { GISTS_BASE_URL } from '../constants';

export const up = (
state: Memento,
cb: (err: Error | undefined) => void
): void => {
let error: Error | undefined;
try {
const key = state.get<string>('gisttoken');
state.update('gisttoken', undefined);
state.update('gist_provider', undefined);
if (key) {
const url = GISTS_BASE_URL;
const name = 'github';
const active = true;

state.update('profiles', { [name]: { active, key, url } });
}
} catch (err) {
error = err;
}

cb(error);
};
70 changes: 70 additions & 0 deletions src/migrations/migration-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Memento, workspace } from 'vscode';

import { logger } from '../logger';

type Migration = [
string,
(state: Memento, callback: (error?: Error) => void) => void
];

class MigrationService {
public static getInstance = (): MigrationService =>
(MigrationService.instance = MigrationService.instance
? MigrationService.instance
: new MigrationService())

private static instance?: MigrationService;

private migrations: Migration[] = [];
private state: Memento = workspace.getConfiguration();

private constructor() {}

public configure(options: { migrations: Migration[]; state: Memento }): void {
this.state = options.state;
this.migrations = options.migrations;
}

public up(
cb: (err: Error | undefined, results: { migrated: string[] }) => void
): void {
const migrated: string[] = [];
let error: Error | undefined;

try {
this.migrations.forEach((m) => {
const [migrationName, migrationFn] = m;
if (this.do(migrationName)) {
logger.debug(`migrating ${migrationName}`);
migrationFn(this.state, (err) => {
if (err) {
logger.error(`could not migrate to ${migrationName}`);
throw err;
}
this.recordMigration(migrationName);
migrated.push(migrationName);
});
}
});
} catch (err) {
error = err;
}

cb(error, { migrated });
}

private do(migrationName: string): boolean {
const pastMigrations = this.state.get('migrations', '').split(';');

return pastMigrations.indexOf(migrationName) === -1;
}

private recordMigration(migrationName: string): void {
const pastMigrations = this.state.get('migrations', '').split(';');
pastMigrations.push(migrationName);
this.state.update('migrations', pastMigrations.join(';'));
logger.debug(`Applied Migration: ${migrationName}`);
}
}

export const migrations = MigrationService.getInstance();
7 changes: 7 additions & 0 deletions src/migrations/migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Memento } from 'vscode';

import { up as up200 } from './migrate-2.0.0';

export const extensionMigrations: Array<
[string, (state: Memento, cb: (err: Error | undefined) => void) => void]
> = [['2.0.0', up200]];
8 changes: 4 additions & 4 deletions src/profiles/profile-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ class ProfileService {
[profile]: { key: p[profile].key, url: p[profile].url, active: false }
}))
.reduce((prev, curr) => ({ ...prev, ...curr }), {});
this.state.update(
'profiles',
JSON.stringify({ ...currentState, [name]: { active, key, url } })
);
this.state.update('profiles', {
...currentState,
[name]: { active, key, url }
});
}

public configure(options: { state: Memento }): void {
Expand Down
4 changes: 4 additions & 0 deletions src/typings/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ interface RawProfile {
interface Profile extends RawProfile {
name: string;
}

interface Extension {
packageJSON: { version: string };
}

0 comments on commit 7c9518e

Please sign in to comment.