Skip to content

chore(ci): refine release process #237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/release.config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"releasedTag": "released",
"mainBranch": "main",
"owner": "algolia",
"owner": "eunjae-lee",
"repo": "api-clients-automation",
"targetBranch": {
"javascript": "next",
Expand Down
21 changes: 18 additions & 3 deletions scripts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const DOCKER = Boolean(process.env.DOCKER);
// This script is run by `yarn workspace ...`, which means the current working directory is `./script`
export const ROOT_DIR = path.resolve(process.cwd(), '..');

export const ROOT_ENV_PATH = path.resolve(process.cwd(), '..', '.env');

export const GENERATORS: Record<string, Generator> = {
// Default `algoliasearch` package as it's built similarly to generated clients
'javascript-algoliasearch': {
Expand Down Expand Up @@ -65,7 +67,17 @@ export function splitGeneratorKey(generatorKey: string): Generator {
return { language, client, key: generatorKey };
}

export function getGitHubUrl(lang: string): string {
type GitHubUrl = (
lang: string,
options?: {
token?: string;
}
) => string;

export const getGitHubUrl: GitHubUrl = (
lang: string,
{ token } = {}
): string => {
const entry = Object.entries(openapitools['generator-cli'].generators).find(
(_entry) => _entry[0].startsWith(`${lang}-`)
);
Expand All @@ -74,8 +86,11 @@ export function getGitHubUrl(lang: string): string {
throw new Error(`\`${lang}\` is not found from \`openapitools.json\`.`);
}
const { gitHost, gitRepoId } = entry[1];
return `https://github.com/${gitHost}/${gitRepoId}`;
}

return token
? `https://${token}:${token}@github.com/${gitHost}/${gitRepoId}`
: `https://github.com/${gitHost}/${gitRepoId}`;
};

export function createGeneratorKey({
language,
Expand Down
4 changes: 2 additions & 2 deletions scripts/release/create-release-issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { Octokit } from '@octokit/rest';
import dotenv from 'dotenv';
import semver from 'semver';

import { GENERATORS, LANGUAGES, run } from '../common';
import { GENERATORS, LANGUAGES, ROOT_ENV_PATH, run } from '../common';

import { RELEASED_TAG, MAIN_BRANCH, OWNER, REPO } from './common';
import TEXT from './text';

dotenv.config();
dotenv.config({ path: ROOT_ENV_PATH });

type Version = {
current: string;
Expand Down
77 changes: 44 additions & 33 deletions scripts/release/process-release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@ import dotenv from 'dotenv';
import execa from 'execa';

import openapitools from '../../openapitools.json';
import { toAbsolutePath, run, exists, getGitHubUrl } from '../common';
import {
ROOT_ENV_PATH,
toAbsolutePath,
run,
exists,
getGitHubUrl,
} from '../common';
import { getLanguageFolder } from '../config';

import {
RELEASED_TAG,
OWNER,
REPO,
getMarkdownSection,
getTargetBranch,
getGitAuthor,
getTargetBranch,
} from './common';
import TEXT from './text';

dotenv.config();
dotenv.config({ path: ROOT_ENV_PATH });

if (!process.env.GITHUB_TOKEN) {
throw new Error('Environment variable `GITHUB_TOKEN` does not exist.');
Expand All @@ -42,11 +48,18 @@ type VersionsToRelease = {
[lang: string]: {
current: string;
next: string;
dateStamp: string;
};
};

function getDateStamp(): string {
return new Date().toISOString().split('T')[0];
}

function getVersionsToRelease(issueBody: string): VersionsToRelease {
const versionsToRelease: VersionsToRelease = {};
const dateStamp = getDateStamp();

getMarkdownSection(issueBody, TEXT.versionChangeHeader)
.split('\n')
.forEach((line) => {
Expand All @@ -58,6 +71,7 @@ function getVersionsToRelease(issueBody: string): VersionsToRelease {
versionsToRelease[lang] = {
current,
next,
dateStamp,
};
});

Expand Down Expand Up @@ -129,17 +143,10 @@ async function processRelease(): Promise<void> {

for (const lang of langsToReleaseOrUpdate) {
// prepare the submodule
const clientPath = toAbsolutePath(getLanguageFolder(lang));
const targetBranch = getTargetBranch(lang);
await run(`git checkout ${targetBranch}`, { cwd: clientPath });
await run(`git pull origin ${targetBranch}`, { cwd: clientPath });

console.log(`Generating ${lang} client(s)...`);
console.log(await run(`yarn cli generate ${lang}`));

const dateStamp = new Date().toISOString().split('T')[0];
const currentVersion = versionsToRelease[lang].current;
const nextVersion = versionsToRelease[lang].next;
const { current, next, dateStamp } = versionsToRelease[lang];

// update changelog
const changelogPath = toAbsolutePath(
Expand All @@ -149,9 +156,7 @@ async function processRelease(): Promise<void> {
? (await fsp.readFile(changelogPath)).toString()
: '';
const changelogHeader = willReleaseLibrary(lang)
? `## [v${nextVersion}](${getGitHubUrl(
lang
)}/compare/v${currentVersion}...v${nextVersion})`
? `## [v${next}](${getGitHubUrl(lang)}/compare/v${current}...v${next})`
: `## ${dateStamp}`;
const newChangelog = getMarkdownSection(
getMarkdownSection(issueBody, TEXT.changelogHeader),
Expand All @@ -162,22 +167,7 @@ async function processRelease(): Promise<void> {
[changelogHeader, newChangelog, existingContent].join('\n\n')
);

// commit changelog and the generated client
await configureGitHubAuthor(clientPath);
await run(`git add .`, { cwd: clientPath });
if (willReleaseLibrary(lang)) {
await execa('git', ['commit', '-m', `chore: release ${nextVersion}`], {
cwd: clientPath,
});
await execa('git', ['tag', `v${nextVersion}`], { cwd: clientPath });
} else {
await execa('git', ['commit', '-m', `chore: update repo ${dateStamp}`], {
cwd: clientPath,
});
}

// add the new reference of the submodule in the monorepo
await run(`git add ${getLanguageFolder(lang)}`);
await run(`git add ${changelogPath}`);
}

// We push commits from submodules AFTER all the generations are done.
Expand All @@ -186,14 +176,35 @@ async function processRelease(): Promise<void> {
const clientPath = toAbsolutePath(getLanguageFolder(lang));
const targetBranch = getTargetBranch(lang);

await run(`git push origin ${targetBranch}`, { cwd: clientPath });
const gitHubUrl = getGitHubUrl(lang, { token: process.env.GITHUB_TOKEN });
const tempGitDir = `${process.env.RUNNER_TEMP}/${lang}`;
await run(`rm -rf ${tempGitDir}`);
await run(
`git clone --depth 1 --branch ${targetBranch} ${gitHubUrl} ${tempGitDir}`
);

await run(`cp -r ${clientPath}/ ${tempGitDir}`);
await configureGitHubAuthor(tempGitDir);
await run(`git add .`, { cwd: tempGitDir });

const { next, dateStamp } = versionsToRelease[lang];

if (willReleaseLibrary(lang)) {
await run('git push --tags', { cwd: clientPath });
await execa('git', ['commit', '-m', `chore: release ${next}`], {
cwd: tempGitDir,
});
await execa('git', ['tag', `v${next}`], { cwd: tempGitDir });
await run(`git push --tags`, { cwd: tempGitDir });
} else {
await execa('git', ['commit', '-m', `chore: update repo ${dateStamp}`], {
cwd: tempGitDir,
});
}
await run(`git push`, { cwd: tempGitDir });
}

// Commit and push from the monorepo level.
await execa('git', ['commit', '-m', TEXT.commitMessage]);
await execa('git', ['commit', '-m', `chore: release ${getDateStamp()}`]);
await run(`git push`);

// remove old `released` tag
Expand Down
2 changes: 0 additions & 2 deletions scripts/release/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,4 @@ export default {
`To skip this release, just close the issue.`,
`- [ ] ${APPROVED}`,
].join('\n'),

commitMessage: `chore: update versions and submodules`,
};