Skip to content

Commit

Permalink
feat: add sortResults function
Browse files Browse the repository at this point in the history
This API is intended to provide a consistent functionality for
sorting function results. The sorting behavior is based on the
functionality of the Sort implementation in the golang function sdk.
  • Loading branch information
sdowell committed Jan 10, 2022
1 parent 9bdbadb commit 69db526
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 1 deletion.
60 changes: 60 additions & 0 deletions ts/kpt-functions/src/types.ts
Expand Up @@ -479,3 +479,63 @@ interface ConfigMap extends KubernetesObject {
function isConfigMap(o: any): o is ConfigMap {
return o && o.apiVersion === 'v1' && o.kind === 'ConfigMap';
}

function fileLess(a: Result, b: Result): number {
const pathA = a.file?.path ?? '';
const pathB = b.file?.path ?? '';
const indexA = a.file?.index ?? 0;
const indexB = b.file?.index ?? 0;

if (pathA < pathB) {
return -1;
} else if (pathA > pathB) {
return 1;
}
return indexA - indexB;
}

function severityLess(a: Result, b: Result): number {
const severityToNumber = {
error: 0,
warn: 1,
info: 2,
};
const severityLevelA = severityToNumber[a.severity];
const severityLevelB = severityToNumber[b.severity];
return severityLevelA - severityLevelB;
}

function stringLess(a: Result, b: Result): number {
const stringify = (r: Result): string => {
return `resource-ref:${JSON.stringify(
r.resourceRef
)},field:${JSON.stringify(r.field)},message:${r.message}`;
};
const s1 = stringify(a);
const s2 = stringify(b);
if (s1 < s2) {
return -1;
} else if (s1 > s2) {
return 1;
}
return 0;
}

/**
* Perform an in place sort of Results
* @param results Array of Result objects
*/
export function sortResults(results: Result[]): Result[] {
results.sort((a: Result, b: Result): number => {
const file = fileLess(a, b);
if (file !== 0) {
return file;
}
const severity = severityLess(a, b);
if (severity !== 0) {
return severity;
}
return stringLess(a, b);
});
return results;
}
140 changes: 139 additions & 1 deletion ts/kpt-functions/src/types_test.ts
Expand Up @@ -16,7 +16,7 @@

import _ from 'lodash';
import { ObjectMeta } from './gen/io.k8s.apimachinery.pkg.apis.meta.v1';
import { Configs, KubernetesObject } from './types';
import { Configs, KubernetesObject, sortResults } from './types';
import { generalResult } from './result';

class Role implements KubernetesObject {
Expand Down Expand Up @@ -333,3 +333,141 @@ describe('results', () => {
expect(results).toEqual([generalResult('a'), generalResult('b')]);
});
});

describe('sortResults', () => {
it('sort based on severity', () => {
const configs = new Configs();
configs.addResults({ message: 'Error message 1', severity: 'info' });
configs.addResults({ message: 'Error message 2', severity: 'error' });
const results = sortResults(configs.getResults());

expect(results).toEqual([
{ message: 'Error message 2', severity: 'error' },
{ message: 'Error message 1', severity: 'info' },
]);
});

it('sort based on file', () => {
const configs = new Configs();
configs.addResults({
message: 'Error message',
severity: 'error',
file: { path: 'resource.yaml', index: 1 },
});
configs.addResults({
message: 'Error message',
severity: 'info',
file: { path: 'resource.yaml', index: 0 },
});
configs.addResults({
message: 'Error message',
severity: 'info',
file: { path: 'other-resource.yaml', index: 0 },
});
configs.addResults({
message: 'Error message',
severity: 'warn',
file: { path: 'resource.yaml', index: 2 },
});
configs.addResults({ message: 'Error message', severity: 'warn' });
const results = sortResults(configs.getResults());

expect(results).toEqual([
{ message: 'Error message', severity: 'warn' },
{
message: 'Error message',
severity: 'info',
file: { path: 'other-resource.yaml', index: 0 },
},
{
message: 'Error message',
severity: 'info',
file: { path: 'resource.yaml', index: 0 },
},
{
message: 'Error message',
severity: 'error',
file: { path: 'resource.yaml', index: 1 },
},
{
message: 'Error message',
severity: 'warn',
file: { path: 'resource.yaml', index: 2 },
},
]);
});

it('sort based on other fields', () => {
const configs = new Configs();
configs.addResults({
message: 'Error message',
severity: 'error',
resourceRef: {
apiVersion: 'v1',
kind: 'Pod',
name: 'bar',
namespace: 'foo-ns',
},
field: { path: 'spec' },
});
configs.addResults({
message: 'Error message',
severity: 'error',
resourceRef: {
apiVersion: 'v1',
kind: 'Pod',
name: 'bar',
namespace: 'foo-ns',
},
field: { path: 'metadata.name' },
});
configs.addResults({
message: 'Another error message',
severity: 'error',
resourceRef: {
apiVersion: 'v1',
kind: 'ConfigMap',
name: 'bar',
namespace: 'foo-ns',
},
field: { path: 'metadata.name' },
});
const results = sortResults(configs.getResults());

expect(results).toEqual([
{
message: 'Another error message',
severity: 'error',
resourceRef: {
apiVersion: 'v1',
kind: 'ConfigMap',
name: 'bar',
namespace: 'foo-ns',
},
field: { path: 'metadata.name' },
},
{
message: 'Error message',
severity: 'error',
resourceRef: {
apiVersion: 'v1',
kind: 'Pod',
name: 'bar',
namespace: 'foo-ns',
},
field: { path: 'metadata.name' },
},
{
message: 'Error message',
severity: 'error',
resourceRef: {
apiVersion: 'v1',
kind: 'Pod',
name: 'bar',
namespace: 'foo-ns',
},
field: { path: 'spec' },
},
]);
});
});

0 comments on commit 69db526

Please sign in to comment.