Merged in fix/SW-2401-share-cache-in-prod (pull request #1815)
Fix/SW-2401 share cache in prod * fix: reuse cache between prod and pre-prod * tests: add tests for generating cachePrefix * tests: remove unnecessary reset of process.env * tests: add tests for generateCacheKey * fix: make sure that we don't get invalid cacheKeys * fix: make sure that we don't get invalid cacheKeys Approved-by: Linus Flood
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import { generateCacheKey } from "./generateCacheKey"
|
||||
|
||||
export function getCacheEndpoint(key: string) {
|
||||
if (!env.REDIS_API_HOST) {
|
||||
throw new Error("REDIS_API_HOST is not set")
|
||||
}
|
||||
|
||||
const url = new URL(`/api/cache`, env.REDIS_API_HOST)
|
||||
url.searchParams.set("key", encodeURIComponent(generateCacheKey(key)))
|
||||
url.searchParams.set("key", encodeURIComponent(key))
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { env } from "@/env/server"
|
||||
|
||||
export function generateCacheKey(key: string | string[]): string {
|
||||
const prefix = getPrefix()
|
||||
key = Array.isArray(key) ? key.join("_") : key
|
||||
|
||||
return `${prefix ? `${prefix}:` : ""}${key}`
|
||||
}
|
||||
|
||||
function getPrefix(): string {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const devPrefix = process.env.USER || process.env.USERNAME || "dev"
|
||||
return `${devPrefix}`
|
||||
}
|
||||
|
||||
const branch = env.BRANCH.trim()
|
||||
const gitSha = env.GIT_SHA?.trim().substring(0, 7)
|
||||
|
||||
return `${branch}:${gitSha}`
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it } from "@jest/globals"
|
||||
|
||||
import { getBranchPrefix } from "./getBranchPrefix"
|
||||
|
||||
describe("getBranchPrefix", () => {
|
||||
it("should return empty string for production branches", () => {
|
||||
expect(getBranchPrefix("production")).toBe("")
|
||||
expect(getBranchPrefix("prod")).toBe("")
|
||||
expect(getBranchPrefix("release")).toBe("")
|
||||
expect(getBranchPrefix("release-v1")).toBe("")
|
||||
expect(getBranchPrefix("release-v1.2")).toBe("")
|
||||
expect(getBranchPrefix("release-v1.2.3")).toBe("")
|
||||
expect(getBranchPrefix("release-v1.2.3-rc1")).toBe("")
|
||||
expect(getBranchPrefix("release-v1.2-beta")).toBe("")
|
||||
expect(getBranchPrefix("release-v1-preview")).toBe("")
|
||||
})
|
||||
|
||||
it("should return branch name for non-production branches", () => {
|
||||
expect(getBranchPrefix("feature/hello")).toBe("feature/hello")
|
||||
expect(getBranchPrefix("fix/stuff")).toBe("fix/stuff")
|
||||
expect(getBranchPrefix("releasee")).toBe("releasee")
|
||||
expect(getBranchPrefix("release-vA")).toBe("release-vA")
|
||||
expect(getBranchPrefix("release-v1.A")).toBe("release-v1.A")
|
||||
expect(getBranchPrefix("release-v1.2.A")).toBe("release-v1.2.A")
|
||||
expect(getBranchPrefix("release-v1.2.A-rc1")).toBe("release-v1.2.A-rc1")
|
||||
expect(getBranchPrefix("release-v1.A-beta")).toBe("release-v1.A-beta")
|
||||
expect(getBranchPrefix("release-vA-preview")).toBe("release-vA-preview")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* This will match release branches
|
||||
* @example
|
||||
* release-v1.2.3
|
||||
* release-v1.2
|
||||
* release-v1
|
||||
* release-v1.2.3-alpha
|
||||
* release-v1.2-beta
|
||||
* release-v1-preview
|
||||
*/
|
||||
const releaseRegex = /^release-v\d+(?:\.\d+){0,2}(?:-\w+)?$/
|
||||
|
||||
/**
|
||||
* If the branch is a production branch reuse the same prefix so that we can reuse the cache between pre-prod and prod
|
||||
* @param branch
|
||||
* @returns
|
||||
*/
|
||||
export const getBranchPrefix = (branch: string) => {
|
||||
const isProdBranch =
|
||||
branch === "production" ||
|
||||
branch === "prod" ||
|
||||
branch === "release" ||
|
||||
releaseRegex.test(branch)
|
||||
|
||||
return isProdBranch ? "" : branch
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import { describe, expect, it, jest } from "@jest/globals"
|
||||
|
||||
jest.doMock("@/env/server", () => ({
|
||||
env: {
|
||||
NODE_ENV: "test",
|
||||
},
|
||||
}))
|
||||
|
||||
const { env } = require("@/env/server")
|
||||
const { getPrefix } = require("./getPrefix")
|
||||
|
||||
const mockedEnv = env as { BRANCH: string; GIT_SHA: string }
|
||||
|
||||
describe("getPrefix", () => {
|
||||
const OLD_ENV = process.env
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.env = OLD_ENV
|
||||
})
|
||||
|
||||
it.each([
|
||||
"prod",
|
||||
"production",
|
||||
"release",
|
||||
"release-v1",
|
||||
"release-v2",
|
||||
"release-v2-alpha",
|
||||
"release-v2.1-alpha",
|
||||
"release-v2.1.2-alpha",
|
||||
])(
|
||||
"should return gitsha for production branches when name is '%s'",
|
||||
(branchName: string) => {
|
||||
mockedEnv.BRANCH = branchName
|
||||
mockedEnv.GIT_SHA = "gitsha"
|
||||
|
||||
const result = getPrefix()
|
||||
|
||||
expect(result).toBe("gitsha")
|
||||
}
|
||||
)
|
||||
|
||||
it.each([
|
||||
"fix/stuff",
|
||||
"feat/my-feature",
|
||||
"feature/my-feature",
|
||||
"releasee",
|
||||
"release-vA",
|
||||
"FEAT",
|
||||
])(
|
||||
"should return branch name and gitsha for non-production branches when name is '%s'",
|
||||
(branchName: string) => {
|
||||
mockedEnv.BRANCH = branchName
|
||||
mockedEnv.GIT_SHA = "gitsha"
|
||||
|
||||
const result = getPrefix()
|
||||
|
||||
expect(result).toBe(`${mockedEnv.BRANCH}:${mockedEnv.GIT_SHA}`)
|
||||
}
|
||||
)
|
||||
|
||||
it("should throw if BRANCH and/or GIT_SHA is not set", () => {
|
||||
mockedEnv.BRANCH = ""
|
||||
mockedEnv.GIT_SHA = ""
|
||||
|
||||
expect(getPrefix).toThrow(
|
||||
"Unable to getPrefix, BRANCH and GIT_SHA must be set"
|
||||
)
|
||||
|
||||
mockedEnv.BRANCH = "hasBranch"
|
||||
mockedEnv.GIT_SHA = ""
|
||||
|
||||
expect(getPrefix).toThrow("Unable to getPrefix, GIT_SHA must be set")
|
||||
|
||||
mockedEnv.BRANCH = ""
|
||||
mockedEnv.GIT_SHA = "hasGitSha"
|
||||
|
||||
expect(getPrefix).toThrow("Unable to getPrefix, BRANCH must be set")
|
||||
})
|
||||
|
||||
it("should return dev or local user if running locally", () => {
|
||||
;(process.env.NODE_ENV as any) = "development"
|
||||
|
||||
process.env.USER = "test_user"
|
||||
process.env.USERNAME = "test_username"
|
||||
|
||||
mockedEnv.BRANCH = ""
|
||||
mockedEnv.GIT_SHA = ""
|
||||
|
||||
expect(getPrefix()).toBe("test_user")
|
||||
|
||||
process.env.USER = ""
|
||||
|
||||
expect(getPrefix()).toBe("test_username")
|
||||
|
||||
process.env.USERNAME = ""
|
||||
expect(getPrefix()).toBe("dev")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import { getBranchPrefix } from "./getBranchPrefix"
|
||||
|
||||
export function getPrefix(): string {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const devPrefix = process.env.USER || process.env.USERNAME || "dev"
|
||||
return `${devPrefix}`
|
||||
}
|
||||
|
||||
const branch = env.BRANCH.trim()
|
||||
const gitSha = env.GIT_SHA?.trim().substring(0, 7)
|
||||
|
||||
if (!branch && !gitSha) {
|
||||
throw new Error("Unable to getPrefix, BRANCH and GIT_SHA must be set")
|
||||
}
|
||||
|
||||
if (!branch) {
|
||||
throw new Error("Unable to getPrefix, BRANCH must be set")
|
||||
}
|
||||
|
||||
if (!gitSha) {
|
||||
throw new Error("Unable to getPrefix, GIT_SHA must be set")
|
||||
}
|
||||
|
||||
const prefixTokens = [getBranchPrefix(branch), gitSha].filter(Boolean)
|
||||
|
||||
return prefixTokens.join(":")
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it, jest } from "@jest/globals"
|
||||
|
||||
jest.mock("./getPrefix", () => ({
|
||||
getPrefix: jest.fn(() => "gitsha"),
|
||||
}))
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
const indexModule: typeof import(".") = require(".")
|
||||
|
||||
const { generateCacheKey } = indexModule
|
||||
|
||||
describe("generateCacheKey", () => {
|
||||
const OLD_ENV = process.env
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.env = OLD_ENV
|
||||
})
|
||||
|
||||
it("generates cachekey with prefix and key using string", () => {
|
||||
expect(generateCacheKey("key1")).toBe("gitsha:key1")
|
||||
})
|
||||
|
||||
it("generates cachekey with prefix and key using array", () => {
|
||||
expect(generateCacheKey(["key1"])).toBe("gitsha:key1")
|
||||
})
|
||||
|
||||
it("generates cachekey with prefix and keys", () => {
|
||||
const actual = generateCacheKey(["key1", "key2"])
|
||||
expect(actual).toBe("gitsha:key1_key2")
|
||||
})
|
||||
|
||||
it("should throw an error if no keys are provided", () => {
|
||||
expect(() => generateCacheKey([])).toThrow("No keys provided")
|
||||
})
|
||||
|
||||
it("should throw an error if only invalid keys are provided", () => {
|
||||
expect(() => generateCacheKey(["", undefined, null] as string[])).toThrow(
|
||||
"No keys provided"
|
||||
)
|
||||
expect(() => generateCacheKey("")).toThrow("No keys provided")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
import { getPrefix } from "./getPrefix"
|
||||
|
||||
export function generateCacheKey(key: string | string[]): string {
|
||||
const keyArray = (Array.isArray(key) ? key : [key]).filter(Boolean)
|
||||
|
||||
if (keyArray.length === 0) {
|
||||
throw new Error("No keys provided")
|
||||
}
|
||||
|
||||
const prefix = getPrefix()
|
||||
|
||||
const keyTokens = [prefix, keyArray.join("_")].filter(Boolean).join(":")
|
||||
|
||||
return keyTokens
|
||||
}
|
||||
Reference in New Issue
Block a user