From ee41ea4c162d01f9f424056ee3076ce8bd064ae1 Mon Sep 17 00:00:00 2001 From: Francesco Date: Mon, 13 Dec 2021 09:57:49 +0000 Subject: [PATCH] Release v1.0.3 (#7) * Refactor and upgrade dependencies (#5) * Prepare for release 1.0.3 (#6) --- .eslintrc.js | 7 +- .github/workflows/publish.yml | 19 +++++ .github/workflows/run-tests.yml | 28 +++++++ .npmignore | 8 -- README.md | 22 ++---- package.json | 40 +++++----- src/__tests__/services/redis/Redis.test.ts | 5 ++ src/services/Redis.ts | 88 ++++++++++------------ src/types/Expire.ts | 14 +++- src/types/Service.ts | 8 +- src/types/redis/Service.ts | 12 --- tsconfig.build.json | 7 ++ tsconfig.json | 4 - 13 files changed, 150 insertions(+), 112 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/run-tests.yml delete mode 100644 .npmignore delete mode 100644 src/types/redis/Service.ts create mode 100644 tsconfig.build.json diff --git a/.eslintrc.js b/.eslintrc.js index 98a1c90..20d64d4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,11 +1,16 @@ module.exports = { - root: true, parser: '@typescript-eslint/parser', + parserOptions: { + project: ['./tsconfig.json'] + }, plugins: [ '@typescript-eslint', ], extends: [ + 'airbnb-base', 'airbnb-typescript/base', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking' ], rules: { '@typescript-eslint/indent': ['error', 4], diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..57b9df1 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,19 @@ +name: Publish Package to npmjs + +on: + release: + types: [ created ] + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm install + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..9720b46 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,28 @@ +name: run-tests + +on: + push: + branches: + - main + - v1.x + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + node: [ '14.x', '16.x' ] + + name: Node v${{ matrix.node }} + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + - run: npm install + - run: npm run lint + - run: npm run test + - run: npm run build diff --git a/.npmignore b/.npmignore deleted file mode 100644 index dd81148..0000000 --- a/.npmignore +++ /dev/null @@ -1,8 +0,0 @@ -/coverage -/node_modules -/src -.gitignore -.travis.yml -package-lock.json -tsconfig.json -tslint.json diff --git a/README.md b/README.md index dbe85c5..6f6ae6c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Cache JS -[![Build Status](https://travis-ci.com/Pod-Point/cache-js.svg?branch=master)](https://travis-ci.com/Pod-Point/cache-js) +![Build Status](https://github.com/Pod-Point/cache-js/actions/workflows/run-tests.yml/badge.svg) A cache service for JS. @@ -41,22 +41,14 @@ This package uses jest. To run the test suites for this project, run the followi npm run test ``` -### Releases +## License -This package is distributed via NPM and published automatically by Travis when creating a tagged commit. This can be done in one of 2 ways: +The MIT License (MIT). Please see [License File](LICENCE) for more information. -#### 1. Pre-merge via the CLI +--- -**Before** merging your PR following code review & QA, run the following commands to update the package version and create a new release/tag. -``` -npm version -git push && git push --tags -``` - -If you forget to do this before merging, this is not a problem, just create a new branch from master and run these same commands, remembering to open and merge a PR for this branch so that the `package.json` file is updated, alternatively, see option 2. - -#### 2. Post-merge via code & GitHub + -**After** merging your code changes, create a new branch/PR from master and update the package version in `package.json` to whatever you wish the next release to be. +Travel shouldn't damage the earth 🌍 -**Before** merging this PR, create a release via GitHub with a tag version to match this package version number, this will trigger the tagged commit and in turn the automatic deployment to NPM. +Made with ❤️  at [Pod Point](https://pod-point.com) diff --git a/package.json b/package.json index 4557c84..72e195b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pod-point/cache-js", - "version": "1.0.2", + "version": "1.0.3", "description": "A cache service for JS.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -20,30 +20,34 @@ "Cache", "Redis" ], + "files": [ + "lib" + ], "scripts": { - "build": "node_modules/.bin/tsc", - "lint": "node_modules/.bin/eslint 'src/**/*.{ts,tsx}'", + "build": "node_modules/.bin/tsc --project tsconfig.build.json", + "lint": "node_modules/.bin/eslint 'src/**/*.ts'", "lint:fix": "npm run lint -- --fix", - "test": "node_modules/.bin/jest --watch", + "test": "node_modules/.bin/jest", + "test:watch": "node_modules/.bin/jest --watch", "test:coverage": "node_modules/.bin/jest --coverage --runInBand --ci" }, "dependencies": { - "redis": "^2.8.0" + "redis": "^3.1.2" }, "devDependencies": { - "@types/faker": "^4.1.8", - "@types/jest": "^24.0.25", - "@types/node": "^13.1.1", - "@types/redis": "^2.8.14", - "@typescript-eslint/eslint-plugin": "^2.13.0", - "@typescript-eslint/parser": "^2.13.0", - "eslint": "^6.8.0", - "eslint-config-airbnb-typescript": "^6.3.1", - "eslint-plugin-import": "^2.19.1", - "faker": "^4.1.0", - "jest": "^24.9.0", - "ts-jest": "^24.2.0", - "typescript": "^3.7.4" + "@types/faker": "^5.5.9", + "@types/jest": "^27.0.3", + "@types/redis": "^2.8.32", + "@types/node": "^16.11.12", + "@typescript-eslint/eslint-plugin": "^5.6.0", + "@typescript-eslint/parser": "^5.6.0", + "eslint": "^8.4.1", + "eslint-config-airbnb-typescript": "^16.1.0", + "eslint-plugin-import": "^2.25.3", + "faker": "^5.5.3", + "jest": "^27.4.4", + "ts-jest": "^27.1.1", + "typescript": "^4.5.3" }, "jest": { "collectCoverageFrom": [ diff --git a/src/__tests__/services/redis/Redis.test.ts b/src/__tests__/services/redis/Redis.test.ts index 95df760..dd2c053 100644 --- a/src/__tests__/services/redis/Redis.test.ts +++ b/src/__tests__/services/redis/Redis.test.ts @@ -1,12 +1,17 @@ import { createClient } from 'redis'; import Redis from '../../../services/Redis'; +/* eslint-disable + @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-unsafe-return + */ const mockSet = jest.fn((key, value, cb) => cb()); const mockQuit = jest.fn(); const mockDel = jest.fn((key, cb) => cb()); const mockExpire = jest.fn((key, time, cb) => cb()); const mockExpireAt = jest.fn((key, time, cb) => cb()); const mockGet = jest.fn((key, cb) => cb(null, 'someData')); +/* eslint-enable */ jest.mock('redis', () => ({ createClient: jest.fn(() => ({ diff --git a/src/services/Redis.ts b/src/services/Redis.ts index 45fabfd..b309d30 100644 --- a/src/services/Redis.ts +++ b/src/services/Redis.ts @@ -1,15 +1,39 @@ -import { ClientOpts, createClient } from 'redis'; +import { ClientOpts, createClient, RedisClient } from 'redis'; import { promisify } from 'util'; import Expire from '../types/Expire'; import Service from '../types/Service'; -import RedisService from '../types/redis/Service'; -class Redis implements Service { - private config: ClientOpts; +interface AsyncRedisClient { + del: (key: string) => Promise; + expire: (key: string, seconds: number) => Promise; + expireAt: (key: string, seconds: number) => Promise; + get: (key: string) => Promise; + quit: () => void + set: (key: string, value: string) => Promise; +} + +function getClient(client: RedisClient): AsyncRedisClient { + return { + /* eslint-disable + @typescript-eslint/unbound-method, + @typescript-eslint/no-unsafe-assignment + */ + del: promisify(client.del).bind(client), + expire: promisify(client.expire).bind(client), + expireAt: promisify(client.expireat).bind(client), + get: promisify(client.get).bind(client), + quit: client.quit as () => void, + set: promisify(client.set).bind(client), + /* eslint-enable */ + }; +} + +export default class Redis implements Service { + private readonly config: ClientOpts; - private ephemeral: boolean; + private readonly ephemeral: boolean; - private service: RedisService; + private readonly client: AsyncRedisClient; /** * Creates a Redis client instance depending on config. @@ -17,21 +41,16 @@ class Redis implements Service { public constructor(config?: ClientOpts, ephemeral?: boolean) { this.ephemeral = ephemeral; this.config = config; - - if (!this.ephemeral) { - this.service = this.getService(true); - } + this.client = getClient(createClient(config)); } /** * Retrieves the keys value from the cache. */ public async get(key: string): Promise { - const service = this.getService(); + const value = await this.client.get(key); - const value = await service.get(key); - - this.quitIfNeeded(service); + this.quitIfNeeded(); return value; } @@ -41,61 +60,36 @@ class Redis implements Service { * optionally setting it to expire at a particular time or in a given number of seconds. */ public async put(key: string, value: string, expire?: Expire): Promise { - const service = this.getService(); - - await service.set(key, value); + await this.client.set(key, value); if (expire) { if (expire.at) { - await service.expireAt(key, expire.at); + await this.client.expireAt(key, expire.at); } if (expire.in) { - await service.expire(key, expire.in); + await this.client.expire(key, expire.in); } } - this.quitIfNeeded(service); + this.quitIfNeeded(); } /** * Removes the key/value pair from the cache. */ public async remove(key: string): Promise { - const service = this.getService(); + await this.client.del(key); - await service.del(key); - - this.quitIfNeeded(service); + this.quitIfNeeded(); } /** * Quits the redis client if required. */ - private async quitIfNeeded(service): Promise { + private quitIfNeeded(): void { if (this.ephemeral) { - service.client.quit(); - } - } - - /** - * Creates new Redis instance if one does not already exist or if is configured to be ephemeral. - */ - private getService(force: boolean = false): RedisService { - if (this.ephemeral || force) { - const client = createClient(this.config); - this.service = { - client, - del: promisify(client.del).bind(client), - expire: promisify(client.expire).bind(client), - expireAt: promisify(client.expireat).bind(client), - get: promisify(client.get).bind(client), - set: promisify(client.set).bind(client), - }; + this.client.quit(); } - - return this.service; } } - -export default Redis; diff --git a/src/types/Expire.ts b/src/types/Expire.ts index 35f81ed..d15bca4 100644 --- a/src/types/Expire.ts +++ b/src/types/Expire.ts @@ -1,13 +1,21 @@ -interface Expire { +interface ExpireAt { /** * The timestamp when the key/value pair should expire. */ - at?: number; + at: number; + in?: never; +} + +interface ExpireIn { /** * The number of seconds until the key/value pair should expire. */ - in?: number; + in: number; + + at?: never; } +type Expire = ExpireAt | ExpireIn; + export default Expire; diff --git a/src/types/Service.ts b/src/types/Service.ts index e54b156..50a27a3 100644 --- a/src/types/Service.ts +++ b/src/types/Service.ts @@ -1,4 +1,6 @@ -interface Service { +import Expire from './Expire'; + +export default interface Service { /** * Retrieves the keys value from the cache. */ @@ -7,12 +9,10 @@ interface Service { /** * Persists the key/value pair in the cache. */ - put(key: string, value: string): Promise; + put(key: string, value: string, expire: Expire): Promise; /** * Removes the key/value pair from the cache. */ remove(key: string): Promise; } - -export default Service; diff --git a/src/types/redis/Service.ts b/src/types/redis/Service.ts deleted file mode 100644 index 7ed0bd6..0000000 --- a/src/types/redis/Service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RedisClient } from 'redis'; - -interface RedisService { - client: RedisClient, - del: (key: string) => Promise; - expire: (key: string, seconds: number) => Promise; - expireAt: (key: string, seconds: number) => Promise; - get: (key: string) => Promise; - set: (key: string, value: string) => Promise; -} - -export default RedisService; diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..ed151f4 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "exclude": [ + "**/__mocks__", + "**/__tests__" + ] +} diff --git a/tsconfig.json b/tsconfig.json index e695cf4..3012d45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,9 +12,5 @@ }, "include": [ "src/**/*" - ], - "exclude": [ - "**/__mocks__", - "**/__tests__" ] }