feat: create remote via DI container
This commit is contained in:
parent
ceafdbab8a
commit
a38c130e73
|
@ -7,9 +7,9 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
connect(): Promise<void>;
|
||||
connect(): Promise<boolean>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<void>
|
||||
Promise<boolean>
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [GitlabRemote](./cautious-journey.gitlabremote.md) > [connect](./cautious-journey.gitlabremote.connect.md)
|
||||
|
||||
## GitlabRemote.connect() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
connect(): Promise<boolean>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<boolean>
|
||||
|
|
@ -23,6 +23,7 @@ export declare class GitlabRemote implements Remote
|
|||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [connect()](./cautious-journey.gitlabremote.connect.md) | | |
|
||||
| [createComment()](./cautious-journey.gitlabremote.createcomment.md) | | |
|
||||
| [createLabel()](./cautious-journey.gitlabremote.createlabel.md) | | |
|
||||
| [deleteLabel()](./cautious-journey.gitlabremote.deletelabel.md) | | |
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [Remote](./cautious-journey.remote.md) > [connect](./cautious-journey.remote.connect.md)
|
||||
|
||||
## Remote.connect() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
connect(): Promise<boolean>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<boolean>
|
||||
|
|
@ -16,6 +16,7 @@ export interface Remote
|
|||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [connect()](./cautious-journey.remote.connect.md) | |
|
||||
| [createComment(options)](./cautious-journey.remote.createcomment.md) | Add a comment to an issue (for attribution and auditing). |
|
||||
| [createLabel(options)](./cautious-journey.remote.createlabel.md) | Create a new label. |
|
||||
| [deleteLabel(options)](./cautious-journey.remote.deletelabel.md) | Delete an existing label. |
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface RemoteOptions
|
||||
export interface RemoteOptions extends BaseOptions
|
||||
```
|
||||
<b>Extends:</b> BaseOptions
|
||||
|
||||
## Properties
|
||||
|
||||
|
|
15
src/main.ts
15
src/main.ts
|
@ -1,10 +1,13 @@
|
|||
import { doesExist, InvalidArgumentError } from '@apextoaster/js-utils';
|
||||
import { Container } from 'noicejs';
|
||||
import { alea } from 'seedrandom';
|
||||
|
||||
import { initConfig } from './config';
|
||||
import { Commands, createParser } from './config/args';
|
||||
import { dotGraph, graphLabels } from './graph';
|
||||
import { BunyanLogger } from './logger/bunyan';
|
||||
import { RemoteModule } from './module/RemoteModule';
|
||||
import { Remote, RemoteOptions } from './remote';
|
||||
import { GithubRemote } from './remote/github';
|
||||
import { syncIssueLabels, SyncOptions, syncProjectLabels } from './sync';
|
||||
import { VERSION_INFO } from './version';
|
||||
|
@ -34,6 +37,9 @@ export async function main(argv: Array<string>): Promise<number> {
|
|||
config,
|
||||
}, 'runtime data');
|
||||
|
||||
const container = Container.from(new RemoteModule());
|
||||
await container.configure();
|
||||
|
||||
for (const project of config.projects) {
|
||||
const { name } = project;
|
||||
|
||||
|
@ -43,13 +49,18 @@ export async function main(argv: Array<string>): Promise<number> {
|
|||
}
|
||||
|
||||
const random = alea(name);
|
||||
const remote = new GithubRemote({
|
||||
const remote = await container.create<Remote, RemoteOptions>(project.remote.type, {
|
||||
data: project.remote.data,
|
||||
dryrun: args.dryrun || project.remote.dryrun || false,
|
||||
logger,
|
||||
type: project.remote.type,
|
||||
});
|
||||
await remote.connect();
|
||||
|
||||
const connected = await remote.connect();
|
||||
if (!connected) {
|
||||
logger.error({ type: project.remote.type }, 'unable to connect to remote');
|
||||
return 1;
|
||||
}
|
||||
|
||||
// mode switch
|
||||
const options: SyncOptions = {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { Module, ModuleOptions } from 'noicejs';
|
||||
|
||||
import { Remote, RemoteOptions } from '../remote';
|
||||
import { GithubRemote } from '../remote/github';
|
||||
import { GitlabRemote } from '../remote/gitlab';
|
||||
import { kebabCase } from '../utils';
|
||||
|
||||
export class RemoteModule extends Module {
|
||||
public async configure(options: ModuleOptions) {
|
||||
await super.configure(options);
|
||||
|
||||
this.bind<Remote, GithubRemote, RemoteOptions>(kebabCase(GithubRemote.name)).toConstructor(GithubRemote);
|
||||
this.bind<Remote, GitlabRemote, RemoteOptions>(kebabCase(GitlabRemote.name)).toConstructor(GitlabRemote);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ export class GithubRemote implements Remote {
|
|||
this.options.logger.debug(options, 'created github remote');
|
||||
}
|
||||
|
||||
public async connect() {
|
||||
public async connect(): Promise<boolean> {
|
||||
this.options.logger.info('connecting to github');
|
||||
|
||||
const type = mustExist(this.options.data.type);
|
||||
|
@ -48,6 +48,8 @@ export class GithubRemote implements Remote {
|
|||
default:
|
||||
throw new InvalidArgumentError('unknown authentication type');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async splitProject(project: string): Promise<{
|
||||
|
|
|
@ -11,7 +11,11 @@ export class GitlabRemote implements Remote {
|
|||
// TODO: set up gitlab API
|
||||
}
|
||||
|
||||
public async createComment() {
|
||||
public async connect(): Promise<boolean> {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
public async createComment(): Promise<void> {
|
||||
throw new NotImplementedError();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Logger } from 'noicejs';
|
||||
import { BaseOptions, Logger } from 'noicejs';
|
||||
|
||||
import { ChangeRecord, ErrorRecord } from '../resolve';
|
||||
|
||||
export interface ProjectQuery {
|
||||
|
@ -32,7 +33,7 @@ export interface LabelUpdate extends LabelQuery {
|
|||
desc: string;
|
||||
}
|
||||
|
||||
export interface RemoteOptions {
|
||||
export interface RemoteOptions extends BaseOptions {
|
||||
/**
|
||||
* Arbitrary key-value data for this remote, usually credentials and base URLs.
|
||||
*/
|
||||
|
@ -55,6 +56,8 @@ export interface RemoteOptions {
|
|||
* Basic functions which every remote API must provide.
|
||||
*/
|
||||
export interface Remote {
|
||||
connect(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Add a comment to an issue (for attribution and auditing).
|
||||
*/
|
||||
|
|
|
@ -35,3 +35,11 @@ export function compareItems<T>(a: Array<T>, b: Array<T>): boolean {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function kebabCase(name: string): string {
|
||||
return name
|
||||
.replace(/([A-Z])/g, (m: string, p1: string) => `-${p1.toLocaleLowerCase()}`) // capitals
|
||||
.replace(/[^-a-z0-9]/g, '-') // non-alnum
|
||||
.replace(/--+/g, '-') // duplicates
|
||||
.replace(/(^-|-$)/g, ''); // leading/trailing
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { expect } from 'chai';
|
||||
|
||||
import { defaultTo, defaultUntil, compareItems } from '../src/utils';
|
||||
import { defaultTo, defaultUntil, compareItems, kebabCase } from '../src/utils';
|
||||
|
||||
const TEST_TRUE = 'foo';
|
||||
const TEST_FALSE = 'bar';
|
||||
|
@ -64,4 +64,31 @@ describe('utils', () => {
|
|||
)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('kebab case helper', () => {
|
||||
it('should replace non-alnum characters with dashes', () => {
|
||||
expect(kebabCase('1_2,3+4')).to.equal('1-2-3-4');
|
||||
});
|
||||
|
||||
it('should lowercase the value', () => {
|
||||
expect(kebabCase('ABC')).to.equal('a-b-c');
|
||||
expect(kebabCase('A-B-C')).to.equal('a-b-c');
|
||||
});
|
||||
|
||||
it('should remove leading dashes', () => {
|
||||
expect(kebabCase('--1')).to.equal('1');
|
||||
expect(kebabCase('++1')).to.equal('1');
|
||||
expect(kebabCase('-g-g')).to.equal('g-g');
|
||||
});
|
||||
|
||||
it('should remove trailing dashes', () => {
|
||||
expect(kebabCase('1--')).to.equal('1');
|
||||
expect(kebabCase('1++')).to.equal('1');
|
||||
});
|
||||
|
||||
it('should remove duplicate dashes', () => {
|
||||
expect(kebabCase('foo...bar')).to.equal('foo-bar');
|
||||
expect(kebabCase('foo-.-bar')).to.equal('foo-bar');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { expect } from 'chai';
|
||||
import { NullLogger } from 'noicejs';
|
||||
import { Container, NullLogger } from 'noicejs';
|
||||
import { alea } from 'seedrandom';
|
||||
import { stub } from 'sinon';
|
||||
|
||||
|
@ -8,8 +8,12 @@ import { syncIssueLabels } from '../../src/sync';
|
|||
|
||||
describe('issue sync', () => {
|
||||
it('should resolve each issue', async () => {
|
||||
const container = Container.from();
|
||||
await container.configure();
|
||||
|
||||
const logger = NullLogger.global;
|
||||
const remoteData = {
|
||||
container,
|
||||
data: {},
|
||||
dryrun: true,
|
||||
logger,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { expect } from 'chai';
|
||||
import { Container } from 'noicejs';
|
||||
import { alea } from 'seedrandom';
|
||||
import { match, spy, stub } from 'sinon';
|
||||
|
||||
|
@ -10,10 +11,14 @@ describe('project sync', () => {
|
|||
describe('all labels', () => {
|
||||
it('should sync each label');
|
||||
it('should pick a stable random color for each label', async () => {
|
||||
const container = Container.from();
|
||||
await container.configure();
|
||||
|
||||
const logger = BunyanLogger.create({
|
||||
name: 'test',
|
||||
});
|
||||
const remoteConfig = {
|
||||
container,
|
||||
data: {},
|
||||
dryrun: true,
|
||||
logger,
|
||||
|
@ -59,10 +64,14 @@ describe('project sync', () => {
|
|||
});
|
||||
|
||||
it('should create missing labels', async () => {
|
||||
const container = Container.from();
|
||||
await container.configure();
|
||||
|
||||
const logger = BunyanLogger.create({
|
||||
name: 'test',
|
||||
});
|
||||
const remoteConfig = {
|
||||
container,
|
||||
data: {},
|
||||
dryrun: true,
|
||||
logger,
|
||||
|
@ -101,10 +110,14 @@ describe('project sync', () => {
|
|||
});
|
||||
|
||||
it('should delete extra labels', async () => {
|
||||
const container = Container.from();
|
||||
await container.configure();
|
||||
|
||||
const logger = BunyanLogger.create({
|
||||
name: 'test',
|
||||
});
|
||||
const remoteConfig = {
|
||||
container,
|
||||
data: {},
|
||||
dryrun: true,
|
||||
logger,
|
||||
|
|
Loading…
Reference in New Issue