Skip to content

Commit

Permalink
Merge pull request #683 from Financial-Times/clean-out
Browse files Browse the repository at this point in the history
Remove deprecated plugins and code before major release
  • Loading branch information
ivomurrell committed Sep 5, 2024
2 parents 86469ba + dc008ff commit 00a7d4f
Show file tree
Hide file tree
Showing 57 changed files with 89 additions and 3,169 deletions.
6 changes: 2 additions & 4 deletions core/cli/test/files/conflict-resolution/.toolkitrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ options:
plugins:
'@dotcom-tool-kit/heroku':
pipeline: tool-kit-test
systemCode: tool-kit-test
'@dotcom-tool-kit/vault':
team: platforms
app: tool-kit-test
'@dotcom-tool-kit/doppler':
project: tool-kit-test
tasks:
HerokuProduction:
scaling:
Expand Down
6 changes: 2 additions & 4 deletions core/cli/test/files/duplicate/.toolkitrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ options:
plugins:
'@dotcom-tool-kit/heroku':
pipeline: tool-kit-test
systemCode: tool-kit-test

'@dotcom-tool-kit/vault':
team: platforms
app: tool-kit-test
'@dotcom-tool-kit/doppler':
project: tool-kit-test
tasks:
HerokuProduction:
scaling:
Expand Down
14 changes: 5 additions & 9 deletions core/create/src/prompts/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,10 @@ export default async function oidcPrompt({ toolKitConfig }: OidcParams): Promise
cloudformationTemplate.setIn(policyPath, cloudformationTemplate.createNode(previousDocument))

// HACK:20240213:IM Guess Doppler project name to use in Parameter
// store path using the same logic we use to infer the name from Tool
// Kit vault plugin options. The class tries to read the options from
// the global options object so let's set these options based on what's
// been selected during the options prompt.
setOptions('@dotcom-tool-kit/vault', toolKitConfig.options.plugins['@dotcom-tool-kit/vault'])
// store path using the same logic we used to use to infer the name
// from Tool Kit vault plugin options. The class tries to read the
// options from the global options object so let's set these options
// based on what's been selected during the options prompt.
setOptions('@dotcom-tool-kit/doppler', toolKitConfig.options.plugins['@dotcom-tool-kit/doppler'])
const dopplerProjectName = new DopplerEnvVars(winstonLogger, 'prod').options.project
const ssmAction = 'ssm:GetParameter'
Expand Down Expand Up @@ -304,10 +303,7 @@ export default async function oidcPrompt({ toolKitConfig }: OidcParams): Promise

let githubUsername
try {
// We've already grabbed access tokens via the Doppler library, so we know
// that the Doppler credentials are stored in an environment variable, which
// we can use to get the current user's login ID.
const octokit = new Octokit({ auth: `token ${process.env.VAULT_AUTH_GITHUB_TOKEN}` })
const octokit = new Octokit({ auth: `token ${dopplerEnv.GITHUB_ACCESS_TOKEN}` })
const resp = await octokit.rest.users.getAuthenticated()
githubUsername = resp.data.login
} catch (err) {
Expand Down
3 changes: 0 additions & 3 deletions lib/doppler/.toolkitrc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
plugins:
- '@dotcom-tool-kit/vault'

version: 2
1 change: 0 additions & 1 deletion lib/doppler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"@dotcom-tool-kit/error": "^3.2.0",
"@dotcom-tool-kit/logger": "^3.4.1",
"@dotcom-tool-kit/options": "^3.2.1",
"@dotcom-tool-kit/vault": "^3.2.1",
"tslib": "^2.3.1"
},
"keywords": [],
Expand Down
81 changes: 4 additions & 77 deletions lib/doppler/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,22 @@
import { spawn } from 'node:child_process'
import fs from 'node:fs'

import type { Logger } from 'winston'

import { ToolKitError } from '@dotcom-tool-kit/error'
import { styles, waitOnExit } from '@dotcom-tool-kit/logger'
import { getOptions } from '@dotcom-tool-kit/options'
import * as Vault from '@dotcom-tool-kit/vault'
import type { DopplerOptions as ConfiguredDopplerOptions } from '@dotcom-tool-kit/schemas/lib/plugins/doppler'

export type Environment = 'prod' | 'ci' | 'dev'

type DopplerOptions = Required<ConfiguredDopplerOptions>
export type DopplerSecrets = Record<string, string>
export type Source = 'doppler' | 'vault'
export interface SecretsWithSource {
secrets: DopplerSecrets
source: Source
}

const dopplerEnvToVaultMap: Record<Environment, Vault.Environment> = {
prod: 'production',
ci: 'continuous-integration',
dev: 'development'
}

let hasLoggedMigrationWarning = false

export class DopplerEnvVars {
options: DopplerOptions

constructor(private logger: Logger, public environment: Environment, options?: DopplerOptions) {
let dopplerOptions = options ?? getOptions('@dotcom-tool-kit/doppler')
if (!(dopplerOptions && dopplerOptions.project)) {
// HACK:20230829:IM check the project passed to the Vault options too so
// that projects don't have to make any changes to their Tool Kit config
const projectName = getOptions('@dotcom-tool-kit/vault')?.app
// HACK:20231020:IM Projects without an associated biz ops system require
// a repo_ prefix in their name. We don't have a biz ops key (yet) so
// let's just try and infer whether it deploys anything based on the
// existence of config files. This won't always be correct and in those
// cases users should set a @dotcom-tool-kit/doppler option.
const isRepo = !(
fs.existsSync('Procfile') ||
fs.existsSync('serverless.yml') ||
fs.existsSync('serverless.yaml')
)
const project = isRepo ? `repo_${projectName}` : projectName
logger.warn(
`Doppler options not found so falling back to Vault options (guessing Doppler project is named ${project})`
)
dopplerOptions = { project }
}
const dopplerOptions = options ?? getOptions('@dotcom-tool-kit/doppler')
if (!(dopplerOptions && dopplerOptions.project)) {
const error = new ToolKitError('Doppler options not found in your Tool Kit configuration')
error.details = `"project" is needed to get your app's secrets from doppler, e.g.
Expand Down Expand Up @@ -102,18 +67,7 @@ export class DopplerEnvVars {
}

async get(): Promise<DopplerSecrets> {
const { secrets } = await this.getWithSource()
return secrets
}

// TODO:20221023:IM remove this function once we drop Vault support and keep
// logic in get() instead
async getWithSource(): Promise<SecretsWithSource> {
// don't fallback to Vault if the project has doppler options set up
// explicitly already
const migratedToolKitToDoppler = Boolean(getOptions('@dotcom-tool-kit/doppler')?.project)

if (migratedToolKitToDoppler && process.env.CIRCLECI) {
if (process.env.CIRCLECI && process.env.NODE_ENV !== 'test') {
const error = new ToolKitError('Doppler options cannot be dynamically accessed within CircleCI')
error.details =
this.environment === 'ci'
Expand All @@ -123,36 +77,9 @@ export class DopplerEnvVars {
}

const secrets = await this.invokeCLI()
if (secrets) {
return { secrets, source: 'doppler' }
}
if (migratedToolKitToDoppler) {
if (!secrets) {
throw new ToolKitError('failed to get secrets from Doppler')
}

// fall back to Vault
if (!hasLoggedMigrationWarning) {
// TODO:20230919:IM enable this logging message once we're ready to shuffle people over to Doppler
// this.logger.warn(
// `getting Doppler secrets failed so falling back to the ${styles.warningHighlight(
// 'DEPRECATED'
// )} Vault secrets manager. please consider migrating to/fixing issues with Doppler.`
// )
this.logger.warn('falling back to Vault')
hasLoggedMigrationWarning = true
}

return { secrets: await this.fallbackToVault(), source: 'vault' }
}

// HACK:20221024:IM This function is here just to enable projects that have
// migrated to Doppler to use the logic in this class that converts between
// Doppler and Vault project names. We should remove this function once we
// drop Vault support.
fallbackToVault(): Promise<DopplerSecrets> {
const vault = new Vault.VaultEnvVars(this.logger, {
environment: dopplerEnvToVaultMap[this.environment]
})
return vault.get()
return secrets
}
}
27 changes: 11 additions & 16 deletions lib/doppler/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import spawk from 'spawk'
import winston, { Logger } from 'winston'
import { VaultEnvVars } from '@dotcom-tool-kit/vault'
import { ToolKitError } from '@dotcom-tool-kit/error'
import { DopplerEnvVars } from '../src/index'

const logger = (winston as unknown) as Logger
const logger = winston as unknown as Logger

jest.mock('@dotcom-tool-kit/vault')
const mockedVaultEnvVars = jest.mocked(VaultEnvVars)
spawk.preventUnmatched()

const environment = 'dev'
Expand All @@ -29,33 +27,30 @@ describe(`Doppler CLI invocations`, () => {
spawk.done()
})

it("should fall back to Vault when Doppler isn't installed", async () => {
it("should throw an error when Doppler isn't installed", async () => {
expect.assertions(1)
const interceptor = spawk.spawn('doppler', expectedArgs)
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
* spawk type definitions are out of date
**/
;(interceptor as any).spawnError('ENOENT')
const env = await doppler.get()
expect(env).toBeUndefined()
expect(mockedVaultEnvVars.mock.instances[0].get).toHaveBeenCalled()
await expect(doppler.get()).rejects.toThrow(ToolKitError)
spawk.done()
})

it('should fall back to Vault when Doppler prints an error', async () => {
it('should throw an error when Doppler prints an error', async () => {
expect.assertions(1)
const interceptor = spawk.spawn('doppler', expectedArgs)
interceptor.stderr('doppler had an issue')
const env = await doppler.get()
expect(env).toBeUndefined()
expect(mockedVaultEnvVars.mock.instances[0].get).toHaveBeenCalled()
await expect(doppler.get()).rejects.toThrow(ToolKitError)
spawk.done()
})

it('should fall back to Vault when the JSON is unparseable', async () => {
it('should throw an error when the JSON is unparseable', async () => {
expect.assertions(1)
const interceptor = spawk.spawn('doppler', expectedArgs)
interceptor.stdout(JSON.stringify(testEnvironment).slice(0, 20))
const env = await doppler.get()
expect(env).toBeUndefined()
expect(mockedVaultEnvVars.mock.instances[0].get).toHaveBeenCalled()
await expect(doppler.get()).rejects.toThrow(ToolKitError)
spawk.done()
})
})
3 changes: 0 additions & 3 deletions lib/doppler/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
{
"path": "../options"
},
{
"path": "../vault"
},
{
"path": "../schemas"
}
Expand Down
5 changes: 1 addition & 4 deletions lib/schemas/src/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { HerokuSchema } from './plugins/heroku'
import { LintStagedNpmSchema } from './plugins/lint-staged-npm'
import { NextRouterSchema } from './plugins/next-router'
import { ServerlessSchema } from './plugins/serverless'
import { VaultSchema } from './plugins/vault'
import { type InferSchemaOptions } from './infer'

// TODO:KB:20240412 remove legacyPluginOptions in a future major version
Expand All @@ -20,7 +19,6 @@ export const legacyPluginOptions: Record<string, string> = {
'@dotcom-tool-kit/n-test': 'NTest',
'@dotcom-tool-kit/node': 'Node',
'@dotcom-tool-kit/nodemon': 'Nodemon',
'@dotcom-tool-kit/pa11y': 'Pa11y',
'@dotcom-tool-kit/prettier': 'Prettier',
'@dotcom-tool-kit/typescript': 'TypeScript',
'@dotcom-tool-kit/upload-assets-to-s3': 'UploadAssetsToS3',
Expand All @@ -34,8 +32,7 @@ export const PluginSchemas = {
'@dotcom-tool-kit/heroku': HerokuSchema,
'@dotcom-tool-kit/lint-staged-npm': LintStagedNpmSchema,
'@dotcom-tool-kit/next-router': NextRouterSchema,
'@dotcom-tool-kit/serverless': ServerlessSchema,
'@dotcom-tool-kit/vault': VaultSchema
'@dotcom-tool-kit/serverless': ServerlessSchema
}

export type PluginOptions = InferSchemaOptions<typeof PluginSchemas>
8 changes: 1 addition & 7 deletions lib/schemas/src/plugins/heroku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ export const HerokuSchema = z.object({
.string()
.describe(
"the ID of your app's Heroku pipeline. this can be found at https://dashboard.heroku.com/pipelines/[PIPELINE_ID]"
),
systemCode: z
.string()
.describe(
"your app's Biz Ops system code. this can be found at https://biz-ops.in.ft.com/System/[SYSTEM_CODE]"
)
})

export type HerokuOptions = z.infer<typeof HerokuSchema>

export const Schema = HerokuSchema
export const generators: PromptGenerators<typeof HerokuSchema> = {
pipeline: async (logger, prompt, onCancel, bizOpsSystem) => bizOpsSystem?.herokuApps[0]?.pipelineName,
systemCode: async (logger, prompt, onCancel, bizOpsSystem) => bizOpsSystem?.code
pipeline: async (logger, prompt, onCancel, bizOpsSystem) => bizOpsSystem?.herokuApps[0]?.pipelineName
}
15 changes: 0 additions & 15 deletions lib/schemas/src/plugins/vault.ts

This file was deleted.

3 changes: 1 addition & 2 deletions lib/schemas/src/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export type SchemaPromptGenerator<T> = (
logger: Logger,
prompt: typeof prompts,
onCancel: () => void,
// HACK:20231209:IM add bizOpsSystem as optional parameter to maintain
// backwards compatibility
// bizOpsSystem will be undefined if project is not a system
bizOpsSystem?: BizOpsSystem
) => Promise<T | undefined>
// This type defines an interface you can use to export prompt generators. The
Expand Down
2 changes: 0 additions & 2 deletions lib/schemas/src/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { JestSchema } from './tasks/jest'
import { MochaSchema } from './tasks/mocha'
import { NodeSchema } from './tasks/node'
import { NodemonSchema } from './tasks/nodemon'
import { Pa11ySchema } from './tasks/pa11y'
import { PrettierSchema } from './tasks/prettier'
import { TypeScriptSchema } from './tasks/typescript'
import { UploadAssetsToS3Schema } from './tasks/upload-assets-to-s3'
Expand All @@ -32,7 +31,6 @@ export const TaskSchemas = {
NpmPrune: z.object({}).describe('Prune development npm dependencies.'),
NpmPublish: z.object({}).describe('Publish package to the npm registry.'),
NTest: SmokeTestSchema,
Pa11y: Pa11ySchema,
Prettier: PrettierSchema,
ServerlessDeploy: z.object({}).describe('Deploy a serverless function'),
ServerlessProvision: z.object({}).describe('Provision a review serverless function'),
Expand Down
11 changes: 0 additions & 11 deletions lib/schemas/src/tasks/pa11y.ts

This file was deleted.

2 changes: 0 additions & 2 deletions lib/vault/.toolkitrc.yml

This file was deleted.

Loading

0 comments on commit 00a7d4f

Please sign in to comment.