Skip to content

Commit 1619c5d

Browse files
committed
add homebrew publish to build/publish
1 parent d389fb4 commit 1619c5d

File tree

9 files changed

+145
-41
lines changed

9 files changed

+145
-41
lines changed

packages/build/src/github-repo.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ export class GithubRepo {
111111
.catch(this._ignoreAlreadyExistsError);
112112
}
113113

114-
// Creates release notes and uploads assets if they are not yet uploaded to
115-
// Github.
114+
/**
115+
* Creates release notes and uploads assets if they are not yet uploaded to Github.
116+
*/
116117
async releaseToGithub(artifact: TarballFile, config: Config): Promise<void> {
117118
const tag = `v${config.version}`;
118119

@@ -204,6 +205,27 @@ export class GithubRepo {
204205
return `https://jira.mongodb.org/issues/?jql=project%20%3D%20MONGOSH%20AND%20fixVersion%20%3D%20${version}`;
205206
}
206207

208+
async createPullRequest(title: string, fromBranch: string, toBaseBranch: string): Promise<{prNumber: number, url: string}> {
209+
const response = await this.octokit.pulls.create({
210+
...this.repo,
211+
base: toBaseBranch,
212+
head: fromBranch,
213+
title
214+
});
215+
216+
return {
217+
prNumber: response.data.number,
218+
url: response.data.html_url
219+
};
220+
}
221+
222+
async mergePullRequest(prNumber: number): Promise<void> {
223+
await this.octokit.pulls.merge({
224+
...this.repo,
225+
pull_number: prNumber
226+
});
227+
}
228+
207229
private _ignoreAlreadyExistsError(): (error: any) => Promise<void> {
208230
return (error: any): Promise<void> => {
209231
if (this._isAlreadyExistsError(error)) {

packages/build/src/homebrew/generate-formula.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
1-
import { httpsSha256 } from './utils';
21

3-
export async function generateHomebrewFormula(version: string): Promise<string> {
4-
const url = `https://registry.npmjs.org/@mongosh/cli-repl/-/cli-repl-${version}.tgz`;
5-
const sha = await httpsSha256(url);
6-
return renderFormula({ version, sha });
7-
}
8-
9-
function renderFormula(context: { version: string, sha: string }): string {
2+
export function generateFormula(context: { version: string, sha: string }): string {
103
return `require "language/node"
114
125
class Mongosh < Formula

packages/build/src/homebrew/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
export * from './publish-to-homebrew';
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { GithubRepo } from '../github-repo';
2+
import { generateFormula } from './generate-formula';
3+
import { updateMongoDBTap } from './update-mongodb-tap';
4+
import { httpsSha256 } from './utils';
5+
6+
const MONGO_HOMEBREW_REPO_URL = '[email protected]:mongodb/homebrew-brew.git';
7+
8+
export async function publishToHomebrew(tmpDir: string, mongoHomebrewRepo: GithubRepo, packageVersion: string): Promise<void> {
9+
const cliReplPackageUrl = `https://registry.npmjs.org/@mongosh/cli-repl/-/cli-repl-${packageVersion}.tgz`;
10+
const packageSha = await httpsSha256(cliReplPackageUrl);
11+
12+
const homebrewFormula = generateFormula({ version: packageVersion, sha: packageSha });
13+
const tapBranch = await updateMongoDBTap({
14+
tmpDir, packageVersion, packageSha, homebrewFormula,
15+
mongoHomebrewRepoUrl: MONGO_HOMEBREW_REPO_URL
16+
});
17+
18+
if (!tapBranch) {
19+
console.warn('There are no changes to the homebrew formula');
20+
return;
21+
}
22+
23+
const pr = await mongoHomebrewRepo.createPullRequest(`mongosh ${packageVersion}`, tapBranch, 'master');
24+
console.info(`Created PR #${pr.prNumber} in mongodb/homebrew-brew: ${pr.url}`);
25+
await mongoHomebrewRepo.mergePullRequest(pr.prNumber);
26+
console.info('-> Merged, homebrew formula is released');
27+
}

packages/build/src/homebrew/update-mongodb-tap.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('Homebrew update-mongodb-tap', () => {
3030
homebrewFormula: 'updated formula',
3131
mongoHomebrewRepoUrl: `file://${repoDir.path}`
3232
});
33-
expect(updated).to.equal(true);
33+
expect(updated).to.equal('mongosh-1.0.0-sha');
3434

3535
execSync('git checkout mongosh-1.0.0-sha', { cwd: repoDir.path });
3636
expect(readFileSync(mongoshFormulaFile, 'utf-8')).to.equal('updated formula');
@@ -44,7 +44,7 @@ describe('Homebrew update-mongodb-tap', () => {
4444
homebrewFormula: 'formula',
4545
mongoHomebrewRepoUrl: `file://${repoDir.path}`
4646
});
47-
expect(updated).to.equal(false);
47+
expect(updated).to.equal(undefined);
4848

4949
const branches = execSync('git branch -a', { cwd: repoDir.path }).toString().trim();
5050
expect(branches).to.equal('* master');

packages/build/src/homebrew/update-mongodb-tap.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ export interface UpdateMongoDBTapParameters {
99
packageSha: string;
1010
homebrewFormula: string;
1111
tmpDir: string;
12-
mongoHomebrewRepoUrl?: string;
12+
mongoHomebrewRepoUrl: string;
1313
}
1414

15-
export async function updateMongoDBTap(params: UpdateMongoDBTapParameters): Promise<boolean> {
16-
const repoUrl = params.mongoHomebrewRepoUrl || '[email protected]:mongodb/homebrew-brew.git';
15+
/**
16+
* Updates the mongosh formula in the given homebrew tap repository and returns the
17+
* name of the branch pushed to the repository.
18+
*/
19+
export async function updateMongoDBTap(params: UpdateMongoDBTapParameters): Promise<string | undefined> {
20+
const repoUrl = params.mongoHomebrewRepoUrl;
1721
const cloneDir = path.resolve(params.tmpDir, 'homebrew-brew');
1822
cloneRepository(cloneDir, repoUrl);
1923

@@ -24,14 +28,13 @@ export async function updateMongoDBTap(params: UpdateMongoDBTapParameters): Prom
2428

2529
const currentContent = await fs.readFile(formulaPath, 'utf-8');
2630
if (currentContent === params.homebrewFormula) {
27-
console.warn('There are no changes to the homebrew formula');
28-
return false;
31+
return undefined;
2932
}
3033

3134
await fs.writeFile( formulaPath, params.homebrewFormula, 'utf-8');
3235

3336
execSync('git add .', { cwd: cloneDir, stdio: 'inherit' });
3437
execSync(`git commit -m "mongosh ${version}"`, { cwd: cloneDir, stdio: 'inherit' });
3538
execSync(`git push origin ${branchName}`, { cwd: cloneDir, stdio: 'inherit' });
36-
return true;
39+
return branchName;
3740
}

packages/build/src/publish.spec.ts

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { GithubRepo } from './github-repo';
2-
import publish from './publish';
31
import chai, { expect } from 'chai';
4-
import Config from './config';
52
import path from 'path';
63
import sinon from 'ts-sinon';
4+
import Config from './config';
5+
import { GithubRepo } from './github-repo';
6+
import type { publishToHomebrew as publishToHomebrewType } from './homebrew';
7+
import publish from './publish';
78

89
chai.use(require('sinon-chai'));
910

@@ -14,7 +15,9 @@ function createStubRepo(overrides?: any): GithubRepo {
1415
describe('publish', () => {
1516
let config: Config;
1617
let uploadDownloadCenterConfig: (version: string, awsKey: string, awsSecret: string) => Promise<any>;
18+
let publishToHomebrew: typeof publishToHomebrewType;
1719
let githubRepo: GithubRepo;
20+
let mongoHomebrewRepo: GithubRepo;
1821

1922
beforeEach(() => {
2023
config = {
@@ -48,7 +51,9 @@ describe('publish', () => {
4851
};
4952

5053
uploadDownloadCenterConfig = sinon.spy();
54+
publishToHomebrew = sinon.spy();
5155
githubRepo = createStubRepo();
56+
mongoHomebrewRepo = createStubRepo();
5257
});
5358

5459
context('if is a public release', () => {
@@ -62,7 +67,9 @@ describe('publish', () => {
6267
await publish(
6368
config,
6469
githubRepo,
65-
uploadDownloadCenterConfig
70+
mongoHomebrewRepo,
71+
uploadDownloadCenterConfig,
72+
publishToHomebrew
6673
);
6774

6875
expect(uploadDownloadCenterConfig).to.have.been.calledWith(
@@ -76,11 +83,30 @@ describe('publish', () => {
7683
await publish(
7784
config,
7885
githubRepo,
79-
uploadDownloadCenterConfig
86+
mongoHomebrewRepo,
87+
uploadDownloadCenterConfig,
88+
publishToHomebrew
8089
);
8190

8291
expect(githubRepo.promoteRelease).to.have.been.calledWith(config);
8392
});
93+
94+
it('publishes to homebrew', async() => {
95+
await publish(
96+
config,
97+
githubRepo,
98+
mongoHomebrewRepo,
99+
uploadDownloadCenterConfig,
100+
publishToHomebrew
101+
);
102+
103+
expect(publishToHomebrew).to.have.been.calledWith(
104+
path.resolve(config.rootDir, 'tmp'),
105+
mongoHomebrewRepo,
106+
config.version
107+
);
108+
expect(publishToHomebrew).to.have.been.calledAfter(githubRepo.promoteRelease as any);
109+
});
84110
});
85111

86112
context('if is not a public release', () => {
@@ -94,7 +120,9 @@ describe('publish', () => {
94120
await publish(
95121
config,
96122
githubRepo,
97-
uploadDownloadCenterConfig
123+
mongoHomebrewRepo,
124+
uploadDownloadCenterConfig,
125+
publishToHomebrew
98126
);
99127

100128
expect(uploadDownloadCenterConfig).not.to.have.been.called;
@@ -104,10 +132,24 @@ describe('publish', () => {
104132
await publish(
105133
config,
106134
githubRepo,
107-
uploadDownloadCenterConfig
135+
mongoHomebrewRepo,
136+
uploadDownloadCenterConfig,
137+
publishToHomebrew
108138
);
109139

110140
expect(githubRepo.promoteRelease).not.to.have.been.called;
111141
});
142+
143+
it('does not publish to homebrew', async() => {
144+
await publish(
145+
config,
146+
githubRepo,
147+
mongoHomebrewRepo,
148+
uploadDownloadCenterConfig,
149+
publishToHomebrew
150+
);
151+
152+
expect(publishToHomebrew).not.to.have.been.called;
153+
});
112154
});
113155
});

packages/build/src/publish.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,36 @@
1-
import { GithubRepo } from './github-repo';
21
import Config from './config';
2+
import { GithubRepo } from './github-repo';
33
import { redactConfig } from './redact-config';
4+
import type { publishToHomebrew as publishToHomebrewType } from './homebrew';
5+
import path from 'path';
46

57
export default async function publish(
68
config: Config,
7-
githubRepo: GithubRepo,
8-
uploadDownloadCenterConfig: (version: string, awsKey: string, awsSecret: string) => Promise<any>
9+
mongoshGithubRepo: GithubRepo,
10+
mongoHomebrewGithubRepo: GithubRepo,
11+
uploadDownloadCenterConfig: (version: string, awsKey: string, awsSecret: string) => Promise<any>,
12+
publishToHomebrew: typeof publishToHomebrewType
913
): Promise<void> {
1014
console.info(
1115
'mongosh: beginning publish release with config:',
1216
redactConfig(config)
1317
);
1418

15-
if (!await githubRepo.shouldDoPublicRelease(config)) return;
19+
if (!await mongoshGithubRepo.shouldDoPublicRelease(config)) return;
1620

1721
await uploadDownloadCenterConfig(
1822
config.version,
1923
config.downloadCenterAwsKey || '',
2024
config.downloadCenterAwsSecret || ''
2125
);
2226

23-
await githubRepo.promoteRelease(config);
27+
await mongoshGithubRepo.promoteRelease(config);
28+
29+
await publishToHomebrew(
30+
path.resolve(config.rootDir, 'tmp'),
31+
mongoHomebrewGithubRepo,
32+
config.version
33+
);
2434

2535
console.info('mongosh: finished release process.');
2636
}

packages/build/src/release.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
import compileExec, { executablePath } from './compile-exec';
2-
import { createTarball, TarballFile } from './tarball';
3-
import Platform from './platform';
1+
/* eslint-disable no-shadow */
2+
import { Octokit } from '@octokit/rest';
3+
import { promises as fs } from 'fs';
44
import os from 'os';
55
import path from 'path';
6-
import { promises as fs } from 'fs';
7-
import macOSSignAndNotarize from './macos-sign';
8-
import uploadToDownloadCenter from './upload-to-download-center';
6+
import { Barque } from './barque';
7+
import compileExec, { executablePath } from './compile-exec';
8+
import Config from './config';
9+
import doUpload from './do-upload';
910
import uploadDownloadCenterConfig from './download-center';
1011
import uploadArtifactToEvergreen from './evergreen';
11-
import doUpload from './do-upload';
1212
import { GithubRepo } from './github-repo';
13-
import { Octokit } from '@octokit/rest';
14-
import { Barque } from './barque';
13+
import { publishToHomebrew } from './homebrew';
14+
import macOSSignAndNotarize from './macos-sign';
15+
import Platform from './platform';
1516
import publish from './publish';
1617
import { redactConfig } from './redact-config';
17-
import Config from './config';
18+
import { createTarball, TarballFile } from './tarball';
19+
import uploadToDownloadCenter from './upload-to-download-center';
1820

1921
/**
2022
* Run the release process.
@@ -31,6 +33,7 @@ export default async function release(
3133
});
3234

3335
const githubRepo = new GithubRepo(config.repo, octokit);
36+
const mongoHomebrewRepo = new GithubRepo({ owner: 'mongodb', repo: 'homebrew-brew' }, octokit);
3437
const barque = new Barque(config);
3538
let tarballFile: TarballFile;
3639

@@ -80,7 +83,9 @@ export default async function release(
8083
await publish(
8184
config,
8285
githubRepo,
83-
uploadDownloadCenterConfig
86+
mongoHomebrewRepo,
87+
uploadDownloadCenterConfig,
88+
publishToHomebrew
8489
);
8590
} else {
8691
throw new Error(`Unknown command: ${command}`);

0 commit comments

Comments
 (0)