Skip to content

Commit

Permalink
Merge pull request #41 from snyk/feat/ignore-platform-qualifiers
Browse files Browse the repository at this point in the history
feat: ignore platform qualifiers
  • Loading branch information
darscan committed Aug 4, 2023
2 parents 63ee494 + 6d3f453 commit 4486aec
Show file tree
Hide file tree
Showing 29 changed files with 344 additions and 64 deletions.
82 changes: 82 additions & 0 deletions .circleci/config.yml
@@ -0,0 +1,82 @@
version: 2.1

orbs:
prodsec: snyk/prodsec-orb@1.0

executors:
docker-node:
parameters:
version:
default: 'lts'
type: string
docker:
- image: cimg/node:<<parameters.version>>

commands:
install:
steps:
- run:
name: Install
command: npm install
test:
steps:
- run:
name: Test
command: npm test
release:
steps:
- run:
name: Release
command: npx semantic-release

jobs:
test:
resource_class: small
parameters:
node-version:
type: string
executor:
name: docker-node
version: << parameters.node-version >>
steps:
- checkout
- install
- test

release:
resource_class: small
executor:
name: docker-node
steps:
- checkout
- install
- release

workflows:
version: 2
test:
jobs:
- prodsec/secrets-scan:
name: Scan repository for secrets
context:
- snyk-bot-slack
channel: os-team-managed-alerts
- test:
name: Test Node << matrix.node-version >>
context: nodejs-install
matrix:
parameters:
node-version: ['16.1.0']
filters:
branches:
ignore:
- master
release:
jobs:
- release:
name: Release
context: nodejs-lib-release
filters:
branches:
only:
- master
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
@@ -1 +1 @@
* @snyk/loki
* @snyk/os-managed
2 changes: 1 addition & 1 deletion .nvmrc
@@ -1 +1 @@
8
16
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
@@ -0,0 +1,5 @@
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.1
hooks:
- id: gitleaks
3 changes: 1 addition & 2 deletions jest.config.js
@@ -1,8 +1,7 @@
// remove the noise from express server logs
process.env.LOG_LEVEL="fatal";
process.env.LOG_LEVEL = 'fatal';

module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};

17 changes: 15 additions & 2 deletions lib/functions.ts
@@ -1,6 +1,6 @@
import { GemVersion, MaybeGemVersion } from './ruby/gem-version';
import { GemVersion, MaybeGemVersion, Platform } from './ruby/gem-version';

export { valid, prerelease, major, minor, patch, inc };
export { valid, prerelease, platform, major, minor, patch, inc };

type Segment = string | number;

Expand Down Expand Up @@ -37,6 +37,19 @@ function prerelease(v: MaybeGemVersion): Segment[] | null {
}
}

function platform(v: MaybeGemVersion): Platform | null {
try {
const version = GemVersion.create(v);
if (version.platform) {
return version.platform
} else {
return null;
}
} catch (err) {
return null;
}
}

function _segmentAt(v, index): Segment | null {
try {
const segment = GemVersion.create(v).getSegments()[index];
Expand Down
4 changes: 2 additions & 2 deletions lib/ranges.ts
Expand Up @@ -77,11 +77,11 @@ function _firstSatisfying(
compareFunction,
): string {
const requirement = _createRequirement(range);
const maxSatisfying = versions
const firstSatisfyingVersion = versions
.map((v) => GemVersion.create(v))
.sort(compareFunction)
.find((v) => requirement.satisfiedBy(v));
return maxSatisfying ? maxSatisfying.toString() : null;
return firstSatisfyingVersion ? firstSatisfyingVersion.toString() : null;
}

function maxSatisfying(versions: MaybeGemVersion[], range: string): string {
Expand Down
6 changes: 4 additions & 2 deletions lib/ruby/gem-requirement.ts
Expand Up @@ -14,6 +14,8 @@ const OPS = {
'~>': (v, r) => v.compare(r) >= 0 && v.release().compare(r.bump()) < 0,
};

type OP = keyof typeof OPS;

const quoted = Object.keys(OPS)
.map((k) => _escapeRegExp(k))
.join('|');
Expand All @@ -24,12 +26,12 @@ const PATTERN = new RegExp(`^${PATTERN_RAW}$`);

// --
// The default requirement matches any version
const DefaultRequirement: [string, GemVersion] = ['>=', new GemVersion('0')];
const DefaultRequirement: [OP, GemVersion] = ['>=', new GemVersion('0')];

type RequirementParts = GemVersion | string | Array<RequirementParts>;

export class GemRequirement {
requirements: Array<unknown>;
requirements: Array<[OP, GemVersion]>;

// --
// Factory method to create a GemRequirement object. Input may be
Expand Down
28 changes: 27 additions & 1 deletion lib/ruby/gem-version.ts
Expand Up @@ -152,11 +152,26 @@ const VERSION_PATTERN =
'[0-9]+(\\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?';
const ANCHORED_VERSION_PATTERN = new RegExp(`^\\s*(${VERSION_PATTERN})?\\s*$`);

export const VALID_PLATFORM_QUALIFIERS = [
'x86_64-darwin',
'arm-linux',
'java',
'arm64-darwin',
'x86-mingw32',
'aarch64-linux',
'x64-mingw-ucrt',
'x86-linux',
'x64-mingw32',
'x86_64-linux',
] as const;

export type MaybeGemVersion = GemVersion | string;
export type Ordering = 1 | 0 | -1;
export type Platform = typeof VALID_PLATFORM_QUALIFIERS[number];

export class GemVersion {
version: string;
platform?: Platform;
_release?: GemVersion;
_isPrerelease?: boolean;
_bump?: GemVersion;
Expand All @@ -168,7 +183,7 @@ export class GemVersion {
// -----------------------------
// A string representation of this Version.
toString(): string {
return this.version;
return this.platform ? `${this.version}-${this.platform as string}` : this.version;
}

// -----------------------------
Expand Down Expand Up @@ -210,6 +225,17 @@ export class GemVersion {
// series of digits or ASCII letters separated by dots.

constructor(version: string) {
const platform: Platform | undefined = VALID_PLATFORM_QUALIFIERS.find(
(platform) => {
return version.endsWith(`-${platform}`);
},
);

if (platform) {
this.platform = platform;
version = version.slice(0, -platform.length - 1);
}

if (!GemVersion.isCorrect(version)) {
throw new Error(`Malformed version number string ${version}`);
}
Expand Down
14 changes: 7 additions & 7 deletions package.json
Expand Up @@ -9,20 +9,20 @@
"prepare": "npm run build",
"build": "tsc",
"lint": "eslint 'lib/**/*.?s'",
"test": "jest \"test/.*\\.test\\.ts\""
"test": "jest \"test/.*\\.test\\.ts\" --runInBand --no-cache"
},
"author": "Gareth Visagie <gareth@snyk.io>",
"license": "Apache-2.0",
"devDependencies": {
"@types/jest": "^25.0.0",
"@types/jest": "^29.5.2",
"@typescript-eslint/eslint-plugin": "^3.5.0",
"@typescript-eslint/parser": "^3.5.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.11.0",
"jest": "^25.0.0",
"prettier": "^2.0.5",
"ts-jest": "^25.0.0",
"typescript": "~3.8.3"
"jest": "^29.5.0",
"prettier": "^2.8.8",
"ts-jest": "^29.1.0",
"typescript": "^5.1.3"
},
"repository": {
"type": "git",
Expand All @@ -35,6 +35,6 @@
"lodash.escaperegexp": "^4.1.0",
"lodash.flatten": "^4.4.0",
"lodash.uniq": "^4.5.0",
"tslib": "^1.13.0"
"tslib": "^2.5.3"
}
}
38 changes: 26 additions & 12 deletions test/comparison/cmp.test.ts
Expand Up @@ -6,57 +6,71 @@ import { cmp } from '../../';
// Throws if an invalid comparison string is provided.

describe('test cmp', () => {
it('cmp(v1, ">", v2)', () => {
it('cmp(v1, ">", v2)', () => {
expect(cmp('2', '>', '1')).toBeTruthy();
expect(cmp('2', '>', '2')).toBeFalsy();
expect(cmp('1', '>', '2')).toBeFalsy();
expect(cmp('1.0.0-x86_64-linux', '>', '1.0.0-java')).toBeFalsy();
});

it('cmp(v1, ">=", v2)', () => {
it('cmp(v1, ">=", v2)', () => {
expect(cmp('2', '>=', '1')).toBeTruthy();
expect(cmp('2', '>=', '2')).toBeTruthy();
expect(cmp('1', '>=', '2')).toBeFalsy();
expect(cmp('1.0.0-x86_64-linux', '>=', '1.0.0-java')).toBeTruthy();
});

it('cmp(v1, "<", v2)', () => {
it('cmp(v1, "<", v2)', () => {
expect(cmp('1', '<', '2')).toBeTruthy();
expect(cmp('2', '<', '2')).toBeFalsy();
expect(cmp('2', '<', '1')).toBeFalsy();
expect(cmp('1.0.0-x86_64-linux', '<', '1.0.0-java')).toBeFalsy();
});

it('cmp(v1, "<=", v2)', () => {
it('cmp(v1, "<=", v2)', () => {
expect(cmp('1', '<=', '2')).toBeTruthy();
expect(cmp('2', '<=', '2')).toBeTruthy();
expect(cmp('2', '<=', '1')).toBeFalsy();
expect(cmp('1.0.0-x86_64-linux', '<=', '1.0.0-java')).toBeTruthy();
});

it('cmp(v1, "==", v2)', () => {
it('cmp(v1, "==", v2)', () => {
expect(cmp('2', '==', '2')).toBeTruthy();
expect(cmp('2', '==', '2.0')).toBeTruthy();
expect(cmp('2', '==', '1')).toBeFalsy();
expect(cmp('1.0.0-x86_64-linux', '==', '1.0.0-java')).toBeTruthy();
});

it('cmp(v1, "!=", v2)', () => {
it('cmp(v1, "!=", v2)', () => {
expect(cmp('2', '!=', '1')).toBeTruthy();
expect(cmp('2', '!=', '2')).toBeFalsy();
expect(cmp('2', '!=', '2.0')).toBeFalsy();
expect(cmp('1.0.0-x86_64-linux', '!=', '1.0.0-java')).toBeFalsy();
});

it('cmp(v1, "===", v2)', () => {
it('cmp(v1, "===", v2)', () => {
expect(cmp('2', '===', '2')).toBeTruthy();
expect(cmp('2', '===', '1')).toBeFalsy();
expect(cmp('2', '===', '2.0')).toBeFalsy();
expect(cmp('1', '===', '1.0.0-java')).toBeFalsy();
});

it('cmp(v1, "!==", v2)', () => {
it('cmp(v1, "!==", v2)', () => {
expect(cmp('2', '!==', '2')).toBeFalsy();
expect(cmp('2', '!==', '2.0')).toBeTruthy();
expect(cmp('2', '!==', '1')).toBeTruthy();
expect(cmp('1', '!==', '1.0.0-java')).toBeTruthy();
});

it('cmp(v1, "nonsense", v2)', () => {
expect(() => {cmp('2', 'nonsense', '2')}).toThrow(new Error('Invalid comparator: nonsense'));
expect(() => {cmp('2', '!====', '2')}).toThrow(new Error('Invalid comparator: !===='));
expect(() => {cmp('2', '>broken', '2')}).toThrow(new Error('Invalid comparator: >broken'));
it('cmp(v1, "nonsense", v2)', () => {
expect(() => {
cmp('2', 'nonsense', '2');
}).toThrow(new Error('Invalid comparator: nonsense'));
expect(() => {
cmp('2', '!====', '2');
}).toThrow(new Error('Invalid comparator: !===='));
expect(() => {
cmp('2', '>broken', '2');
}).toThrow(new Error('Invalid comparator: >broken'));
});
});
5 changes: 4 additions & 1 deletion test/comparison/compare.test.ts
Expand Up @@ -11,6 +11,7 @@ describe('test compare', () => {
expect(compare('1.1.0.1', '1.1.0.1')).toBe(0);
expect(compare('1.1.0.1-alpha', '1.1.0.1-alpha')).toBe(0);
expect(compare('1.1.0.1-alpha.2', '1.1.0.1-alpha.2')).toBe(0);
expect(compare('1.0.0-x86_64-linux', '1.0.0-java')).toBe(0);
});

it('compare(v1, v2): 1 if v1 > v2', () => {
Expand All @@ -20,6 +21,7 @@ describe('test compare', () => {
expect(compare('1.1.0.2', '1.1.0.1')).toBe(1);
expect(compare('1.1.0.1-beta', '1.1.0.1-alpha')).toBe(1);
expect(compare('1.1.0.1-alpha.3', '1.1.0.1-alpha.2')).toBe(1);
expect(compare('1.0.1-x86_64-linux', '1.0.0-java')).toBe(1);
});

it('compare(v1, v2): -1 if v1 < v2', () => {
Expand All @@ -29,5 +31,6 @@ describe('test compare', () => {
expect(compare('1.1.0.1', '1.1.0.2')).toBe(-1);
expect(compare('1.1.0.1-alpha', '1.1.0.1-beta')).toBe(-1);
expect(compare('1.1.0.1-alpha.2', '1.1.0.1-alpha.3')).toBe(-1);
})
expect(compare('1.0.0-x86_64-linux', '1.0.1-java')).toBe(-1);
});
});

0 comments on commit 4486aec

Please sign in to comment.