Skip to content

Commit cec801e

Browse files
committed
add homebrew publish to build/publish
1 parent 87b8e55 commit cec801e

File tree

9 files changed

+162
-51
lines changed

9 files changed

+162
-51
lines changed

packages/build/src/github-repo.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ export class GithubRepo {
115115
.catch(this._ignoreAlreadyExistsError);
116116
}
117117

118-
// Creates release notes and uploads assets if they are not yet uploaded to
119-
// Github.
118+
/**
119+
* Creates release notes and uploads assets if they are not yet uploaded to Github.
120+
*/
120121
async releaseToGithub(artifact: TarballFile, config: Config): Promise<void> {
121122
const tag = `v${config.version}`;
122123

@@ -208,6 +209,27 @@ export class GithubRepo {
208209
return `https://jira.mongodb.org/issues/?jql=project%20%3D%20MONGOSH%20AND%20fixVersion%20%3D%20${version}`;
209210
}
210211

212+
async createPullRequest(title: string, fromBranch: string, toBaseBranch: string): Promise<{prNumber: number, url: string}> {
213+
const response = await this.octokit.pulls.create({
214+
...this.repo,
215+
base: toBaseBranch,
216+
head: fromBranch,
217+
title
218+
});
219+
220+
return {
221+
prNumber: response.data.number,
222+
url: response.data.html_url
223+
};
224+
}
225+
226+
async mergePullRequest(prNumber: number): Promise<void> {
227+
await this.octokit.pulls.merge({
228+
...this.repo,
229+
pull_number: prNumber
230+
});
231+
}
232+
211233
private _ignoreAlreadyExistsError(): (error: any) => Promise<void> {
212234
return (error: any): Promise<void> => {
213235
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: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
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';
74
import type writeAnalyticsConfigType from './analytics';
8-
import type { publishNpmPackages as publishNpmPackagesType } from './npm-packages';
5+
import Config from './config';
96
import type uploadDownloadCenterConfigType from './download-center';
7+
import { GithubRepo } from './github-repo';
8+
import type { publishToHomebrew as publishToHomebrewType } from './homebrew';
9+
import type { publishNpmPackages as publishNpmPackagesType } from './npm-packages';
10+
import publish from './publish';
1011

1112
chai.use(require('sinon-chai'));
1213

@@ -19,7 +20,9 @@ describe('publish', () => {
1920
let uploadDownloadCenterConfig: typeof uploadDownloadCenterConfigType;
2021
let publishNpmPackages: typeof publishNpmPackagesType;
2122
let writeAnalyticsConfig: typeof writeAnalyticsConfigType;
23+
let publishToHomebrew: typeof publishToHomebrewType;
2224
let githubRepo: GithubRepo;
25+
let mongoHomebrewRepo: GithubRepo;
2326

2427
beforeEach(() => {
2528
config = {
@@ -55,7 +58,9 @@ describe('publish', () => {
5558
uploadDownloadCenterConfig = sinon.spy();
5659
publishNpmPackages = sinon.spy();
5760
writeAnalyticsConfig = sinon.spy();
61+
publishToHomebrew = sinon.spy();
5862
githubRepo = createStubRepo();
63+
mongoHomebrewRepo = createStubRepo();
5964
});
6065

6166
context('if is a public release', () => {
@@ -69,9 +74,11 @@ describe('publish', () => {
6974
await publish(
7075
config,
7176
githubRepo,
77+
mongoHomebrewRepo,
7278
uploadDownloadCenterConfig,
7379
publishNpmPackages,
74-
writeAnalyticsConfig
80+
writeAnalyticsConfig,
81+
publishToHomebrew
7582
);
7683

7784
expect(uploadDownloadCenterConfig).to.have.been.calledWith(
@@ -85,9 +92,11 @@ describe('publish', () => {
8592
await publish(
8693
config,
8794
githubRepo,
95+
mongoHomebrewRepo,
8896
uploadDownloadCenterConfig,
8997
publishNpmPackages,
90-
writeAnalyticsConfig
98+
writeAnalyticsConfig,
99+
publishToHomebrew
91100
);
92101

93102
expect(githubRepo.promoteRelease).to.have.been.calledWith(config);
@@ -97,9 +106,11 @@ describe('publish', () => {
97106
await publish(
98107
config,
99108
githubRepo,
109+
mongoHomebrewRepo,
100110
uploadDownloadCenterConfig,
101111
publishNpmPackages,
102-
writeAnalyticsConfig
112+
writeAnalyticsConfig,
113+
publishToHomebrew
103114
);
104115

105116
expect(writeAnalyticsConfig).to.have.been.calledOnceWith(
@@ -109,6 +120,24 @@ describe('publish', () => {
109120
expect(publishNpmPackages).to.have.been.calledWith();
110121
expect(publishNpmPackages).to.have.been.calledAfter(writeAnalyticsConfig as any);
111122
});
123+
it('publishes to homebrew', async() => {
124+
await publish(
125+
config,
126+
githubRepo,
127+
mongoHomebrewRepo,
128+
uploadDownloadCenterConfig,
129+
publishNpmPackages,
130+
writeAnalyticsConfig,
131+
publishToHomebrew
132+
);
133+
134+
expect(publishToHomebrew).to.have.been.calledWith(
135+
path.resolve(config.rootDir, 'tmp'),
136+
mongoHomebrewRepo,
137+
config.version
138+
);
139+
expect(publishToHomebrew).to.have.been.calledAfter(githubRepo.promoteRelease as any);
140+
});
112141
});
113142

114143
context('if is not a public release', () => {
@@ -122,9 +151,11 @@ describe('publish', () => {
122151
await publish(
123152
config,
124153
githubRepo,
154+
mongoHomebrewRepo,
125155
uploadDownloadCenterConfig,
126156
publishNpmPackages,
127-
writeAnalyticsConfig
157+
writeAnalyticsConfig,
158+
publishToHomebrew
128159
);
129160

130161
expect(uploadDownloadCenterConfig).not.to.have.been.called;
@@ -134,9 +165,11 @@ describe('publish', () => {
134165
await publish(
135166
config,
136167
githubRepo,
168+
mongoHomebrewRepo,
137169
uploadDownloadCenterConfig,
138170
publishNpmPackages,
139-
writeAnalyticsConfig
171+
writeAnalyticsConfig,
172+
publishToHomebrew
140173
);
141174

142175
expect(githubRepo.promoteRelease).not.to.have.been.called;
@@ -146,12 +179,28 @@ describe('publish', () => {
146179
await publish(
147180
config,
148181
githubRepo,
182+
mongoHomebrewRepo,
149183
uploadDownloadCenterConfig,
150184
publishNpmPackages,
151-
writeAnalyticsConfig
185+
writeAnalyticsConfig,
186+
publishToHomebrew
152187
);
153188

154189
expect(publishNpmPackages).not.to.have.been.called;
155190
});
191+
192+
it('does not publish to homebrew', async() => {
193+
await publish(
194+
config,
195+
githubRepo,
196+
mongoHomebrewRepo,
197+
uploadDownloadCenterConfig,
198+
publishNpmPackages,
199+
writeAnalyticsConfig,
200+
publishToHomebrew
201+
);
202+
203+
expect(publishToHomebrew).not.to.have.been.called;
204+
});
156205
});
157206
});

packages/build/src/publish.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,41 @@
1-
import { GithubRepo } from './github-repo';
2-
import Config from './config';
3-
import { redactConfig } from './redact-config';
1+
import path from 'path';
42
import type writeAnalyticsConfigType from './analytics';
5-
import type { publishNpmPackages as publishNpmPackagesType } from './npm-packages';
3+
import Config from './config';
64
import type uploadDownloadCenterConfigType from './download-center';
5+
import { GithubRepo } from './github-repo';
6+
import type { publishToHomebrew as publishToHomebrewType } from './homebrew';
7+
import type { publishNpmPackages as publishNpmPackagesType } from './npm-packages';
8+
import { redactConfig } from './redact-config';
79

810
export default async function publish(
911
config: Config,
10-
githubRepo: GithubRepo,
12+
mongoshGithubRepo: GithubRepo,
13+
mongoHomebrewGithubRepo: GithubRepo,
1114
uploadDownloadCenterConfig: typeof uploadDownloadCenterConfigType,
1215
publishNpmPackages: typeof publishNpmPackagesType,
13-
writeAnalyticsConfig: typeof writeAnalyticsConfigType
16+
writeAnalyticsConfig: typeof writeAnalyticsConfigType,
17+
publishToHomebrew: typeof publishToHomebrewType
1418
): Promise<void> {
1519
console.info(
1620
'mongosh: beginning publish release with config:',
1721
redactConfig(config)
1822
);
1923

20-
if (!await githubRepo.shouldDoPublicRelease(config)) return;
24+
if (!await mongoshGithubRepo.shouldDoPublicRelease(config)) return;
2125

2226
await uploadDownloadCenterConfig(
2327
config.version,
2428
config.downloadCenterAwsKey || '',
2529
config.downloadCenterAwsSecret || ''
2630
);
2731

28-
await githubRepo.promoteRelease(config);
32+
await mongoshGithubRepo.promoteRelease(config);
33+
34+
await publishToHomebrew(
35+
path.resolve(config.rootDir, 'tmp'),
36+
mongoHomebrewGithubRepo,
37+
config.version
38+
);
2939

3040
// ensures the segment api key to be present in the published packages
3141
await writeAnalyticsConfig(

0 commit comments

Comments
 (0)