Skip to content

Commit

Permalink
feat: allow jigsaw to be called with the build bot token (#6096)
Browse files Browse the repository at this point in the history
* feat: allow jigsaw to be called with the build bot token

* chore: pass ffs to getIntegrations
  • Loading branch information
khendrikse authored Feb 24, 2025
1 parent 58e4537 commit 7a2525f
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 5 deletions.
3 changes: 2 additions & 1 deletion packages/build/src/plugins/child/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getUtils } from './utils.js'

/** Run a specific plugin event handler */
export const run = async function (
{ event, error, constants, envChanges, featureFlags, netlifyConfig, otelCarrier },
{ event, error, constants, envChanges, featureFlags, netlifyConfig, otelCarrier, extensionMetadata },
{ methods, inputs, packageJson, verbose },
) {
setGlobalContext(propagation.extract(context.active(), otelCarrier))
Expand All @@ -31,6 +31,7 @@ export const run = async function (
error,
featureFlags,
systemLog,
extensionMetadata,
}

const envBefore = setEnvChanges(envChanges)
Expand Down
1 change: 1 addition & 0 deletions packages/build/src/steps/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const firePluginStep = async function ({
netlifyConfig,
constants,
otelCarrier,
extensionMetadata,
},
logs: logsA,
verbose,
Expand Down
4 changes: 4 additions & 0 deletions packages/build/src/types/netlify_plugin_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ export interface NetlifyPluginOptions<TInputs extends PluginInputs<StringKeys<TI
utils: NetlifyPluginUtils
featureFlags?: Record<string, unknown>
systemLog?(message: string): void
/**
* When an extension's event handler executes, we pass extension-specific metadata to the exension
*/
extensionMetadata: { extension_token?: string }
}
26 changes: 22 additions & 4 deletions packages/config/src/api/site_info.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NetlifyAPI } from 'netlify'
import fetch from 'node-fetch'
import type { RequestInit } from 'node-fetch'

import { getEnvelope } from '../env/envelope.js'
import { throwUserError } from '../error.js'
Expand All @@ -17,6 +18,7 @@ type GetSiteInfoOpts = {
featureFlags?: Record<string, boolean>
testOpts?: TestOptions
siteFeatureFlagPrefix: string
token: string
}
/**
* Retrieve Netlify Site information, if available.
Expand All @@ -36,6 +38,8 @@ export const getSiteInfo = async function ({
offline = false,
testOpts = {},
siteFeatureFlagPrefix,
token,
featureFlags = {},
}: GetSiteInfoOpts) {
const { env: testEnv = false } = testOpts

Expand All @@ -46,7 +50,9 @@ export const getSiteInfo = async function ({
if (accountId !== undefined) siteInfo.account_id = accountId

const integrations =
mode === 'buildbot' && !offline ? await getIntegrations({ siteId, testOpts, offline, accountId }) : []
mode === 'buildbot' && !offline
? await getIntegrations({ siteId, testOpts, offline, accountId, token, featureFlags })
: []

return { siteInfo, accounts: [], addons: [], integrations }
}
Expand All @@ -55,7 +61,7 @@ export const getSiteInfo = async function ({
getSite(api, siteId, siteFeatureFlagPrefix),
getAccounts(api),
getAddons(api, siteId),
getIntegrations({ siteId, testOpts, offline, accountId }),
getIntegrations({ siteId, testOpts, offline, accountId, token, featureFlags }),
]

const [siteInfo, accounts, addons, integrations] = await Promise.all(promises)
Expand Down Expand Up @@ -109,18 +115,22 @@ type GetIntegrationsOpts = {
accountId?: string
testOpts: TestOptions
offline: boolean
token?: string
featureFlags?: Record<string, boolean>
}

const getIntegrations = async function ({
siteId,
accountId,
testOpts,
offline,
token,
featureFlags,
}: GetIntegrationsOpts): Promise<IntegrationResponse[]> {
if (!siteId || offline) {
return []
}

const sendBuildBotTokenToJigsaw = featureFlags?.send_build_bot_token_to_jigsaw
const { host } = testOpts

const baseUrl = new URL(host ? `http://${host}` : `https://api.netlifysdk.com`)
Expand All @@ -131,7 +141,15 @@ const getIntegrations = async function ({
: `${baseUrl}site/${siteId}/integrations/safe`

try {
const response = await fetch(url)
const requestOptions = {} as RequestInit

if (sendBuildBotTokenToJigsaw && token) {
requestOptions.headers = {
'netlify-sdk-build-bot-token': token,
}
}

const response = await fetch(url, requestOptions)
if (!response.ok) {
throw new Error(`Unexpected status code ${response.status} from fetching extensions`)
}
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const resolveConfig = async function (opts) {
offline,
featureFlags,
testOpts,
token,
})

const { defaultConfig: defaultConfigA, baseRelDir: baseRelDirA } = parseDefaultConfig({
Expand Down
26 changes: 26 additions & 0 deletions packages/config/tests/api/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,32 @@ test('Integrations are returned if accountId is present and mode is dev', async
t.assert(config.integrations[0].has_build === true)
})

test('Integrations are returned and called with a netlify-sdk-build-bot-token', async (t) => {
const { output, requests } = await new Fixture('./fixtures/base')
.withFlags({
siteId: 'test',
mode: 'dev',
token: 'test',
accountId: 'account1',
featureFlags: {
send_build_bot_token_to_jigsaw: true,
},
})
.runConfigServer([SITE_INFO_DATA, TEAM_INSTALLATIONS_META_RESPONSE, FETCH_INTEGRATIONS_EMPTY_RESPONSE])

const config = JSON.parse(output)
const installationsHeaders = requests.find(
(request) => request.url === TEAM_INSTALLATIONS_META_RESPONSE.path,
)?.headers

t.assert(installationsHeaders.includes('netlify-sdk-build-bot-token'))
t.assert(config.integrations)
t.assert(config.integrations.length === 1)
t.assert(config.integrations[0].slug === 'test')
t.assert(config.integrations[0].version === 'so-cool-v2')
t.assert(config.integrations[0].has_build === true)
})

test('Integrations are not returned if failed to fetch integrations', async (t) => {
const { output } = await new Fixture('./fixtures/base')
.withFlags({
Expand Down

0 comments on commit 7a2525f

Please sign in to comment.