bktide 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -0
- package/WORKFLOW_README.md +65 -0
- package/bin/alfred-entrypoint +54 -0
- package/dist/commands/BaseCommand.js +159 -0
- package/dist/commands/BaseCommand.js.map +1 -0
- package/dist/commands/BaseCommandHandler.js +80 -0
- package/dist/commands/BaseCommandHandler.js.map +1 -0
- package/dist/commands/BuildCommandHandler.js +28 -0
- package/dist/commands/BuildCommandHandler.js.map +1 -0
- package/dist/commands/HelloCommandHandler.js +6 -0
- package/dist/commands/HelloCommandHandler.js.map +1 -0
- package/dist/commands/ListAnnotations.js +60 -0
- package/dist/commands/ListAnnotations.js.map +1 -0
- package/dist/commands/ListBuilds.js +137 -0
- package/dist/commands/ListBuilds.js.map +1 -0
- package/dist/commands/ListOrganizations.js +27 -0
- package/dist/commands/ListOrganizations.js.map +1 -0
- package/dist/commands/ListPipelines.js +114 -0
- package/dist/commands/ListPipelines.js.map +1 -0
- package/dist/commands/ManageToken.js +180 -0
- package/dist/commands/ManageToken.js.map +1 -0
- package/dist/commands/OrganizationCommandHandler.js +53 -0
- package/dist/commands/OrganizationCommandHandler.js.map +1 -0
- package/dist/commands/PipelineCommandHandler.js +142 -0
- package/dist/commands/PipelineCommandHandler.js.map +1 -0
- package/dist/commands/ShowViewer.js +26 -0
- package/dist/commands/ShowViewer.js.map +1 -0
- package/dist/commands/UserBuildsCommandHandler.js +61 -0
- package/dist/commands/UserBuildsCommandHandler.js.map +1 -0
- package/dist/commands/ViewerBuildsCommandHandler.js +176 -0
- package/dist/commands/ViewerBuildsCommandHandler.js.map +1 -0
- package/dist/commands/ViewerCommandHandler.js +46 -0
- package/dist/commands/ViewerCommandHandler.js.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/formatters/BaseFormatter.js +14 -0
- package/dist/formatters/BaseFormatter.js.map +1 -0
- package/dist/formatters/FormatterFactory.js +48 -0
- package/dist/formatters/FormatterFactory.js.map +1 -0
- package/dist/formatters/annotations/Formatter.js +10 -0
- package/dist/formatters/annotations/Formatter.js.map +1 -0
- package/dist/formatters/annotations/JsonFormatter.js +20 -0
- package/dist/formatters/annotations/JsonFormatter.js.map +1 -0
- package/dist/formatters/annotations/PlainTextFormatter.js +35 -0
- package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/annotations/index.js +23 -0
- package/dist/formatters/annotations/index.js.map +1 -0
- package/dist/formatters/builds/AlfredFormatter.js +135 -0
- package/dist/formatters/builds/AlfredFormatter.js.map +1 -0
- package/dist/formatters/builds/Formatter.js +10 -0
- package/dist/formatters/builds/Formatter.js.map +1 -0
- package/dist/formatters/builds/JsonFormatter.js +44 -0
- package/dist/formatters/builds/JsonFormatter.js.map +1 -0
- package/dist/formatters/builds/PlainTextFormatter.js +113 -0
- package/dist/formatters/builds/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/builds/index.js +26 -0
- package/dist/formatters/builds/index.js.map +1 -0
- package/dist/formatters/errors/AlfredFormatter.js +110 -0
- package/dist/formatters/errors/AlfredFormatter.js.map +1 -0
- package/dist/formatters/errors/Formatter.js +98 -0
- package/dist/formatters/errors/Formatter.js.map +1 -0
- package/dist/formatters/errors/JsonFormatter.js +63 -0
- package/dist/formatters/errors/JsonFormatter.js.map +1 -0
- package/dist/formatters/errors/PlainTextFormatter.js +52 -0
- package/dist/formatters/errors/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/errors/index.js +26 -0
- package/dist/formatters/errors/index.js.map +1 -0
- package/dist/formatters/index.js +9 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/organizations/Formatter.js +10 -0
- package/dist/formatters/organizations/Formatter.js.map +1 -0
- package/dist/formatters/organizations/JsonFormatter.js +16 -0
- package/dist/formatters/organizations/JsonFormatter.js.map +1 -0
- package/dist/formatters/organizations/PlainTextFormatter.js +15 -0
- package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/organizations/index.js +21 -0
- package/dist/formatters/organizations/index.js.map +1 -0
- package/dist/formatters/pipelines/AlfredFormatter.js +42 -0
- package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -0
- package/dist/formatters/pipelines/Formatter.js +10 -0
- package/dist/formatters/pipelines/Formatter.js.map +1 -0
- package/dist/formatters/pipelines/JsonFormatter.js +13 -0
- package/dist/formatters/pipelines/JsonFormatter.js.map +1 -0
- package/dist/formatters/pipelines/PlainTextFormatter.js +47 -0
- package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/pipelines/index.js +28 -0
- package/dist/formatters/pipelines/index.js.map +1 -0
- package/dist/formatters/token/AlfredFormatter.js +191 -0
- package/dist/formatters/token/AlfredFormatter.js.map +1 -0
- package/dist/formatters/token/Formatter.js +13 -0
- package/dist/formatters/token/Formatter.js.map +1 -0
- package/dist/formatters/token/JsonFormatter.js +211 -0
- package/dist/formatters/token/JsonFormatter.js.map +1 -0
- package/dist/formatters/token/PlainTextFormatter.js +184 -0
- package/dist/formatters/token/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/token/index.js +26 -0
- package/dist/formatters/token/index.js.map +1 -0
- package/dist/formatters/viewer/Formatter.js +10 -0
- package/dist/formatters/viewer/Formatter.js.map +1 -0
- package/dist/formatters/viewer/JsonFormatter.js +20 -0
- package/dist/formatters/viewer/JsonFormatter.js.map +1 -0
- package/dist/formatters/viewer/PlainTextFormatter.js +20 -0
- package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/viewer/index.js +21 -0
- package/dist/formatters/viewer/index.js.map +1 -0
- package/dist/graphql/generated/fragment-masking.js +17 -0
- package/dist/graphql/generated/fragment-masking.js.map +1 -0
- package/dist/graphql/generated/gql.js +13 -0
- package/dist/graphql/generated/gql.js.map +1 -0
- package/dist/graphql/generated/graphql.js +852 -0
- package/dist/graphql/generated/graphql.js.map +1 -0
- package/dist/graphql/generated/index.js +3 -0
- package/dist/graphql/generated/index.js.map +1 -0
- package/dist/graphql/generated/sdk.js +872 -0
- package/dist/graphql/generated/sdk.js.map +1 -0
- package/dist/graphql/queries.js +138 -0
- package/dist/graphql/queries.js.map +1 -0
- package/dist/index.js +271 -0
- package/dist/index.js.map +1 -0
- package/dist/services/BuildkiteClient.js +520 -0
- package/dist/services/BuildkiteClient.js.map +1 -0
- package/dist/services/BuildkiteRestClient.js +244 -0
- package/dist/services/BuildkiteRestClient.js.map +1 -0
- package/dist/services/CacheManager.js +221 -0
- package/dist/services/CacheManager.js.map +1 -0
- package/dist/services/CredentialManager.js +158 -0
- package/dist/services/CredentialManager.js.map +1 -0
- package/dist/services/EnhancedBuildkiteClient.js +297 -0
- package/dist/services/EnhancedBuildkiteClient.js.map +1 -0
- package/dist/services/logger.js +107 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/types/buildkite.js +5 -0
- package/dist/types/buildkite.js.map +1 -0
- package/dist/types/credentials.js +2 -0
- package/dist/types/credentials.js.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/cli-error-handler.js +172 -0
- package/dist/utils/cli-error-handler.js.map +1 -0
- package/dist/utils/errorUtils.js +59 -0
- package/dist/utils/errorUtils.js.map +1 -0
- package/dist/utils/parseBuildRef.js +31 -0
- package/dist/utils/parseBuildRef.js.map +1 -0
- package/dist/utils/textFormatter.js +53 -0
- package/dist/utils/textFormatter.js.map +1 -0
- package/dist/utils/xdgPaths.js +95 -0
- package/dist/utils/xdgPaths.js.map +1 -0
- package/env.example +66 -0
- package/icons/README.md +68 -0
- package/icons/blocked.png +0 -0
- package/icons/buildkite.png +0 -0
- package/icons/failed.png +0 -0
- package/icons/failing.png +0 -0
- package/icons/passed.png +0 -0
- package/icons/running.png +0 -0
- package/icons/scheduled.png +0 -0
- package/icons/skipped.png +0 -0
- package/icons/unknown.png +0 -0
- package/info.plist +734 -0
- package/package.json +87 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { logger } from '../../services/logger.js';
|
|
2
|
+
export class BaseFormatter {
|
|
3
|
+
format(data, formatFn, options) {
|
|
4
|
+
if (options?.debug) {
|
|
5
|
+
logger.debug(`Formatting with ${this.name} formatter`);
|
|
6
|
+
}
|
|
7
|
+
return formatFn(data, options);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/annotations/Formatter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAgBlD,MAAM,OAAgB,aAAa;IAKjC,MAAM,CAAI,IAAS,EAAE,QAA2D,EAAE,OAA0B;QAC1G,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;CACF","sourcesContent":["import { BaseFormatter as BaseFormatterInterface, FormatterOptions } from '../BaseFormatter.js';\nimport { Annotation } from '../../types/index.js';\nimport { logger } from '../../services/logger.js';\n\nexport interface AnnotationFormatterOptions extends FormatterOptions {\n // Error information\n hasError?: boolean;\n errorMessage?: string;\n errorType?: 'access' | 'not_found' | 'api' | 'unknown';\n accessErrors?: string[];\n // Filtering information\n contextFilter?: string;\n}\n\nexport interface AnnotationFormatter extends BaseFormatterInterface {\n formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string;\n}\n\nexport abstract class BaseFormatter implements AnnotationFormatter {\n abstract name: string;\n \n abstract formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string;\n \n format<T>(data: T[], formatFn: (data: T[], options?: FormatterOptions) => string, options?: FormatterOptions): string {\n if (options?.debug) {\n logger.debug(`Formatting with ${this.name} formatter`);\n }\n return formatFn(data, options);\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
export class JsonFormatter extends BaseFormatter {
|
|
3
|
+
name = 'JSON';
|
|
4
|
+
formatAnnotations(annotations, options) {
|
|
5
|
+
if (options?.hasError) {
|
|
6
|
+
return JSON.stringify({
|
|
7
|
+
error: true,
|
|
8
|
+
message: options.errorMessage || 'Unknown error occurred',
|
|
9
|
+
type: options.errorType || 'unknown'
|
|
10
|
+
}, null, 2);
|
|
11
|
+
}
|
|
12
|
+
const result = {
|
|
13
|
+
annotations: annotations || [],
|
|
14
|
+
count: annotations ? annotations.length : 0,
|
|
15
|
+
...(options?.contextFilter && { contextFilter: options.contextFilter })
|
|
16
|
+
};
|
|
17
|
+
return JSON.stringify(result, null, 2);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=JsonFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/annotations/JsonFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8B,MAAM,gBAAgB,CAAC;AAG3E,MAAM,OAAO,aAAc,SAAQ,aAAa;IAC9C,IAAI,GAAG,MAAM,CAAC;IAEd,iBAAiB,CAAC,WAAyB,EAAE,OAAoC;QAC/E,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,IAAI;gBACX,OAAO,EAAE,OAAO,CAAC,YAAY,IAAI,wBAAwB;gBACzD,IAAI,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;aACrC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG;YACb,WAAW,EAAE,WAAW,IAAI,EAAE;YAC9B,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,OAAO,EAAE,aAAa,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC;SACxE,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;CACF","sourcesContent":["import { BaseFormatter, AnnotationFormatterOptions } from './Formatter.js';\nimport { Annotation } from '../../types/index.js';\n\nexport class JsonFormatter extends BaseFormatter {\n name = 'JSON';\n\n formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string {\n if (options?.hasError) {\n return JSON.stringify({\n error: true,\n message: options.errorMessage || 'Unknown error occurred',\n type: options.errorType || 'unknown'\n }, null, 2);\n }\n\n const result = {\n annotations: annotations || [],\n count: annotations ? annotations.length : 0,\n ...(options?.contextFilter && { contextFilter: options.contextFilter })\n };\n\n return JSON.stringify(result, null, 2);\n }\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
import { formatAnnotationBody } from '../../utils/textFormatter.js';
|
|
3
|
+
export class PlainTextFormatter extends BaseFormatter {
|
|
4
|
+
name = 'PlainText';
|
|
5
|
+
formatAnnotations(annotations, options) {
|
|
6
|
+
if (options?.hasError) {
|
|
7
|
+
return `Error: ${options.errorMessage || 'Unknown error occurred'}`;
|
|
8
|
+
}
|
|
9
|
+
if (!annotations || annotations.length === 0) {
|
|
10
|
+
if (options?.contextFilter) {
|
|
11
|
+
return `No annotations found for this build with context '${options.contextFilter}'.`;
|
|
12
|
+
}
|
|
13
|
+
return 'No annotations found for this build.';
|
|
14
|
+
}
|
|
15
|
+
const lines = [];
|
|
16
|
+
annotations.forEach((annotation, index) => {
|
|
17
|
+
if (index > 0) {
|
|
18
|
+
lines.push(''); // Add blank line between annotations
|
|
19
|
+
}
|
|
20
|
+
lines.push(`Annotation ${index + 1}:`);
|
|
21
|
+
lines.push(` Context: ${annotation.context}`);
|
|
22
|
+
lines.push(` Style: ${annotation.style}`);
|
|
23
|
+
// Format the body HTML with proper HTML/markdown handling
|
|
24
|
+
const formattedBody = formatAnnotationBody(annotation.body.html);
|
|
25
|
+
// Indent the formatted body properly
|
|
26
|
+
const indentedBody = formattedBody
|
|
27
|
+
.split('\n')
|
|
28
|
+
.map(line => ` ${line}`)
|
|
29
|
+
.join('\n');
|
|
30
|
+
lines.push(` Body: ${indentedBody}`);
|
|
31
|
+
});
|
|
32
|
+
return lines.join('\n');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=PlainTextFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/annotations/PlainTextFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8B,MAAM,gBAAgB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,IAAI,GAAG,WAAW,CAAC;IAEnB,iBAAiB,CAAC,WAAyB,EAAE,OAAoC;QAC/E,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;YACtB,OAAO,UAAU,OAAO,CAAC,YAAY,IAAI,wBAAwB,EAAE,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;gBAC3B,OAAO,qDAAqD,OAAO,CAAC,aAAa,IAAI,CAAC;YACxF,CAAC;YACD,OAAO,sCAAsC,CAAC;QAChD,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;YACxC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,qCAAqC;YACvD,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,cAAc,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,cAAc,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,YAAY,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;YAE3C,0DAA0D;YAC1D,MAAM,aAAa,GAAG,oBAAoB,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEjE,qCAAqC;YACrC,MAAM,YAAY,GAAG,aAAa;iBAC/B,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;iBACxB,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,KAAK,CAAC,IAAI,CAAC,WAAW,YAAY,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF","sourcesContent":["import { BaseFormatter, AnnotationFormatterOptions } from './Formatter.js';\nimport { Annotation } from '../../types/index.js';\nimport { formatAnnotationBody } from '../../utils/textFormatter.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'PlainText';\n\n formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string {\n if (options?.hasError) {\n return `Error: ${options.errorMessage || 'Unknown error occurred'}`;\n }\n\n if (!annotations || annotations.length === 0) {\n if (options?.contextFilter) {\n return `No annotations found for this build with context '${options.contextFilter}'.`;\n }\n return 'No annotations found for this build.';\n }\n\n const lines: string[] = [];\n \n annotations.forEach((annotation, index) => {\n if (index > 0) {\n lines.push(''); // Add blank line between annotations\n }\n \n lines.push(`Annotation ${index + 1}:`);\n lines.push(` Context: ${annotation.context}`);\n lines.push(` Style: ${annotation.style}`);\n \n // Format the body HTML with proper HTML/markdown handling\n const formattedBody = formatAnnotationBody(annotation.body.html);\n \n // Indent the formatted body properly\n const indentedBody = formattedBody\n .split('\\n')\n .map(line => ` ${line}`)\n .join('\\n');\n \n lines.push(` Body: ${indentedBody}`);\n });\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PlainTextFormatter } from './PlainTextFormatter.js';
|
|
2
|
+
import { JsonFormatter } from './JsonFormatter.js';
|
|
3
|
+
import { logger } from '../../services/logger.js';
|
|
4
|
+
/**
|
|
5
|
+
* Get the appropriate annotation formatter based on the format string
|
|
6
|
+
* @param format The format to use ('plain', 'json', or 'alfred')
|
|
7
|
+
* @returns An AnnotationFormatter instance
|
|
8
|
+
*/
|
|
9
|
+
export function getAnnotationFormatter(format = 'plain') {
|
|
10
|
+
// Normalize the format string
|
|
11
|
+
const normalizedFormat = format.toLowerCase().trim();
|
|
12
|
+
switch (normalizedFormat) {
|
|
13
|
+
case 'json':
|
|
14
|
+
return new JsonFormatter();
|
|
15
|
+
case 'plain':
|
|
16
|
+
case 'text':
|
|
17
|
+
return new PlainTextFormatter();
|
|
18
|
+
default:
|
|
19
|
+
logger.warn(`Unknown format '${format}', defaulting to plain text`);
|
|
20
|
+
return new PlainTextFormatter();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["formatters/annotations/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB,OAAO;IAC7D,8BAA8B;IAC9B,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAErD,QAAQ,gBAAgB,EAAE,CAAC;QACzB,KAAK,MAAM;YACT,OAAO,IAAI,aAAa,EAAE,CAAC;QAC7B,KAAK,OAAO,CAAC;QACb,KAAK,MAAM;YACT,OAAO,IAAI,kBAAkB,EAAE,CAAC;QAClC;YACE,MAAM,CAAC,IAAI,CAAC,mBAAmB,MAAM,6BAA6B,CAAC,CAAC;YACpE,OAAO,IAAI,kBAAkB,EAAE,CAAC;IACpC,CAAC;AACH,CAAC","sourcesContent":["import { AnnotationFormatter } from './Formatter.js';\nimport { PlainTextFormatter } from './PlainTextFormatter.js';\nimport { JsonFormatter } from './JsonFormatter.js';\nimport { logger } from '../../services/logger.js';\n\n/**\n * Get the appropriate annotation formatter based on the format string\n * @param format The format to use ('plain', 'json', or 'alfred')\n * @returns An AnnotationFormatter instance\n */\nexport function getAnnotationFormatter(format: string = 'plain'): AnnotationFormatter {\n // Normalize the format string\n const normalizedFormat = format.toLowerCase().trim();\n \n switch (normalizedFormat) {\n case 'json':\n return new JsonFormatter();\n case 'plain':\n case 'text':\n return new PlainTextFormatter();\n default:\n logger.warn(`Unknown format '${format}', defaulting to plain text`);\n return new PlainTextFormatter();\n }\n}\n\nexport { AnnotationFormatter };\n"]}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
export class AlfredFormatter extends BaseFormatter {
|
|
3
|
+
name = 'alfred';
|
|
4
|
+
formatBuilds(builds, options) {
|
|
5
|
+
// Handle error cases
|
|
6
|
+
if (options?.hasError) {
|
|
7
|
+
let errorTitle = 'Error';
|
|
8
|
+
let errorSubtitle = options.errorMessage || 'An error occurred';
|
|
9
|
+
if (options.errorType === 'access') {
|
|
10
|
+
errorTitle = 'Access Error';
|
|
11
|
+
if (options.accessErrors && options.accessErrors.length > 0) {
|
|
12
|
+
errorSubtitle = options.accessErrors[0];
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
errorSubtitle = 'You don\'t have access to the specified organization(s).';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else if (options.errorType === 'not_found') {
|
|
19
|
+
errorTitle = 'No Builds Found';
|
|
20
|
+
if (options.userName) {
|
|
21
|
+
errorSubtitle = `No builds found for ${options.userName}${options.userEmail ? ` (${options.userEmail})` : ''}.`;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
errorSubtitle = 'No builds found.';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const errorItem = {
|
|
28
|
+
uid: 'error',
|
|
29
|
+
title: errorTitle,
|
|
30
|
+
subtitle: errorSubtitle,
|
|
31
|
+
icon: {
|
|
32
|
+
path: 'icons/unknown.png'
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
return JSON.stringify({ items: [errorItem] }, null, 2);
|
|
36
|
+
}
|
|
37
|
+
// Handle empty results (no error, just no data)
|
|
38
|
+
if (builds.length === 0) {
|
|
39
|
+
let emptyTitle = 'No Builds Found';
|
|
40
|
+
let emptySubtitle = options?.userName
|
|
41
|
+
? `No builds found for ${options.userName}${options?.userEmail ? ` (${options.userEmail})` : ''}.`
|
|
42
|
+
: 'No builds found.';
|
|
43
|
+
if (!options?.orgSpecified) {
|
|
44
|
+
emptySubtitle += ' Try specifying an organization with --org.';
|
|
45
|
+
}
|
|
46
|
+
const emptyItem = {
|
|
47
|
+
uid: 'empty',
|
|
48
|
+
title: emptyTitle,
|
|
49
|
+
subtitle: emptySubtitle,
|
|
50
|
+
icon: {
|
|
51
|
+
path: 'icons/unknown.png'
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return JSON.stringify({ items: [emptyItem] }, null, 2);
|
|
55
|
+
}
|
|
56
|
+
// Format builds as Alfred-compatible JSON items
|
|
57
|
+
const alfredItems = builds.map((build) => {
|
|
58
|
+
// Generate web URL for the build (if not already present)
|
|
59
|
+
const buildUrl = build.web_url || build.url || '';
|
|
60
|
+
// Derive org/pipeline/number buildRef for alternative actions
|
|
61
|
+
const orgSlug = build.organization?.slug || extractFromUrl(buildUrl, 'org');
|
|
62
|
+
const pipelineSlug = build.pipeline?.slug || extractFromUrl(buildUrl, 'pipeline');
|
|
63
|
+
const buildNumber = build.number;
|
|
64
|
+
const buildRef = orgSlug && pipelineSlug && buildNumber ? `${orgSlug}/${pipelineSlug}/${buildNumber}` : undefined;
|
|
65
|
+
const uid = `${build.pipeline?.slug || 'unknown'}-${build.number}`;
|
|
66
|
+
const title = `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}`;
|
|
67
|
+
const subtitle = `${build.state || 'Unknown'} • ${build.branch || 'Unknown'} • ${build.message || 'No message'}`;
|
|
68
|
+
const autocomplete = `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}`;
|
|
69
|
+
// Previously used for alternative subtitles; not needed with new modifiers
|
|
70
|
+
const item = {
|
|
71
|
+
uid: uid,
|
|
72
|
+
title: title,
|
|
73
|
+
subtitle: subtitle,
|
|
74
|
+
arg: buildUrl,
|
|
75
|
+
autocomplete: autocomplete,
|
|
76
|
+
icon: {
|
|
77
|
+
path: this.getStateIcon(build.state)
|
|
78
|
+
},
|
|
79
|
+
mods: {
|
|
80
|
+
cmd: {
|
|
81
|
+
subtitle: 'Paste URL',
|
|
82
|
+
arg: buildUrl
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
text: {
|
|
86
|
+
copy: buildUrl,
|
|
87
|
+
largetype: `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}\n${build.state || 'Unknown'} • ${build.branch || 'Unknown'}\n${build.message || 'No message'}`
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
if (buildRef) {
|
|
91
|
+
item.mods.alt = {
|
|
92
|
+
subtitle: 'Show annotations',
|
|
93
|
+
arg: buildRef
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return item;
|
|
97
|
+
});
|
|
98
|
+
// Return formatted JSON for Alfred
|
|
99
|
+
return JSON.stringify({ items: alfredItems }, null, 2);
|
|
100
|
+
}
|
|
101
|
+
getStateIcon(state) {
|
|
102
|
+
if (!state)
|
|
103
|
+
return 'icons/unknown.png';
|
|
104
|
+
const normalizedState = state.toLowerCase();
|
|
105
|
+
switch (normalizedState) {
|
|
106
|
+
case 'passed':
|
|
107
|
+
return 'icons/passed.png';
|
|
108
|
+
case 'failed':
|
|
109
|
+
return 'icons/failed.png';
|
|
110
|
+
case 'running':
|
|
111
|
+
return 'icons/running.png';
|
|
112
|
+
case 'scheduled':
|
|
113
|
+
return 'icons/scheduled.png';
|
|
114
|
+
case 'canceled':
|
|
115
|
+
return 'icons/unknown.png';
|
|
116
|
+
case 'canceling':
|
|
117
|
+
return 'icons/unknown.png';
|
|
118
|
+
case 'skipped':
|
|
119
|
+
return 'icons/skipped.png';
|
|
120
|
+
case 'not_run':
|
|
121
|
+
return 'icons/unknown.png';
|
|
122
|
+
default:
|
|
123
|
+
return 'icons/unknown.png';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function extractFromUrl(url, part) {
|
|
128
|
+
if (!url)
|
|
129
|
+
return undefined;
|
|
130
|
+
const match = url.match(/^https?:\/\/buildkite\.com\/([^\/]+)\/([^\/]+)\/builds\/\d+\/?/i);
|
|
131
|
+
if (!match)
|
|
132
|
+
return undefined;
|
|
133
|
+
return part === 'org' ? match[1] : match[2];
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=AlfredFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/builds/AlfredFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseFormatter, BuildFormatterOptions } from './Formatter.js';\nimport { Build } from '../../types/index.js';\n\nexport class AlfredFormatter extends BaseFormatter {\n name = 'alfred';\n \n formatBuilds(builds: Build[], options?: BuildFormatterOptions): string {\n // Handle error cases\n if (options?.hasError) {\n let errorTitle = 'Error';\n let errorSubtitle = options.errorMessage || 'An error occurred';\n \n if (options.errorType === 'access') {\n errorTitle = 'Access Error';\n if (options.accessErrors && options.accessErrors.length > 0) {\n errorSubtitle = options.accessErrors[0];\n } else {\n errorSubtitle = 'You don\\'t have access to the specified organization(s).';\n }\n } else if (options.errorType === 'not_found') {\n errorTitle = 'No Builds Found';\n if (options.userName) {\n errorSubtitle = `No builds found for ${options.userName}${options.userEmail ? ` (${options.userEmail})` : ''}.`;\n } else {\n errorSubtitle = 'No builds found.';\n }\n }\n \n const errorItem = {\n uid: 'error',\n title: errorTitle,\n subtitle: errorSubtitle,\n icon: {\n path: 'icons/unknown.png'\n }\n };\n \n return JSON.stringify({ items: [errorItem] }, null, 2);\n }\n \n // Handle empty results (no error, just no data)\n if (builds.length === 0) {\n let emptyTitle = 'No Builds Found';\n let emptySubtitle = options?.userName \n ? `No builds found for ${options.userName}${options?.userEmail ? ` (${options.userEmail})` : ''}.`\n : 'No builds found.';\n \n if (!options?.orgSpecified) {\n emptySubtitle += ' Try specifying an organization with --org.';\n }\n \n const emptyItem = {\n uid: 'empty',\n title: emptyTitle,\n subtitle: emptySubtitle,\n icon: {\n path: 'icons/unknown.png'\n }\n };\n \n return JSON.stringify({ items: [emptyItem] }, null, 2);\n }\n \n // Format builds as Alfred-compatible JSON items\n const alfredItems = builds.map((build: Build) => {\n // Generate web URL for the build (if not already present)\n const buildUrl = build.web_url || build.url || '';\n\n // Derive org/pipeline/number buildRef for alternative actions\n const orgSlug = build.organization?.slug || extractFromUrl(buildUrl, 'org');\n const pipelineSlug = build.pipeline?.slug || extractFromUrl(buildUrl, 'pipeline');\n const buildNumber = build.number;\n const buildRef = orgSlug && pipelineSlug && buildNumber ? `${orgSlug}/${pipelineSlug}/${buildNumber}` : undefined;\n\n const uid = `${build.pipeline?.slug || 'unknown'}-${build.number}`;\n const title = `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}`;\n const subtitle = `${build.state || 'Unknown'} • ${build.branch || 'Unknown'} • ${build.message || 'No message'}`;\n const autocomplete = `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}`;\n\n // Previously used for alternative subtitles; not needed with new modifiers\n\n const item: any = {\n uid: uid,\n title: title,\n subtitle: subtitle,\n arg: buildUrl,\n autocomplete: autocomplete,\n icon: {\n path: this.getStateIcon(build.state)\n },\n mods: {\n cmd: {\n subtitle: 'Paste URL',\n arg: buildUrl\n }\n },\n text: {\n copy: buildUrl,\n largetype: `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}\\n${build.state || 'Unknown'} • ${build.branch || 'Unknown'}\\n${build.message || 'No message'}`\n }\n };\n\n if (buildRef) {\n item.mods.alt = {\n subtitle: 'Show annotations',\n arg: buildRef\n };\n }\n\n return item;\n });\n \n // Return formatted JSON for Alfred\n return JSON.stringify({ items: alfredItems }, null, 2);\n }\n \n private getStateIcon(state?: string): string {\n if (!state) return 'icons/unknown.png';\n \n const normalizedState = state.toLowerCase();\n switch (normalizedState) {\n case 'passed':\n return 'icons/passed.png';\n case 'failed':\n return 'icons/failed.png';\n case 'running':\n return 'icons/running.png';\n case 'scheduled':\n return 'icons/scheduled.png';\n case 'canceled':\n return 'icons/unknown.png';\n case 'canceling':\n return 'icons/unknown.png';\n case 'skipped':\n return 'icons/skipped.png';\n case 'not_run':\n return 'icons/unknown.png';\n default:\n return 'icons/unknown.png';\n }\n }\n}\n\nfunction extractFromUrl(url: string, part: 'org' | 'pipeline'): string | undefined {\n if (!url) return undefined;\n const match = url.match(/^https?:\\/\\/buildkite\\.com\\/([^\\/]+)\\/([^\\/]+)\\/builds\\/\\d+\\/?/i);\n if (!match) return undefined;\n return part === 'org' ? match[1] : match[2];\n} "]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { logger } from '../../services/logger.js';
|
|
2
|
+
export class BaseFormatter {
|
|
3
|
+
format(data, formatFn, options) {
|
|
4
|
+
if (options?.debug) {
|
|
5
|
+
logger.debug(`Formatting with ${this.name} formatter`);
|
|
6
|
+
}
|
|
7
|
+
return formatFn(data, options);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/builds/Formatter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAclD,MAAM,OAAgB,aAAa;IAKjC,MAAM,CAAI,IAAS,EAAE,QAA2D,EAAE,OAA0B;QAC1G,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;CACF","sourcesContent":["import { BaseFormatter as BaseFormatterInterface, FormatterOptions } from '../BaseFormatter.js';\nimport { Build } from '../../types/index.js';\nimport { logger } from '../../services/logger.js';\n\nexport interface BuildFormatterOptions extends FormatterOptions {\n // Error information\n hasError?: boolean;\n errorMessage?: string;\n errorType?: 'access' | 'not_found' | 'api' | 'unknown';\n accessErrors?: string[];\n}\n\nexport interface BuildFormatter extends BaseFormatterInterface {\n formatBuilds(builds: Build[], options?: BuildFormatterOptions): string;\n}\n\nexport abstract class BaseFormatter implements BuildFormatter {\n abstract name: string;\n \n abstract formatBuilds(builds: Build[], options?: BuildFormatterOptions): string;\n \n format<T>(data: T[], formatFn: (data: T[], options?: FormatterOptions) => string, options?: FormatterOptions): string {\n if (options?.debug) {\n logger.debug(`Formatting with ${this.name} formatter`);\n }\n return formatFn(data, options);\n }\n} "]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
export class JsonFormatter extends BaseFormatter {
|
|
3
|
+
name = 'json';
|
|
4
|
+
formatBuilds(builds, options) {
|
|
5
|
+
// Handle error cases
|
|
6
|
+
if (options?.hasError) {
|
|
7
|
+
const errorResult = {
|
|
8
|
+
error: true,
|
|
9
|
+
errorType: options.errorType || 'unknown',
|
|
10
|
+
message: options.errorMessage || 'An error occurred',
|
|
11
|
+
accessErrors: options.accessErrors || []
|
|
12
|
+
};
|
|
13
|
+
return JSON.stringify(errorResult, null, 2);
|
|
14
|
+
}
|
|
15
|
+
// Handle empty results (no error, just no data)
|
|
16
|
+
if (builds.length === 0) {
|
|
17
|
+
const emptyResult = {
|
|
18
|
+
count: 0,
|
|
19
|
+
builds: [],
|
|
20
|
+
message: options?.userName
|
|
21
|
+
? `No builds found for ${options.userName}${options?.userEmail ? ` (${options.userEmail})` : ''}.`
|
|
22
|
+
: 'No builds found.'
|
|
23
|
+
};
|
|
24
|
+
return JSON.stringify(emptyResult, null, 2);
|
|
25
|
+
}
|
|
26
|
+
// Normal case with builds
|
|
27
|
+
const result = {
|
|
28
|
+
count: builds.length,
|
|
29
|
+
builds: builds.map((build) => ({
|
|
30
|
+
pipeline: build.pipeline?.slug || 'Unknown pipeline',
|
|
31
|
+
number: build.number,
|
|
32
|
+
branch: build.branch || 'Unknown',
|
|
33
|
+
state: build.state || 'Unknown',
|
|
34
|
+
message: build.message || 'No message',
|
|
35
|
+
url: build.web_url || build.url || 'No URL',
|
|
36
|
+
created_at: build.created_at || build.createdAt || null,
|
|
37
|
+
started_at: build.started_at || build.startedAt || null,
|
|
38
|
+
finished_at: build.finished_at || build.finishedAt || null
|
|
39
|
+
}))
|
|
40
|
+
};
|
|
41
|
+
return JSON.stringify(result, null, 2);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=JsonFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/builds/JsonFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAyB,MAAM,gBAAgB,CAAC;AAGtE,MAAM,OAAO,aAAc,SAAQ,aAAa;IAC9C,IAAI,GAAG,MAAM,CAAC;IAEd,YAAY,CAAC,MAAe,EAAE,OAA+B;QAC3D,qBAAqB;QACrB,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;YACtB,MAAM,WAAW,GAAG;gBAClB,KAAK,EAAE,IAAI;gBACX,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;gBACzC,OAAO,EAAE,OAAO,CAAC,YAAY,IAAI,mBAAmB;gBACpD,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE;aACzC,CAAC;YAEF,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,gDAAgD;QAChD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,WAAW,GAAG;gBAClB,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,EAAE;gBACV,OAAO,EAAE,OAAO,EAAE,QAAQ;oBACxB,CAAC,CAAC,uBAAuB,OAAO,CAAC,QAAQ,GAAG,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG;oBAClG,CAAC,CAAC,kBAAkB;aACvB,CAAC;YAEF,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,0BAA0B;QAC1B,MAAM,MAAM,GAAG;YACb,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAY,EAAE,EAAE,CAAC,CAAC;gBACpC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,kBAAkB;gBACpD,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,SAAS;gBACjC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,SAAS;gBAC/B,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,YAAY;gBACtC,GAAG,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,IAAI,QAAQ;gBAC3C,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI;gBACvD,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI;gBACvD,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU,IAAI,IAAI;aAC3D,CAAC,CAAC;SACJ,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;CACF","sourcesContent":["import { BaseFormatter, BuildFormatterOptions } from './Formatter.js';\nimport { Build } from '../../types/index.js';\n\nexport class JsonFormatter extends BaseFormatter {\n name = 'json';\n \n formatBuilds(builds: Build[], options?: BuildFormatterOptions): string {\n // Handle error cases\n if (options?.hasError) {\n const errorResult = {\n error: true,\n errorType: options.errorType || 'unknown',\n message: options.errorMessage || 'An error occurred',\n accessErrors: options.accessErrors || []\n };\n \n return JSON.stringify(errorResult, null, 2);\n }\n \n // Handle empty results (no error, just no data)\n if (builds.length === 0) {\n const emptyResult = {\n count: 0,\n builds: [],\n message: options?.userName \n ? `No builds found for ${options.userName}${options?.userEmail ? ` (${options.userEmail})` : ''}.`\n : 'No builds found.'\n };\n \n return JSON.stringify(emptyResult, null, 2);\n }\n \n // Normal case with builds\n const result = {\n count: builds.length,\n builds: builds.map((build: Build) => ({\n pipeline: build.pipeline?.slug || 'Unknown pipeline',\n number: build.number,\n branch: build.branch || 'Unknown',\n state: build.state || 'Unknown',\n message: build.message || 'No message',\n url: build.web_url || build.url || 'No URL',\n created_at: build.created_at || build.createdAt || null,\n started_at: build.started_at || build.startedAt || null,\n finished_at: build.finished_at || build.finishedAt || null\n }))\n };\n \n return JSON.stringify(result, null, 2);\n }\n} "]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
export class PlainTextFormatter extends BaseFormatter {
|
|
3
|
+
name = 'plain-text';
|
|
4
|
+
formatBuilds(builds, options) {
|
|
5
|
+
// Handle error cases first
|
|
6
|
+
if (options?.hasError) {
|
|
7
|
+
if (options.errorType === 'access') {
|
|
8
|
+
return this.formatAccessError(options);
|
|
9
|
+
}
|
|
10
|
+
else if (options.errorType === 'not_found') {
|
|
11
|
+
return this.formatNotFoundError(options);
|
|
12
|
+
}
|
|
13
|
+
else if (options.errorType === 'api') {
|
|
14
|
+
return this.formatApiError(options);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return this.formatGenericError(options);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Handle empty results (no error, just no data)
|
|
21
|
+
if (builds.length === 0) {
|
|
22
|
+
let output = 'No builds found.';
|
|
23
|
+
// Add user info if provided
|
|
24
|
+
if (options?.userName) {
|
|
25
|
+
output = `No builds found for ${options.userName}`;
|
|
26
|
+
if (options?.userEmail || options?.userId) {
|
|
27
|
+
output += ` (${options.userEmail || options.userId})`;
|
|
28
|
+
}
|
|
29
|
+
output += '.';
|
|
30
|
+
}
|
|
31
|
+
// Add organization suggestion if applicable
|
|
32
|
+
if (!options?.orgSpecified) {
|
|
33
|
+
output += '\nTry specifying an organization with --org to narrow your search.';
|
|
34
|
+
}
|
|
35
|
+
return output;
|
|
36
|
+
}
|
|
37
|
+
let output = `Found ${builds.length} builds:\n`;
|
|
38
|
+
output += '==============================================\n';
|
|
39
|
+
builds.forEach((build) => {
|
|
40
|
+
try {
|
|
41
|
+
output += `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}\n`;
|
|
42
|
+
output += `State: ${build.state || 'Unknown'}\n`;
|
|
43
|
+
output += `Branch: ${build.branch || 'Unknown'}\n`;
|
|
44
|
+
output += `Message: ${build.message || 'No message'}\n`;
|
|
45
|
+
const createdDate = (build.created_at || build.createdAt) ?
|
|
46
|
+
new Date(build.created_at || build.createdAt).toLocaleString() : 'Unknown';
|
|
47
|
+
const startedDate = (build.started_at || build.startedAt) ?
|
|
48
|
+
new Date(build.started_at || build.startedAt).toLocaleString() : 'Not started';
|
|
49
|
+
const finishedDate = (build.finished_at || build.finishedAt) ?
|
|
50
|
+
new Date(build.finished_at || build.finishedAt).toLocaleString() : 'Not finished';
|
|
51
|
+
output += `Created: ${createdDate}\n`;
|
|
52
|
+
output += `Started: ${startedDate}\n`;
|
|
53
|
+
output += `Finished: ${finishedDate}\n`;
|
|
54
|
+
output += `URL: ${build.web_url || build.url || 'No URL'}\n`;
|
|
55
|
+
output += '------------------\n';
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
output += `Error displaying build: ${error}\n`;
|
|
59
|
+
if (options?.debug) {
|
|
60
|
+
output += `Build data: ${JSON.stringify(build, null, 2)}\n`;
|
|
61
|
+
}
|
|
62
|
+
output += '------------------\n';
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Summary and guidance lines
|
|
66
|
+
output += `\nShowing ${builds.length} builds. Use --count and --page options to see more.\n`;
|
|
67
|
+
if (options?.organizationsCount && options.organizationsCount > 1 && !options.orgSpecified) {
|
|
68
|
+
output += `Searched across ${options.organizationsCount} organizations. Use --org to filter to a specific organization.\n`;
|
|
69
|
+
}
|
|
70
|
+
return output;
|
|
71
|
+
}
|
|
72
|
+
formatAccessError(options) {
|
|
73
|
+
let output = '';
|
|
74
|
+
if (options?.userName) {
|
|
75
|
+
output = `No builds found for ${options.userName}`;
|
|
76
|
+
if (options?.userEmail || options?.userId) {
|
|
77
|
+
output += ` (${options.userEmail || options.userId})`;
|
|
78
|
+
}
|
|
79
|
+
output += '. ';
|
|
80
|
+
}
|
|
81
|
+
if (options?.orgSpecified && options?.accessErrors && options.accessErrors.length > 0) {
|
|
82
|
+
output += options.accessErrors[0];
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
output += 'You don\'t have access to the specified organization(s).';
|
|
86
|
+
}
|
|
87
|
+
return output;
|
|
88
|
+
}
|
|
89
|
+
formatNotFoundError(options) {
|
|
90
|
+
let output = '';
|
|
91
|
+
if (options?.userName) {
|
|
92
|
+
output = `No builds found for ${options.userName}`;
|
|
93
|
+
if (options?.userEmail || options?.userId) {
|
|
94
|
+
output += ` (${options.userEmail || options.userId})`;
|
|
95
|
+
}
|
|
96
|
+
output += '.';
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
output = 'No builds found.';
|
|
100
|
+
}
|
|
101
|
+
if (!options?.orgSpecified) {
|
|
102
|
+
output += '\nTry specifying an organization with --org to narrow your search.';
|
|
103
|
+
}
|
|
104
|
+
return output;
|
|
105
|
+
}
|
|
106
|
+
formatApiError(options) {
|
|
107
|
+
return options?.errorMessage || 'An API error occurred while fetching builds.';
|
|
108
|
+
}
|
|
109
|
+
formatGenericError(options) {
|
|
110
|
+
return options?.errorMessage || 'An error occurred while fetching builds.';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=PlainTextFormatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/builds/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseFormatter, BuildFormatterOptions } from './Formatter.js';\nimport { Build } from '../../types/index.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'plain-text';\n \n formatBuilds(builds: Build[], options?: BuildFormatterOptions): string {\n // Handle error cases first\n if (options?.hasError) {\n if (options.errorType === 'access') {\n return this.formatAccessError(options);\n } else if (options.errorType === 'not_found') {\n return this.formatNotFoundError(options);\n } else if (options.errorType === 'api') {\n return this.formatApiError(options);\n } else {\n return this.formatGenericError(options);\n }\n }\n \n // Handle empty results (no error, just no data)\n if (builds.length === 0) {\n let output = 'No builds found.';\n \n // Add user info if provided\n if (options?.userName) {\n output = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n output += ` (${options.userEmail || options.userId})`;\n }\n output += '.';\n }\n \n // Add organization suggestion if applicable\n if (!options?.orgSpecified) {\n output += '\\nTry specifying an organization with --org to narrow your search.';\n }\n \n return output;\n }\n\n let output = `Found ${builds.length} builds:\\n`;\n output += '==============================================\\n';\n \n builds.forEach((build: Build) => {\n try {\n output += `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}\\n`;\n output += `State: ${build.state || 'Unknown'}\\n`;\n output += `Branch: ${build.branch || 'Unknown'}\\n`;\n output += `Message: ${build.message || 'No message'}\\n`;\n \n const createdDate = (build.created_at || build.createdAt) ? \n new Date(build.created_at || build.createdAt as string).toLocaleString() : 'Unknown';\n \n const startedDate = (build.started_at || build.startedAt) ? \n new Date(build.started_at || build.startedAt as string).toLocaleString() : 'Not started';\n \n const finishedDate = (build.finished_at || build.finishedAt) ? \n new Date(build.finished_at || build.finishedAt as string).toLocaleString() : 'Not finished';\n \n output += `Created: ${createdDate}\\n`;\n output += `Started: ${startedDate}\\n`;\n output += `Finished: ${finishedDate}\\n`;\n output += `URL: ${build.web_url || build.url || 'No URL'}\\n`;\n output += '------------------\\n';\n } catch (error) {\n output += `Error displaying build: ${error}\\n`;\n if (options?.debug) {\n output += `Build data: ${JSON.stringify(build, null, 2)}\\n`;\n }\n output += '------------------\\n';\n }\n });\n \n // Summary and guidance lines\n output += `\\nShowing ${builds.length} builds. Use --count and --page options to see more.\\n`;\n if (options?.organizationsCount && options.organizationsCount > 1 && !options.orgSpecified) {\n output += `Searched across ${options.organizationsCount} organizations. Use --org to filter to a specific organization.\\n`;\n }\n \n return output;\n }\n \n private formatAccessError(options?: BuildFormatterOptions): string {\n let output = '';\n \n if (options?.userName) {\n output = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n output += ` (${options.userEmail || options.userId})`;\n }\n output += '. ';\n }\n \n if (options?.orgSpecified && options?.accessErrors && options.accessErrors.length > 0) {\n output += options.accessErrors[0];\n } else {\n output += 'You don\\'t have access to the specified organization(s).';\n }\n \n return output;\n }\n \n private formatNotFoundError(options?: BuildFormatterOptions): string {\n let output = '';\n \n if (options?.userName) {\n output = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n output += ` (${options.userEmail || options.userId})`;\n }\n output += '.';\n } else {\n output = 'No builds found.';\n }\n \n if (!options?.orgSpecified) {\n output += '\\nTry specifying an organization with --org to narrow your search.';\n }\n \n return output;\n }\n \n private formatApiError(options?: BuildFormatterOptions): string {\n return options?.errorMessage || 'An API error occurred while fetching builds.';\n }\n \n private formatGenericError(options?: BuildFormatterOptions): string {\n return options?.errorMessage || 'An error occurred while fetching builds.';\n }\n} "]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PlainTextFormatter } from './PlainTextFormatter.js';
|
|
2
|
+
import { JsonFormatter } from './JsonFormatter.js';
|
|
3
|
+
import { AlfredFormatter } from './AlfredFormatter.js';
|
|
4
|
+
import { logger } from '../../services/logger.js';
|
|
5
|
+
/**
|
|
6
|
+
* Get the appropriate build formatter based on the format string
|
|
7
|
+
* @param format The format to use ('plain', 'json', or 'alfred')
|
|
8
|
+
* @returns A BuildFormatter instance
|
|
9
|
+
*/
|
|
10
|
+
export function getBuildFormatter(format = 'plain') {
|
|
11
|
+
// Normalize the format string
|
|
12
|
+
const normalizedFormat = format.toLowerCase().trim();
|
|
13
|
+
switch (normalizedFormat) {
|
|
14
|
+
case 'json':
|
|
15
|
+
return new JsonFormatter();
|
|
16
|
+
case 'alfred':
|
|
17
|
+
return new AlfredFormatter();
|
|
18
|
+
case 'plain':
|
|
19
|
+
case 'text':
|
|
20
|
+
return new PlainTextFormatter();
|
|
21
|
+
default:
|
|
22
|
+
logger.warn(`Unknown format '${format}', defaulting to plain text`);
|
|
23
|
+
return new PlainTextFormatter();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["formatters/builds/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB,OAAO;IACxD,8BAA8B;IAC9B,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAErD,QAAQ,gBAAgB,EAAE,CAAC;QACzB,KAAK,MAAM;YACT,OAAO,IAAI,aAAa,EAAE,CAAC;QAC7B,KAAK,QAAQ;YACX,OAAO,IAAI,eAAe,EAAE,CAAC;QAC/B,KAAK,OAAO,CAAC;QACb,KAAK,MAAM;YACT,OAAO,IAAI,kBAAkB,EAAE,CAAC;QAClC;YACE,MAAM,CAAC,IAAI,CAAC,mBAAmB,MAAM,6BAA6B,CAAC,CAAC;YACpE,OAAO,IAAI,kBAAkB,EAAE,CAAC;IACpC,CAAC;AACH,CAAC","sourcesContent":["import { BuildFormatter } from './Formatter.js';\nimport { PlainTextFormatter } from './PlainTextFormatter.js';\nimport { JsonFormatter } from './JsonFormatter.js';\nimport { AlfredFormatter } from './AlfredFormatter.js';\nimport { logger } from '../../services/logger.js';\n\n/**\n * Get the appropriate build formatter based on the format string\n * @param format The format to use ('plain', 'json', or 'alfred')\n * @returns A BuildFormatter instance\n */\nexport function getBuildFormatter(format: string = 'plain'): BuildFormatter {\n // Normalize the format string\n const normalizedFormat = format.toLowerCase().trim();\n \n switch (normalizedFormat) {\n case 'json':\n return new JsonFormatter();\n case 'alfred':\n return new AlfredFormatter();\n case 'plain':\n case 'text':\n return new PlainTextFormatter();\n default:\n logger.warn(`Unknown format '${format}', defaulting to plain text`);\n return new PlainTextFormatter();\n }\n}\n\nexport { BuildFormatter }; "]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { BaseErrorFormatter } from './Formatter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Alfred formatter for errors
|
|
4
|
+
*
|
|
5
|
+
* This formatter provides Alfred-compatible JSON output for error conditions
|
|
6
|
+
* that can be processed by Alfred workflows
|
|
7
|
+
*/
|
|
8
|
+
export class AlfredFormatter extends BaseErrorFormatter {
|
|
9
|
+
name = 'alfred';
|
|
10
|
+
/**
|
|
11
|
+
* Format one or more errors for display in Alfred JSON format
|
|
12
|
+
*
|
|
13
|
+
* @param errors The error(s) to format
|
|
14
|
+
* @param options Formatting options
|
|
15
|
+
* @returns Alfred JSON formatted error message
|
|
16
|
+
*/
|
|
17
|
+
formatError(errors, options) {
|
|
18
|
+
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
19
|
+
const items = [];
|
|
20
|
+
for (const error of errorArray) {
|
|
21
|
+
// Add main error item
|
|
22
|
+
items.push({
|
|
23
|
+
uid: 'error',
|
|
24
|
+
title: `Error: ${this.getErrorMessage(error)}`,
|
|
25
|
+
subtitle: this.getErrorSubtitle(error),
|
|
26
|
+
arg: this.getErrorMessage(error),
|
|
27
|
+
icon: {
|
|
28
|
+
path: 'icons/error.png'
|
|
29
|
+
},
|
|
30
|
+
valid: true
|
|
31
|
+
});
|
|
32
|
+
// Add stack trace items if debug is enabled
|
|
33
|
+
if (options?.debug) {
|
|
34
|
+
const stack = this.getStackTrace(error);
|
|
35
|
+
if (stack) {
|
|
36
|
+
const stackItems = stack.split('\n').map((line, index) => ({
|
|
37
|
+
uid: `stack-${index}`,
|
|
38
|
+
title: line.trim(),
|
|
39
|
+
subtitle: 'Stack trace line',
|
|
40
|
+
arg: line,
|
|
41
|
+
icon: {
|
|
42
|
+
path: 'icons/stack.png'
|
|
43
|
+
},
|
|
44
|
+
valid: true
|
|
45
|
+
}));
|
|
46
|
+
items.push(...stackItems);
|
|
47
|
+
}
|
|
48
|
+
// Add API errors if present
|
|
49
|
+
const apiErrors = this.getApiErrors(error);
|
|
50
|
+
if (apiErrors?.length) {
|
|
51
|
+
apiErrors.forEach((apiError, index) => {
|
|
52
|
+
items.push({
|
|
53
|
+
uid: `api-error-${index}`,
|
|
54
|
+
title: `API Error: ${apiError.message || 'Unknown error'}`,
|
|
55
|
+
subtitle: apiError.path ? `Path: ${apiError.path.join('.')}` : 'API Error',
|
|
56
|
+
arg: apiError.message || 'Unknown error',
|
|
57
|
+
icon: {
|
|
58
|
+
path: 'icons/api-error.png'
|
|
59
|
+
},
|
|
60
|
+
valid: true
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Add request details if available
|
|
65
|
+
const request = this.getRequestDetails(error);
|
|
66
|
+
if (request) {
|
|
67
|
+
items.push({
|
|
68
|
+
uid: 'request-details',
|
|
69
|
+
title: 'Request Details',
|
|
70
|
+
subtitle: `${request.method || 'Unknown'} ${request.url || 'Unknown URL'}`,
|
|
71
|
+
arg: `${request.method || 'Unknown'} ${request.url || 'Unknown URL'}`,
|
|
72
|
+
icon: {
|
|
73
|
+
path: 'icons/request.png'
|
|
74
|
+
},
|
|
75
|
+
valid: false
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Add system info if debug is enabled
|
|
81
|
+
if (options?.debug) {
|
|
82
|
+
items.push({
|
|
83
|
+
uid: 'system-info',
|
|
84
|
+
title: 'System Information',
|
|
85
|
+
subtitle: `Node ${process.version} on ${process.platform} (${process.arch})`,
|
|
86
|
+
arg: `Node ${process.version} on ${process.platform} (${process.arch})`,
|
|
87
|
+
icon: {
|
|
88
|
+
path: 'icons/info.png'
|
|
89
|
+
},
|
|
90
|
+
valid: false
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return JSON.stringify({ items });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get a subtitle for the error to display in Alfred
|
|
97
|
+
* @param error The error object
|
|
98
|
+
* @returns A subtitle string
|
|
99
|
+
*/
|
|
100
|
+
getErrorSubtitle(error) {
|
|
101
|
+
const errorName = this.getErrorName(error);
|
|
102
|
+
const apiErrors = this.getApiErrors(error);
|
|
103
|
+
if (apiErrors?.length) {
|
|
104
|
+
const firstError = apiErrors[0];
|
|
105
|
+
return `API Error: ${firstError.message || 'Unknown error'}`;
|
|
106
|
+
}
|
|
107
|
+
return `${errorName} - Press Enter to copy error message`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=AlfredFormatter.js.map
|