From 1f3cbac59894241c30b6605c7b0b802643413cd8 Mon Sep 17 00:00:00 2001 From: ssube Date: Sun, 30 Aug 2020 23:29:17 -0500 Subject: [PATCH] feat: add initial labels to project --- .../cautious-journey.resolveinput.initial.md | 11 ++++++ docs/api/cautious-journey.resolveinput.md | 1 + src/config/index.ts | 2 + src/config/schema.yml | 6 +++ src/remote/base.ts | 3 ++ src/resolve.ts | 38 +++++++++++++------ src/sync.ts | 1 + test/TestMain.ts | 3 ++ test/TestResolve.ts | 16 ++++++++ test/remote/TestGithubRemote.ts | 33 +++++++++++++++- test/resolve/TestResolveIssueLabels.ts | 6 ++- test/resolve/cases.ts | 11 ++++++ test/sync/TestSyncIssues.ts | 1 + test/sync/TestSyncProjects.ts | 6 +++ 14 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 docs/api/cautious-journey.resolveinput.initial.md diff --git a/docs/api/cautious-journey.resolveinput.initial.md b/docs/api/cautious-journey.resolveinput.initial.md new file mode 100644 index 0000000..aa370a1 --- /dev/null +++ b/docs/api/cautious-journey.resolveinput.initial.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [ResolveInput](./cautious-journey.resolveinput.md) > [initial](./cautious-journey.resolveinput.initial.md) + +## ResolveInput.initial property + +Signature: + +```typescript +initial: Array; +``` diff --git a/docs/api/cautious-journey.resolveinput.md b/docs/api/cautious-journey.resolveinput.md index 389e549..72403d1 100644 --- a/docs/api/cautious-journey.resolveinput.md +++ b/docs/api/cautious-journey.resolveinput.md @@ -17,6 +17,7 @@ export interface ResolveInput | Property | Type | Description | | --- | --- | --- | | [flags](./cautious-journey.resolveinput.flags.md) | Array<[FlagLabel](./cautious-journey.flaglabel.md)> | | +| [initial](./cautious-journey.resolveinput.initial.md) | Array<string> | | | [labels](./cautious-journey.resolveinput.labels.md) | Array<string> | | | [states](./cautious-journey.resolveinput.states.md) | Array<[StateLabel](./cautious-journey.statelabel.md)> | | diff --git a/src/config/index.ts b/src/config/index.ts index 6a0336f..6410e98 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -33,6 +33,8 @@ export interface ProjectConfig { */ flags: Array; + initial: Array; + /** * Project name or path. */ diff --git a/src/config/schema.yml b/src/config/schema.yml index b98c6fa..d820837 100644 --- a/src/config/schema.yml +++ b/src/config/schema.yml @@ -121,6 +121,7 @@ definitions: - colors - comment - flags + - initial - name - remote - states @@ -138,6 +139,11 @@ definitions: items: $ref: "#/definitions/flag-label" default: [] + initial: + type: array + items: + type: string + default: [] name: type: string remote: diff --git a/src/remote/base.ts b/src/remote/base.ts index f09459d..0e57a13 100644 --- a/src/remote/base.ts +++ b/src/remote/base.ts @@ -34,6 +34,9 @@ export abstract class BaseRemote implem case ChangeVerb.CREATED: lines.push(`- \`${change.label}\` was created by \`${change.cause}\`.`); break; + case ChangeVerb.INITIAL: + lines.push(`- \`${change.label}\` is an initial label.`); + break; case ChangeVerb.REMOVED: lines.push(`- \`${change.label}\` was removed by \`${change.cause}\`.`); break; diff --git a/src/resolve.ts b/src/resolve.ts index dfd9a77..dad0a69 100644 --- a/src/resolve.ts +++ b/src/resolve.ts @@ -10,6 +10,7 @@ export enum ChangeVerb { BECAME = 'became', CONFLICTED = 'conflicted', CREATED = 'created', + INITIAL = 'initial', REMOVED = 'removed', REQUIRED = 'required', } @@ -44,6 +45,7 @@ export interface ErrorRecord { */ export interface ResolveInput { flags: Array; + initial: Array; labels: Array; states: Array; } @@ -187,19 +189,33 @@ export function resolveProject(options: ResolveInput): ResolveResult { errors: [], labels: [], }; - const activeLabels = new Set(options.labels); - const sortedFlags = prioritySort(options.flags); - for (const flag of sortedFlags) { - resolveBaseLabel(flag, result, activeLabels); + if (options.labels.length === 0) { + result.labels.push(...options.initial); + + for (const i of options.initial) { + result.changes.push({ + cause: '', + effect: ChangeVerb.INITIAL, + label: i, + }); + } + } else { + const activeLabels = new Set(options.labels); + + const sortedFlags = prioritySort(options.flags); + for (const flag of sortedFlags) { + resolveBaseLabel(flag, result, activeLabels); + } + + const sortedStates = prioritySort(options.states); + for (const state of sortedStates) { + resolveState(state, result, activeLabels); + } + + result.labels.push(...activeLabels); } - const sortedStates = prioritySort(options.states); - for (const state of sortedStates) { - resolveState(state, result, activeLabels); - } - - result.labels = Array.from(activeLabels).sort(); - + result.labels.sort(); return result; } diff --git a/src/sync.ts b/src/sync.ts index fdf0edc..5efb740 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -30,6 +30,7 @@ export async function syncIssueLabels(options: SyncOptions): Promise { const { changes, errors, labels } = resolveProject({ flags: project.flags, + initial: project.initial, labels: issue.labels, states: project.states, }); diff --git a/test/TestMain.ts b/test/TestMain.ts index 6655983..2ada5f1 100644 --- a/test/TestMain.ts +++ b/test/TestMain.ts @@ -34,6 +34,7 @@ describe('main app', () => { colors: [], comment: false, flags: [], + initial: [], name: '', remote: { data: {}, @@ -68,6 +69,7 @@ describe('main app', () => { colors: [], comment: false, flags: [], + initial: [], name: '', remote: { data: {}, @@ -103,6 +105,7 @@ describe('main app', () => { colors: [], comment: false, flags: [], + initial: [], name: 'bar', remote: { data: {}, diff --git a/test/TestResolve.ts b/test/TestResolve.ts index 33db7c9..3625cb2 100644 --- a/test/TestResolve.ts +++ b/test/TestResolve.ts @@ -10,6 +10,7 @@ describe('resolve labels', () => { it('should return the existing labels', () => { const result = resolveProject({ flags: [], + initial: [], labels: TEST_LABELS, states: [], }); @@ -20,6 +21,7 @@ describe('resolve labels', () => { it('should not make any changes', () => { const result = resolveProject({ flags: [], + initial: [], labels: TEST_LABELS, states: [], }); @@ -28,6 +30,20 @@ describe('resolve labels', () => { }); }); + describe('with empty labels', () => { + it('should return initial labels', () => { + const initial = ['bar', 'foo']; + const result = resolveProject({ + flags: [], + initial, + labels: [], + states: [], + }); + + expect(result.labels).to.deep.equal(initial); + }); + }); + // procedural tests describe('resolver test cases', () => { for (const test of TEST_CASES) { diff --git a/test/remote/TestGithubRemote.ts b/test/remote/TestGithubRemote.ts index 80bee9b..b366038 100644 --- a/test/remote/TestGithubRemote.ts +++ b/test/remote/TestGithubRemote.ts @@ -97,7 +97,12 @@ describe('github remote', () => { const remote = await container.create(GithubRemote, REMOTE_OPTIONS); - for (const effect of [ChangeVerb.CONFLICTED, ChangeVerb.CREATED, ChangeVerb.REMOVED, ChangeVerb.REQUIRED]) { + for (const effect of [ + ChangeVerb.CONFLICTED, + ChangeVerb.CREATED, + ChangeVerb.REMOVED, + ChangeVerb.REQUIRED, + ]) { const body = remote.formatBody({ changes: [{ cause: 'foo', @@ -112,6 +117,32 @@ describe('github remote', () => { expect(body).to.include('bar').and.include('foo'); } }); + + it('should include initial labels', async () => { + const module = new RemoteModule(); + const container = Container.from(module); + await container.configure(); + + const client = new Octokit(); + stub(client.issues, 'createLabel'); + module.bind(Octokit).toInstance(client); + + const remote = await container.create(GithubRemote, REMOTE_OPTIONS); + + const body = remote.formatBody({ + changes: [{ + cause: 'foo', + effect: ChangeVerb.INITIAL, + label: 'bar', + }], + errors: [], + issue: '', + project: '', + }); + + expect(body).to.include('bar').and.include('initial'); + }); + }); describe('create comment endpoint', () => { diff --git a/test/resolve/TestResolveIssueLabels.ts b/test/resolve/TestResolveIssueLabels.ts index f101337..7d7a880 100644 --- a/test/resolve/TestResolveIssueLabels.ts +++ b/test/resolve/TestResolveIssueLabels.ts @@ -2,8 +2,6 @@ import { expect } from 'chai'; import { resolveProject } from '../../src/resolve'; -const TEST_LABELS = ['foo', 'bar']; - describe('resolve labels', () => { describe('flags with unfulfilled requires rule', () => { it('should be removed when required label is missing', () => { @@ -17,6 +15,7 @@ describe('resolve labels', () => { name: 'linda', }], }], + initial: [], labels: ['gayle'], states: [], }); @@ -37,6 +36,7 @@ describe('resolve labels', () => { name: 'linda', }], }], + initial: [], labels: ['gayle', 'linda'], states: [], }); @@ -57,6 +57,7 @@ describe('resolve labels', () => { removes: [], requires: [], }], + initial: [], labels: ['bob'], states: [], }); @@ -77,6 +78,7 @@ describe('resolve labels', () => { }], requires: [], }], + initial: [], labels: ['bob', 'hugo'], states: [], }); diff --git a/test/resolve/cases.ts b/test/resolve/cases.ts index 1a2da71..3694540 100644 --- a/test/resolve/cases.ts +++ b/test/resolve/cases.ts @@ -114,6 +114,7 @@ const DEPENDENT_FLAG: FlagLabel = { export const TEST_CASES: Array = [{ input: { flags: [], + initial: [], labels: [], states: [], }, @@ -126,6 +127,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [SIMPLE_FLAG], + initial: [], labels: [ 'test', ], @@ -142,6 +144,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [], + initial: [], labels: ['foo/bar', 'next'], states: [TWO_STATE_CYCLE], }, @@ -153,6 +156,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [], + initial: [], labels: ['foo/bar', 'next', 'bob'], states: [TWO_STATE_CYCLE], }, @@ -164,6 +168,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [], + initial: [], labels: ['foo/bar', 'foo/bin'], states: [TWO_STATE_CYCLE], }, @@ -175,6 +180,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [], + initial: [], labels: ['foo/bar', 'foo/bin'], states: [SECOND_STATE_FALLBACK], }, @@ -186,6 +192,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [], + initial: [], labels: ['foo/bar', 'foo/bin', 'bob'], states: [SECOND_STATE_FALLBACK], }, @@ -197,6 +204,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [], + initial: [], labels: ['foo/bin', 'bob'], states: [SECOND_STATE_FALLBACK], }, @@ -208,6 +216,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [DEPENDENT_FLAG], + initial: [], labels: ['test', 'bar'], states: [], }, @@ -219,6 +228,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [DEPENDENT_FLAG], + initial: [], labels: ['bar'], states: [], }, @@ -230,6 +240,7 @@ export const TEST_CASES: Array = [{ }, { input: { flags: [DEPENDENT_FLAG, SIMPLE_FLAG], + initial: [], labels: [], states: [TWO_STATE_CYCLE, SECOND_STATE_FALLBACK], }, diff --git a/test/sync/TestSyncIssues.ts b/test/sync/TestSyncIssues.ts index dc312a4..9b78b9d 100644 --- a/test/sync/TestSyncIssues.ts +++ b/test/sync/TestSyncIssues.ts @@ -46,6 +46,7 @@ describe('issue sync', () => { name: 'yep', }], }], + initial: [], name: 'foo', remote: remoteData, states: [], diff --git a/test/sync/TestSyncProjects.ts b/test/sync/TestSyncProjects.ts index a4c5ad4..221ce9d 100644 --- a/test/sync/TestSyncProjects.ts +++ b/test/sync/TestSyncProjects.ts @@ -66,6 +66,7 @@ describe('project sync', () => { ], comment: true, flags: [TEST_FLAG], + initial: [], name: '', remote: remoteConfig, states: [], @@ -112,6 +113,7 @@ describe('project sync', () => { colors: [], comment: true, flags: [TEST_FLAG], + initial: [], name: '', remote: remoteConfig, states: [], @@ -148,6 +150,7 @@ describe('project sync', () => { colors: [], comment: true, flags: [], + initial: [], name: '', remote: remoteConfig, states: [TEST_STATE], @@ -191,6 +194,7 @@ describe('project sync', () => { colors: [], comment: true, flags: [], + initial: [], name: '', remote: remoteConfig, states: [], @@ -231,6 +235,7 @@ describe('project sync', () => { colors: [], comment: false, flags: [], + initial: [], name: '', remote: { data: {}, @@ -262,6 +267,7 @@ describe('project sync', () => { colors: [], comment: false, flags: [], + initial: [], name: '', remote: { data: {},