From 3a90bbce9f0c9187cd1d65937c3c3426e2c9068f Mon Sep 17 00:00:00 2001 From: Robert Lin Date: Sat, 12 Dec 2020 21:03:19 +0800 Subject: [PATCH 1/2] dev(release): improve caching behaviour for version confirmation --- dev/release/src/campaigns.ts | 4 ++-- dev/release/src/config.ts | 31 +++++++++++++++++++----------- dev/release/src/github.ts | 4 ++-- dev/release/src/google-calendar.ts | 6 +++--- dev/release/src/release.ts | 17 ++++++++++++---- dev/release/src/slack.ts | 4 ++-- dev/release/src/util.ts | 2 ++ 7 files changed, 44 insertions(+), 24 deletions(-) diff --git a/dev/release/src/campaigns.ts b/dev/release/src/campaigns.ts index 81d03376ed2f..438aa65a625d 100644 --- a/dev/release/src/campaigns.ts +++ b/dev/release/src/campaigns.ts @@ -1,5 +1,5 @@ import { CreatedChangeset } from './github' -import { readLine } from './util' +import { readLine, cacheFolder } from './util' import YAML from 'yaml' import execa from 'execa' import fetch from 'node-fetch' @@ -21,7 +21,7 @@ export async function sourcegraphCLIConfig(): Promise { await commandExists('src') // CLI must be present for campaigns interactions return { SRC_ENDPOINT: DEFAULT_SRC_ENDPOINT, - SRC_ACCESS_TOKEN: await readLine('k8s.sgdev.org src-cli token: ', '.secrets/src-cli.txt'), + SRC_ACCESS_TOKEN: await readLine('k8s.sgdev.org src-cli token: ', `${cacheFolder}/src-cli.txt`), } } diff --git a/dev/release/src/config.ts b/dev/release/src/config.ts index 15be535d8cd9..b976fa96234d 100644 --- a/dev/release/src/config.ts +++ b/dev/release/src/config.ts @@ -1,6 +1,6 @@ -import { readLine, getWeekNumber } from './util' +import { cacheFolder, readLine, getWeekNumber } from './util' import * as semver from 'semver' -import { readFileSync } from 'fs' +import { readFileSync, unlinkSync } from 'fs' import { parse as parseJSONC } from '@sqs/jsonc-parser' /** @@ -29,11 +29,16 @@ export interface Config { } } +/** + * Default path of JSONC containing release configuration. + */ +const configPath = 'release-config.jsonc' + /** * Loads configuration from predefined path. It does not do any special validation. */ export function loadConfig(): Config { - return parseJSONC(readFileSync('release-config.jsonc').toString()) as Config + return parseJSONC(readFileSync(configPath).toString()) as Config } /** @@ -60,19 +65,23 @@ export async function releaseVersions( // Verify the configured upcoming release. The response is cached and expires in a // week, after which the captain is required to confirm again. const now = new Date() - const cachedVersion = `.secrets/current_release_${now.getUTCFullYear()}_${getWeekNumber(now)}.txt` + const cachedVersionResponse = `${cacheFolder}/current_release_${now.getUTCFullYear()}_${getWeekNumber(now)}.txt` const confirmVersion = await readLine( - `Please confirm the upcoming release version (configured: '${config.upcomingRelease}'): `, - cachedVersion + `Please confirm the upcoming release version configured in '${configPath}' (currently '${config.upcomingRelease}'): `, + cachedVersionResponse ) const parsedConfirmed = semver.parse(confirmVersion, parseOptions) + let error = '' if (!parsedConfirmed) { - throw new Error(`Provided version '${confirmVersion}' is not valid semver (in ${cachedVersion})`) + error = `Provided version '${confirmVersion}' is not valid semver` + } else if (semver.neq(parsedConfirmed, parsedUpcoming)) { + error = `Provided version '${confirmVersion}' and config.upcomingRelease '${config.upcomingRelease}' to not match - please update the release configuration at '${configPath}' and try again` } - if (semver.neq(parsedConfirmed, parsedUpcoming)) { - throw new Error( - `Provided version '${confirmVersion}' and config.upcomingRelease '${config.upcomingRelease}' to not match - please update the release configuration, or confirm the version in your cached answer (in ${cachedVersion})` - ) + + // If error, abort and remove the cached response (since it is invalid anyway) + if (error !== '') { + unlinkSync(cachedVersionResponse) + throw new Error(error) } const versions = { diff --git a/dev/release/src/github.ts b/dev/release/src/github.ts index bd8ee33df9ce..495934e0154b 100644 --- a/dev/release/src/github.ts +++ b/dev/release/src/github.ts @@ -1,5 +1,5 @@ import Octokit from '@octokit/rest' -import { readLine, formatDate, timezoneLink } from './util' +import { readLine, formatDate, timezoneLink, cacheFolder } from './util' import { promisify } from 'util' import * as semver from 'semver' import { mkdtemp as original_mkdtemp } from 'fs' @@ -12,7 +12,7 @@ const mkdtemp = promisify(original_mkdtemp) export async function getAuthenticatedGitHubClient(): Promise { const githubPAT = await readLine( 'Enter a GitHub personal access token with "repo" scope (https://github.com/settings/tokens/new): ', - '.secrets/github.txt' + `${cacheFolder}/github.txt` ) const trimmedGithubPAT = githubPAT.trim() return new Octokit({ auth: trimmedGithubPAT }) diff --git a/dev/release/src/google-calendar.ts b/dev/release/src/google-calendar.ts index a081d56df914..312a90c2995c 100644 --- a/dev/release/src/google-calendar.ts +++ b/dev/release/src/google-calendar.ts @@ -2,17 +2,17 @@ import { google, calendar_v3 } from 'googleapis' import { OAuth2Client } from 'googleapis-common' import open from 'open' import { Credentials } from 'google-auth-library' -import { readLine } from './util' +import { readLine, cacheFolder } from './util' import { readFile, writeFile } from 'mz/fs' const SCOPES = ['https://www.googleapis.com/auth/calendar.events'] -const TOKEN_PATH = '.secrets/google-calendar-token.json' +const TOKEN_PATH = `${cacheFolder}/google-calendar-token.json` export async function getClient(): Promise { const credentials = JSON.parse( await readLine( 'Paste Google Calendar credentials (1Password "Release automation Google Calendar API App credentials"): ', - '.secrets/google-calendar-credentials.json' + `${cacheFolder}/google-calendar-credentials.json` ) ) const { client_secret, client_id, redirect_uris } = credentials.installed diff --git a/dev/release/src/release.ts b/dev/release/src/release.ts index c142c72aa97b..5110d5ef3a76 100644 --- a/dev/release/src/release.ts +++ b/dev/release/src/release.ts @@ -13,9 +13,9 @@ import { import * as changelog from './changelog' import * as campaigns from './campaigns' import { Config, releaseVersions } from './config' -import { formatDate, timezoneLink } from './util' +import { cacheFolder, formatDate, timezoneLink } from './util' import { addMinutes, isWeekend, eachDayOfInterval, addDays, subDays } from 'date-fns' -import { readFileSync, writeFileSync } from 'fs' +import { readFileSync, rmdirSync, writeFileSync } from 'fs' import * as path from 'path' import commandExists from 'command-exists' @@ -36,6 +36,8 @@ export type StepID = | 'release:add-to-campaign' | 'release:finalize' | 'release:close' + // util + | 'util:clear-cache' // testing | '_test:google-calendar' | '_test:slack' @@ -258,7 +260,7 @@ If you have changes that should go into this patch release, <${patchRequestTempl owner: 'sourcegraph', repo: 'sourcegraph', base: 'main', - head: `publish-${release.version}`, + head: `changelog-${release.version}`, title: prMessage, commitMessage: prMessage, edits: [ @@ -281,7 +283,7 @@ If you have changes that should go into this patch release, <${patchRequestTempl // Update changelog writeFileSync(changelogPath, changelogContents) }, - ], // Changes already done + ], }, ], dryRun: config.dryRun.changesets, @@ -612,6 +614,13 @@ Campaign: ${campaignURL}`, } }, }, + { + id: 'util:clear-cache', + description: 'Clear release tool cache', + run: () => { + rmdirSync(cacheFolder, { recursive: true }) + }, + }, { id: '_test:google-calendar', description: 'Test Google Calendar integration', diff --git a/dev/release/src/slack.ts b/dev/release/src/slack.ts index 83ff51c7ff77..52e20030c708 100644 --- a/dev/release/src/slack.ts +++ b/dev/release/src/slack.ts @@ -1,10 +1,10 @@ import got from 'got' -import { readLine } from './util' +import { readLine, cacheFolder } from './util' export async function postMessage(message: string, channel: string): Promise { const webhookURL = await readLine( `Enter the Slack webhook URL corresponding to the #${channel} channel (https://api.slack.com/apps/APULW2LKS/incoming-webhooks?): `, - `.secrets/slackWebhookURL-${channel}.txt` + `${cacheFolder}/slackWebhookURL-${channel}.txt` ) await got.post(webhookURL, { body: JSON.stringify({ text: message, link_names: true }), diff --git a/dev/release/src/util.ts b/dev/release/src/util.ts index 1817d315af9e..8912d2daa9c8 100644 --- a/dev/release/src/util.ts +++ b/dev/release/src/util.ts @@ -24,6 +24,8 @@ export function timezoneLink(date: Date, linkName: string): string { })}_${date.getUTCFullYear()}_in_UTC?${encodeURI(linkName)}` } +export const cacheFolder = './.secrets' + export async function readLine(prompt: string, cacheFile?: string): Promise { if (!cacheFile) { return readLineNoCache(prompt) From 554cf3b41fd387d4a3de7f96b95f58fe96914a73 Mon Sep 17 00:00:00 2001 From: Robert Lin Date: Tue, 15 Dec 2020 08:17:55 +0800 Subject: [PATCH 2/2] Update dev/release/src/config.ts Co-authored-by: Gonzalo Peci --- dev/release/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/release/src/config.ts b/dev/release/src/config.ts index b976fa96234d..2dd803c7aa87 100644 --- a/dev/release/src/config.ts +++ b/dev/release/src/config.ts @@ -75,7 +75,7 @@ export async function releaseVersions( if (!parsedConfirmed) { error = `Provided version '${confirmVersion}' is not valid semver` } else if (semver.neq(parsedConfirmed, parsedUpcoming)) { - error = `Provided version '${confirmVersion}' and config.upcomingRelease '${config.upcomingRelease}' to not match - please update the release configuration at '${configPath}' and try again` + error = `Provided version '${confirmVersion}' and config.upcomingRelease '${config.upcomingRelease}' do not match - please update the release configuration at '${configPath}' and try again` } // If error, abort and remove the cached response (since it is invalid anyway)