feat(config): add project comment, state divider to config
This commit is contained in:
parent
3a3facb282
commit
2feb5a3c60
|
@ -1,11 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [SyncOptions](./cautious-journey.syncoptions.md) > [flags](./cautious-journey.syncoptions.flags.md)
|
||||
[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [StateLabel](./cautious-journey.statelabel.md) > [divider](./cautious-journey.statelabel.divider.md)
|
||||
|
||||
## SyncOptions.flags property
|
||||
## StateLabel.divider property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
flags: Array<FlagLabel>;
|
||||
divider: string;
|
||||
```
|
|
@ -17,5 +17,6 @@ export interface StateLabel extends BaseLabel
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [divider](./cautious-journey.statelabel.divider.md) | string | |
|
||||
| [values](./cautious-journey.statelabel.values.md) | Array<[StateValue](./cautious-journey.statevalue.md)<!-- -->> | Values for this state. |
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [SyncOptions](./cautious-journey.syncoptions.md) > [colors](./cautious-journey.syncoptions.colors.md)
|
||||
|
||||
## SyncOptions.colors property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
colors: Array<string>;
|
||||
```
|
|
@ -14,11 +14,8 @@ export interface SyncOptions
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [colors](./cautious-journey.syncoptions.colors.md) | Array<string> | |
|
||||
| [flags](./cautious-journey.syncoptions.flags.md) | Array<[FlagLabel](./cautious-journey.flaglabel.md)<!-- -->> | |
|
||||
| [logger](./cautious-journey.syncoptions.logger.md) | Logger | |
|
||||
| [project](./cautious-journey.syncoptions.project.md) | string | |
|
||||
| [project](./cautious-journey.syncoptions.project.md) | ProjectConfig | |
|
||||
| [random](./cautious-journey.syncoptions.random.md) | prng | |
|
||||
| [remote](./cautious-journey.syncoptions.remote.md) | [Remote](./cautious-journey.remote.md) | |
|
||||
| [states](./cautious-journey.syncoptions.states.md) | Array<[StateLabel](./cautious-journey.statelabel.md)<!-- -->> | States from project config. |
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
project: string;
|
||||
project: ProjectConfig;
|
||||
```
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [cautious-journey](./cautious-journey.md) > [SyncOptions](./cautious-journey.syncoptions.md) > [states](./cautious-journey.syncoptions.states.md)
|
||||
|
||||
## SyncOptions.states property
|
||||
|
||||
States from project config.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
states: Array<StateLabel>;
|
||||
```
|
|
@ -5,40 +5,51 @@ import { FlagLabel, StateLabel } from '../labels';
|
|||
import { RemoteOptions } from '../remote';
|
||||
import * as SCHEMA_DATA from './schema.yml';
|
||||
|
||||
export interface LoggerConfig {
|
||||
level: LogLevel;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ProjectConfig {
|
||||
/**
|
||||
* Color palette for labels without their own.
|
||||
*/
|
||||
colors: Array<string>;
|
||||
|
||||
/**
|
||||
* Leave a comment along with any update, explaining the changes that were made.
|
||||
*
|
||||
* @default `true`
|
||||
*/
|
||||
comment: boolean;
|
||||
|
||||
/**
|
||||
* Individual flag labels.
|
||||
*/
|
||||
flags: Array<FlagLabel>;
|
||||
|
||||
/**
|
||||
* Project name or path.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Remote APIs.
|
||||
*/
|
||||
remote: RemoteOptions;
|
||||
|
||||
/**
|
||||
* Grouped state labels.
|
||||
*/
|
||||
states: Array<StateLabel>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Config data for the app, loaded from CLI or DOM.
|
||||
*/
|
||||
export interface ConfigData {
|
||||
logger: {
|
||||
level: LogLevel;
|
||||
name: string;
|
||||
};
|
||||
projects: Array<{
|
||||
/**
|
||||
* Color palette for labels without their own.
|
||||
*/
|
||||
colors: Array<string>;
|
||||
|
||||
/**
|
||||
* Individual flag labels.
|
||||
*/
|
||||
flags: Array<FlagLabel>;
|
||||
|
||||
/**
|
||||
* Project name or path.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Remote APIs.
|
||||
*/
|
||||
remote: RemoteOptions;
|
||||
|
||||
/**
|
||||
* Grouped state labels.
|
||||
*/
|
||||
states: Array<StateLabel>;
|
||||
}>;
|
||||
logger: LoggerConfig;
|
||||
projects: Array<ProjectConfig>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,6 +65,7 @@ export function initConfig(): ConfigData {
|
|||
},
|
||||
projects: [{
|
||||
colors: [],
|
||||
comment: true,
|
||||
flags: [],
|
||||
name: '',
|
||||
remote: {
|
||||
|
@ -82,5 +94,11 @@ export function validateConfig(it: unknown): it is ConfigData {
|
|||
const ajv = new Ajv(SCHEMA_OPTIONS);
|
||||
ajv.addSchema(SCHEMA_DATA, 'cautious-journey');
|
||||
|
||||
return ajv.validate('cautious-journey#/definitions/config', it) === true;
|
||||
if (ajv.validate('cautious-journey#/definitions/config', it) === true) {
|
||||
return true;
|
||||
} else {
|
||||
/* eslint-disable-next-line */
|
||||
console.error('invalid config', ajv.errors, it);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,17 @@ $id: cautious-journey
|
|||
definitions:
|
||||
label-ref:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
||||
change-set:
|
||||
type: object
|
||||
required:
|
||||
- adds
|
||||
- removes
|
||||
properties:
|
||||
adds:
|
||||
type: array
|
||||
|
@ -23,6 +28,9 @@ definitions:
|
|||
|
||||
base-label:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- requires
|
||||
properties:
|
||||
color:
|
||||
type: string
|
||||
|
@ -59,7 +67,13 @@ definitions:
|
|||
- $ref: "#/definitions/change-set"
|
||||
- $ref: "#/definitions/base-label"
|
||||
- type: object
|
||||
required:
|
||||
- divider
|
||||
- values
|
||||
properties:
|
||||
divider:
|
||||
type: string
|
||||
default: "/"
|
||||
values:
|
||||
type: array
|
||||
items:
|
||||
|
@ -71,6 +85,8 @@ definitions:
|
|||
- $ref: "#/definitions/change-set"
|
||||
- $ref: "#/definitions/base-label"
|
||||
- type: object
|
||||
required:
|
||||
- becomes
|
||||
properties:
|
||||
becomes:
|
||||
type: array
|
||||
|
@ -78,38 +94,60 @@ definitions:
|
|||
$ref: "#/definitions/state-change"
|
||||
default: []
|
||||
|
||||
project:
|
||||
type: object
|
||||
required:
|
||||
- colors
|
||||
- comment
|
||||
- flags
|
||||
- name
|
||||
- remote
|
||||
- states
|
||||
properties:
|
||||
colors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
comment:
|
||||
type: boolean
|
||||
default: true
|
||||
flags:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/flag-label"
|
||||
default: []
|
||||
name:
|
||||
type: string
|
||||
remote:
|
||||
type: object
|
||||
states:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/state-label"
|
||||
default: []
|
||||
|
||||
logger:
|
||||
type: object
|
||||
required:
|
||||
- level
|
||||
- name
|
||||
properties:
|
||||
level:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
|
||||
config:
|
||||
type: object
|
||||
required:
|
||||
- logger
|
||||
- projects
|
||||
properties:
|
||||
logger:
|
||||
type: object
|
||||
properties:
|
||||
level:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
$ref: "#/definitions/logger"
|
||||
projects:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
colors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
flags:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/flag-label"
|
||||
default: []
|
||||
name:
|
||||
type: string
|
||||
remote:
|
||||
type: object
|
||||
states:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/state-label"
|
||||
default: []
|
||||
|
||||
$ref: "#/definitions/project"
|
||||
|
||||
type: object
|
|
@ -14,7 +14,7 @@ const STATUS_ERROR = 1;
|
|||
*/
|
||||
main(process.argv).then((status) => process.exit(status)).catch((err: Error) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('uncaught error during main:', err);
|
||||
console.error('uncaught error during main:', err.message);
|
||||
process.exit(STATUS_ERROR);
|
||||
});
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ export interface StateValue extends BaseLabel {
|
|||
* Grouped labels: the equivalent of a radio group.
|
||||
*/
|
||||
export interface StateLabel extends BaseLabel {
|
||||
divider: string;
|
||||
|
||||
/**
|
||||
* Values for this state.
|
||||
*/
|
||||
|
@ -97,12 +99,12 @@ export function getLabelNames(flags: Array<FlagLabel>, states: Array<StateLabel>
|
|||
return new Set(labels);
|
||||
}
|
||||
|
||||
export function splitValueName(name: string): Array<string> {
|
||||
return name.split('/');
|
||||
export function splitValueName(state: StateLabel, name: string): Array<string> {
|
||||
return name.split(state.divider);
|
||||
}
|
||||
|
||||
export function getValueName(state: StateLabel, value: StateValue): string {
|
||||
return `${state.name}/${value.name}`;
|
||||
return `${state.name}${state.divider}${value.name}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
21
src/main.ts
21
src/main.ts
|
@ -1,4 +1,4 @@
|
|||
import { doesExist, InvalidArgumentError, isNil } from '@apextoaster/js-utils';
|
||||
import { doesExist, InvalidArgumentError } from '@apextoaster/js-utils';
|
||||
import { createSchema } from '@apextoaster/js-yaml-schema';
|
||||
import { existsSync, readFileSync, realpathSync } from 'fs';
|
||||
import { DEFAULT_SAFE_SCHEMA, safeLoad } from 'js-yaml';
|
||||
|
@ -7,11 +7,11 @@ import { alea } from 'seedrandom';
|
|||
|
||||
import { ConfigData, validateConfig } from './config';
|
||||
import { Commands, createParser } from './config/args';
|
||||
import { dotGraph, graphLabels } from './graph';
|
||||
import { BunyanLogger } from './logger/bunyan';
|
||||
import { GithubRemote } from './remote/github';
|
||||
import { syncIssueLabels, SyncOptions, syncProjectLabels } from './sync';
|
||||
import { VERSION_INFO } from './version';
|
||||
import { graphLabels, dotGraph } from './graph';
|
||||
|
||||
export { FlagLabel, StateLabel } from './labels';
|
||||
export { Remote, RemoteOptions } from './remote';
|
||||
|
@ -38,7 +38,7 @@ async function loadConfig(path: string): Promise<ConfigData> {
|
|||
const config = safeLoad(rawConfig, { schema });
|
||||
|
||||
if (!validateConfig(config)) {
|
||||
throw new Error();
|
||||
throw new InvalidArgumentError();
|
||||
}
|
||||
|
||||
return config as ConfigData;
|
||||
|
@ -52,14 +52,16 @@ export async function main(argv: Array<string>): Promise<number> {
|
|||
const logger = BunyanLogger.create(config.logger);
|
||||
|
||||
logger.info({
|
||||
args,
|
||||
config,
|
||||
mode,
|
||||
version: VERSION_INFO,
|
||||
}, 'startup environment');
|
||||
}, 'running main');
|
||||
logger.debug({
|
||||
args,
|
||||
config,
|
||||
}, 'runtime data');
|
||||
|
||||
for (const project of config.projects) {
|
||||
const { colors, flags, name, states } = project;
|
||||
const { name } = project;
|
||||
|
||||
if (doesExist(args.project) && !args.project.includes(name)) {
|
||||
logger.info({ project: name }, 'skipping project');
|
||||
|
@ -77,13 +79,10 @@ export async function main(argv: Array<string>): Promise<number> {
|
|||
|
||||
// mode switch
|
||||
const options: SyncOptions = {
|
||||
colors,
|
||||
flags,
|
||||
logger,
|
||||
project: name,
|
||||
project,
|
||||
random,
|
||||
remote,
|
||||
states,
|
||||
};
|
||||
switch (mode) {
|
||||
case Commands.GRAPH:
|
||||
|
|
|
@ -133,40 +133,45 @@ export function resolveLabels(options: ResolveInput): ResolveResult {
|
|||
label: name,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const combinedValue: BaseLabel = {
|
||||
adds: [...state.adds, ...value.adds],
|
||||
name,
|
||||
priority: defaultUntil(value.priority, state.priority, 0),
|
||||
removes: [...state.removes, ...value.removes],
|
||||
requires: [...state.requires, ...value.requires],
|
||||
};
|
||||
|
||||
if (checkLabelRules(combinedValue)) {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let removed = false;
|
||||
for (const become of value.becomes) {
|
||||
if (become.matches.every((l) => activeLabels.has(l.name))) {
|
||||
checkLabelRules({
|
||||
...combinedValue,
|
||||
adds: become.adds,
|
||||
removes: [...become.matches, ...become.removes],
|
||||
requires: [],
|
||||
const combinedValue: BaseLabel = {
|
||||
adds: [...state.adds, ...value.adds],
|
||||
name,
|
||||
priority: defaultUntil(value.priority, state.priority, 0),
|
||||
removes: [...state.removes, ...value.removes],
|
||||
requires: [...state.requires, ...value.requires],
|
||||
};
|
||||
|
||||
if (checkLabelRules(combinedValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: flatten this bit and remove the mutable boolean
|
||||
let removed = false;
|
||||
for (const become of value.becomes) {
|
||||
const matches = become.matches.every((l) => activeLabels.has(l.name));
|
||||
|
||||
if (matches) {
|
||||
checkLabelRules({
|
||||
...combinedValue,
|
||||
adds: become.adds,
|
||||
removes: [...become.matches, ...become.removes],
|
||||
requires: [],
|
||||
});
|
||||
|
||||
if (activeLabels.delete(name)) {
|
||||
changes.push({
|
||||
cause: name,
|
||||
effect: ChangeVerb.REMOVED,
|
||||
label: name,
|
||||
});
|
||||
|
||||
if (activeLabels.delete(name)) {
|
||||
changes.push({
|
||||
cause: name,
|
||||
effect: ChangeVerb.REMOVED,
|
||||
label: name,
|
||||
});
|
||||
removed = true;
|
||||
}
|
||||
|
||||
break;
|
||||
removed = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
|
|
105
src/sync.ts
105
src/sync.ts
|
@ -6,25 +6,13 @@ import { FlagLabel, getLabelColor, getLabelNames, getValueName, StateLabel } fro
|
|||
import { LabelUpdate, Remote } from './remote';
|
||||
import { resolveLabels } from './resolve';
|
||||
import { defaultTo, defaultUntil, compareItems } from './utils';
|
||||
import { ProjectConfig } from './config';
|
||||
|
||||
export interface SyncOptions {
|
||||
/**
|
||||
*/
|
||||
colors: Array<string>;
|
||||
|
||||
/**
|
||||
*/
|
||||
flags: Array<FlagLabel>;
|
||||
|
||||
logger: Logger;
|
||||
project: string;
|
||||
project: ProjectConfig;
|
||||
random: prng;
|
||||
remote: Remote;
|
||||
|
||||
/**
|
||||
* States from project config.
|
||||
*/
|
||||
states: Array<StateLabel>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,34 +20,38 @@ export interface SyncOptions {
|
|||
* if there are changes and no errors, then updates the issue.
|
||||
*/
|
||||
export async function syncIssueLabels(options: SyncOptions): Promise<unknown> {
|
||||
const issues = await options.remote.listIssues({
|
||||
project: options.project,
|
||||
const { logger, project, remote } = options;
|
||||
const issues = await remote.listIssues({
|
||||
project: project.name,
|
||||
});
|
||||
|
||||
for (const issue of issues) {
|
||||
options.logger.info({ issue }, 'project issue');
|
||||
logger.info({ issue }, 'project issue');
|
||||
|
||||
const { changes, errors, labels } = resolveLabels({
|
||||
flags: options.flags,
|
||||
flags: project.flags,
|
||||
labels: issue.labels,
|
||||
states: options.states,
|
||||
states: project.states,
|
||||
});
|
||||
|
||||
options.logger.debug({ changes, errors, issue, labels }, 'resolved labels');
|
||||
logger.debug({ changes, errors, issue, labels }, 'resolved labels');
|
||||
|
||||
// TODO: prompt user to update this particular issue
|
||||
const sameLabels = compareItems(issue.labels, labels) || changes.length === 0;
|
||||
if (sameLabels === false && errors.length === 0) {
|
||||
options.logger.info({ changes, errors, issue, labels }, 'updating issue');
|
||||
await options.remote.updateIssue({
|
||||
logger.info({ changes, errors, issue, labels }, 'updating issue');
|
||||
await remote.updateIssue({
|
||||
...issue,
|
||||
labels,
|
||||
});
|
||||
await options.remote.createComment({
|
||||
...issue,
|
||||
changes,
|
||||
errors,
|
||||
});
|
||||
|
||||
if (project.comment) {
|
||||
await remote.createComment({
|
||||
...issue,
|
||||
changes,
|
||||
errors,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,19 +59,21 @@ export async function syncIssueLabels(options: SyncOptions): Promise<unknown> {
|
|||
}
|
||||
|
||||
export async function syncProjectLabels(options: SyncOptions): Promise<unknown> {
|
||||
const labels = await options.remote.listLabels({
|
||||
project: options.project,
|
||||
const { logger, project, remote } = options;
|
||||
|
||||
const labels = await remote.listLabels({
|
||||
project: project.name,
|
||||
});
|
||||
|
||||
const present = new Set(labels.map((l) => l.name));
|
||||
const desired = getLabelNames(options.flags, options.states);
|
||||
const desired = getLabelNames(project.flags, project.states);
|
||||
const combined = new Set([...desired, ...present]);
|
||||
|
||||
for (const label of combined) {
|
||||
const exists = present.has(label);
|
||||
const expected = desired.has(label);
|
||||
|
||||
options.logger.info({
|
||||
logger.info({
|
||||
exists,
|
||||
expected,
|
||||
label,
|
||||
|
@ -90,15 +84,15 @@ export async function syncProjectLabels(options: SyncOptions): Promise<unknown>
|
|||
const data = mustExist(labels.find((l) => l.name === label));
|
||||
await syncSingleLabel(options, data);
|
||||
} else {
|
||||
options.logger.warn({ label }, 'remove label');
|
||||
await options.remote.deleteLabel({
|
||||
logger.warn({ label }, 'remove label');
|
||||
await remote.deleteLabel({
|
||||
name: label,
|
||||
project: options.project,
|
||||
project: project.name,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (expected) {
|
||||
options.logger.info({ label }, 'create label');
|
||||
logger.info({ label }, 'create label');
|
||||
await createLabel(options, label);
|
||||
} else {
|
||||
// skip
|
||||
|
@ -110,27 +104,29 @@ export async function syncProjectLabels(options: SyncOptions): Promise<unknown>
|
|||
}
|
||||
|
||||
export async function createLabel(options: SyncOptions, name: string) {
|
||||
const flag = options.flags.find((it) => name === it.name);
|
||||
const { project, remote } = options;
|
||||
|
||||
const flag = project.flags.find((it) => name === it.name);
|
||||
if (doesExist(flag)) {
|
||||
await options.remote.createLabel({
|
||||
color: getLabelColor(options.colors, options.random, flag),
|
||||
await remote.createLabel({
|
||||
color: getLabelColor(project.colors, options.random, flag),
|
||||
desc: mustExist(flag.desc),
|
||||
name,
|
||||
project: options.project,
|
||||
project: project.name,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const state = options.states.find((it) => name.startsWith(it.name));
|
||||
const state = project.states.find((it) => name.startsWith(it.name));
|
||||
if (doesExist(state)) {
|
||||
const value = state.values.find((it) => getValueName(state, it) === name);
|
||||
if (doesExist(value)) {
|
||||
await options.remote.createLabel({
|
||||
color: getLabelColor(options.colors, options.random, state, value),
|
||||
await remote.createLabel({
|
||||
color: getLabelColor(project.colors, options.random, state, value),
|
||||
desc: defaultUntil(value.desc, state.desc, ''),
|
||||
name: getValueName(state, value),
|
||||
project: options.project,
|
||||
project: project.name,
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -139,6 +135,8 @@ export async function createLabel(options: SyncOptions, name: string) {
|
|||
}
|
||||
|
||||
export async function syncLabelDiff(options: SyncOptions, oldLabel: LabelUpdate, newLabel: LabelUpdate) {
|
||||
const { logger, project } = options;
|
||||
|
||||
const dirty =
|
||||
oldLabel.color !== mustExist(newLabel.color) ||
|
||||
oldLabel.desc !== mustExist(newLabel.desc);
|
||||
|
@ -148,41 +146,40 @@ export async function syncLabelDiff(options: SyncOptions, oldLabel: LabelUpdate,
|
|||
color: defaultTo(newLabel.color, oldLabel.color),
|
||||
desc: defaultTo(newLabel.desc, oldLabel.desc),
|
||||
name: oldLabel.name,
|
||||
project: options.project,
|
||||
project: project.name,
|
||||
};
|
||||
|
||||
options.logger.debug({ body, newLabel, oldLabel }, 'update label');
|
||||
|
||||
logger.debug({ body, newLabel, oldLabel }, 'updating label');
|
||||
const resp = await options.remote.updateLabel(body);
|
||||
|
||||
options.logger.debug({ resp }, 'update resp');
|
||||
logger.debug({ resp }, 'update response');
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncSingleLabel(options: SyncOptions, label: LabelUpdate): Promise<void> {
|
||||
const flag = options.flags.find((it) => label.name === it.name);
|
||||
const { project } = options;
|
||||
const flag = project.flags.find((it) => label.name === it.name);
|
||||
if (doesExist(flag)) {
|
||||
const color = getLabelColor(options.colors, options.random, flag);
|
||||
const color = getLabelColor(project.colors, options.random, flag);
|
||||
await syncLabelDiff(options, label, {
|
||||
color,
|
||||
desc: defaultTo(flag.desc, label.desc),
|
||||
name: flag.name,
|
||||
project: options.project,
|
||||
project: project.name,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const state = options.states.find((it) => label.name.startsWith(it.name));
|
||||
const state = project.states.find((it) => label.name.startsWith(it.name));
|
||||
if (doesExist(state)) {
|
||||
const value = state.values.find((it) => getValueName(state, it) === label.name);
|
||||
if (doesExist(value)) {
|
||||
const color = mustExist(getLabelColor(options.colors, options.random, state, value));
|
||||
const color = mustExist(getLabelColor(project.colors, options.random, state, value));
|
||||
await syncLabelDiff(options, label, {
|
||||
color,
|
||||
desc: defaultTo(value.desc, label.desc),
|
||||
name: getValueName(state, value),
|
||||
project: options.project,
|
||||
project: project.name,
|
||||
});
|
||||
|
||||
return;
|
||||
|
|
|
@ -35,3 +35,11 @@ export function compareItems<T>(a: Array<T>, b: Array<T>): boolean {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
interface Collection<T> {
|
||||
has(value: T): boolean;
|
||||
}
|
||||
|
||||
export function contains<T>(a: Collection<T>, b: Array<T>): boolean {
|
||||
return b.every((it) => a.has(it));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { expect } from 'chai';
|
||||
import { alea } from 'seedrandom';
|
||||
|
||||
import { getLabelColor, getLabelNames, prioritySort } from '../src/labels';
|
||||
import { getLabelColor, getLabelNames, prioritySort, StateLabel } from '../src/labels';
|
||||
|
||||
describe('label helpers', () => {
|
||||
describe('label name helper', () => {
|
||||
|
@ -38,8 +38,9 @@ describe('label helpers', () => {
|
|||
removes: [],
|
||||
requires: [],
|
||||
}];
|
||||
const states = [{
|
||||
const states: Array<StateLabel> = [{
|
||||
adds: [],
|
||||
divider: '/',
|
||||
name: 'foo',
|
||||
priority: 1,
|
||||
removes: [],
|
||||
|
@ -47,6 +48,7 @@ describe('label helpers', () => {
|
|||
values,
|
||||
}, {
|
||||
adds: [],
|
||||
divider: '/',
|
||||
name: 'bar',
|
||||
priority: 1,
|
||||
removes: [],
|
||||
|
@ -109,6 +111,7 @@ describe('label helpers', () => {
|
|||
expect(getLabelColor(['test'], alea(), {
|
||||
adds: [],
|
||||
color: 'beans',
|
||||
divider: '/',
|
||||
name: '',
|
||||
priority: 1,
|
||||
removes: [],
|
||||
|
@ -129,6 +132,7 @@ describe('label helpers', () => {
|
|||
expect(getLabelColor(['test'], alea(), {
|
||||
adds: [],
|
||||
color: 'beans',
|
||||
divider: '/',
|
||||
name: '',
|
||||
priority: 1,
|
||||
removes: [],
|
||||
|
|
|
@ -12,30 +12,35 @@ describe('label sync', () => {
|
|||
const logger = BunyanLogger.create({
|
||||
name: 'test',
|
||||
});
|
||||
const remote = new GithubRemote({
|
||||
const remoteConfig = {
|
||||
data: {},
|
||||
dryrun: true,
|
||||
logger,
|
||||
type: '',
|
||||
});
|
||||
};
|
||||
const remote = new GithubRemote(remoteConfig);
|
||||
const updateSpy = spy(remote, 'updateLabel');
|
||||
|
||||
await syncSingleLabel({
|
||||
colors: [
|
||||
'ff0000',
|
||||
],
|
||||
flags: [{
|
||||
adds: [],
|
||||
name: 'foo',
|
||||
priority: 1,
|
||||
removes: [],
|
||||
requires: [],
|
||||
}],
|
||||
logger,
|
||||
project: '',
|
||||
project: {
|
||||
colors: [
|
||||
'ff0000',
|
||||
],
|
||||
comment: true,
|
||||
flags: [{
|
||||
adds: [],
|
||||
name: 'foo',
|
||||
priority: 1,
|
||||
removes: [],
|
||||
requires: [],
|
||||
}],
|
||||
name: '',
|
||||
remote: remoteConfig,
|
||||
states: [],
|
||||
},
|
||||
random: alea(),
|
||||
remote,
|
||||
states: [],
|
||||
}, {
|
||||
color: '',
|
||||
desc: '',
|
||||
|
|
Loading…
Reference in New Issue