Skip to content

Commit 964b0a2

Browse files
authored
fix: only purge alias by default if the purgeCache function is called within a deployed function (#576)
linear ticket: https://linear.app/netlify/issue/RUN-1417/ This patch will ensure that when `purgeCache` is called within a deployed function, the purge will happen for the deployment which contains the function. I.E. If it's the production deployment, it purges production. If it's a branch deployment, it purges the branch. If it's a deploy-preview, it purges the deploy-preview.
1 parent aad5814 commit 964b0a2

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

src/lib/purge_cache.test.ts

+100
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,106 @@ test('Calls the purge API endpoint and returns `undefined` if the operation was
5858
expect(mockAPI.fulfilled).toBeTruthy()
5959
})
6060

61+
test('Does not default the deploy_alias field to process.env.NETLIFY_BRANCH if supplied in the options', async () => {
62+
const mockSiteID = '123456789'
63+
const mockToken = '1q2w3e4r5t6y7u8i9o0p'
64+
65+
process.env.NETLIFY_PURGE_API_TOKEN = mockToken
66+
process.env.SITE_ID = mockSiteID
67+
process.env.NETLIFY_BRANCH = 'main'
68+
69+
const mockAPI = new MockFetch().post({
70+
body: (payload: string) => {
71+
const data = JSON.parse(payload)
72+
73+
expect(data.site_id).toBe(mockSiteID)
74+
expect(data.deploy_alias).toBe('test')
75+
},
76+
headers: { Authorization: `Bearer ${mockToken}` },
77+
method: 'post',
78+
response: new Response(null, { status: 202 }),
79+
url: `https://api.netlify.com/api/v1/purge`,
80+
})
81+
// eslint-disable-next-line unicorn/consistent-function-scoping
82+
const myFunction = async () => {
83+
await purgeCache({ deployAlias: 'test' })
84+
}
85+
86+
globalThis.fetch = mockAPI.fetcher
87+
88+
const response = await invokeLambda(myFunction)
89+
90+
expect(response).toBeUndefined()
91+
expect(mockAPI.fulfilled).toBeTruthy()
92+
})
93+
94+
test('Defaults the deploy_alias field to process.env.NETLIFY_BRANCH if not running locally', async () => {
95+
const mockSiteID = '123456789'
96+
const mockToken = '1q2w3e4r5t6y7u8i9o0p'
97+
98+
process.env.NETLIFY_PURGE_API_TOKEN = mockToken
99+
process.env.SITE_ID = mockSiteID
100+
process.env.NETLIFY_BRANCH = 'main'
101+
102+
const mockAPI = new MockFetch().post({
103+
body: (payload: string) => {
104+
const data = JSON.parse(payload)
105+
106+
expect(data.site_id).toBe(mockSiteID)
107+
expect(data.deploy_alias).toBe(process.env.NETLIFY_BRANCH)
108+
},
109+
headers: { Authorization: `Bearer ${mockToken}` },
110+
method: 'post',
111+
response: new Response(null, { status: 202 }),
112+
url: `https://api.netlify.com/api/v1/purge`,
113+
})
114+
// eslint-disable-next-line unicorn/consistent-function-scoping
115+
const myFunction = async () => {
116+
await purgeCache()
117+
}
118+
119+
globalThis.fetch = mockAPI.fetcher
120+
121+
const response = await invokeLambda(myFunction)
122+
123+
expect(response).toBeUndefined()
124+
expect(mockAPI.fulfilled).toBeTruthy()
125+
})
126+
127+
test('Does not default the deploy_alias field to process.env.NETLIFY_BRANCH when running locally', async () => {
128+
const mockSiteID = '123456789'
129+
const mockToken = '1q2w3e4r5t6y7u8i9o0p'
130+
131+
process.env.NETLIFY_PURGE_API_TOKEN = mockToken
132+
process.env.SITE_ID = mockSiteID
133+
process.env.NETLIFY_LOCAL = 'true'
134+
process.env.NETLIFY_BRANCH = 'main'
135+
136+
const mockAPI = new MockFetch().post({
137+
body: (payload: string) => {
138+
const data = JSON.parse(payload)
139+
140+
expect(data.site_id).toBe(mockSiteID)
141+
expect(data.deploy_alias).toBeUndefined()
142+
},
143+
headers: { Authorization: `Bearer ${mockToken}` },
144+
method: 'post',
145+
response: new Response(null, { status: 202 }),
146+
url: `https://api.netlify.com/api/v1/purge`,
147+
})
148+
// eslint-disable-next-line unicorn/consistent-function-scoping
149+
const myFunction = async () => {
150+
await purgeCache()
151+
}
152+
153+
globalThis.fetch = mockAPI.fetcher
154+
155+
const response = await invokeLambda(myFunction)
156+
157+
expect(response).toBeUndefined()
158+
expect(mockAPI.fulfilled).toBeTruthy()
159+
})
160+
61161
test('Throws an error if the API response does not have a successful status code, using the response body as part of the error message', async () => {
62162
if (!hasFetchAPI) {
63163
console.warn('Skipping test requires the fetch API')

src/lib/purge_cache.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,14 @@ export const purgeCache = async (options: PurgeCacheOptions = {}) => {
4848

4949
const payload: PurgeAPIPayload = {
5050
cache_tags: options.tags,
51-
deploy_alias: options.deployAlias,
5251
}
52+
53+
if ('deployAlias' in options) {
54+
payload.deploy_alias = options.deployAlias
55+
} else if (!env.NETLIFY_LOCAL) {
56+
payload.deploy_alias = env.NETLIFY_BRANCH
57+
}
58+
5359
const token = env.NETLIFY_PURGE_API_TOKEN || options.token
5460

5561
if (env.NETLIFY_LOCAL && !token) {

0 commit comments

Comments
 (0)