Skip to content
Merged
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
40 changes: 24 additions & 16 deletions src/utils/roll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,21 @@ async function updateLabels(
return coveredBranches;
}

async function triggerChromiumUpgradeWorkflow(octokit: Octokit) {
// Dispatches the agent-driven Chromium upgrade workflow against the given
// roll branch (`roller/chromium/<electron branch>`), for main and release
// branches alike.
async function triggerChromiumUpgradeWorkflow(octokit: Octokit, rollBranchName: string) {
const d = debug('roller/chromium:triggerChromiumUpgradeWorkflow()');
try {
await octokit.actions.createWorkflowDispatch(CHROMIUM_UPGRADE_WORKFLOW);
d(`Dispatched ${CHROMIUM_UPGRADE_WORKFLOW.workflow_id}`);
await octokit.actions.createWorkflowDispatch({
...CHROMIUM_UPGRADE_WORKFLOW,
inputs: { 'base-ref': rollBranchName },
});
d(`Dispatched ${CHROMIUM_UPGRADE_WORKFLOW.workflow_id} for ${rollBranchName}`);
} catch (e) {
d(`Failed to dispatch ${CHROMIUM_UPGRADE_WORKFLOW.workflow_id}: ${e.message}`);
d(
`Failed to dispatch ${CHROMIUM_UPGRADE_WORKFLOW.workflow_id} for ${rollBranchName}: ${e.message}`,
);
}
}

Expand All @@ -181,6 +189,10 @@ export async function roll({
let didRoll = false;
let coveredBranches: string[] = [];

// The bot only ever rolls into the branch it created itself, which it names
// `roller/<target>/<electron branch>` in the electron/electron repo.
const rollBranchName = `roller/${rollTarget.name}/${electronBranch.name}`;

// Look for a pre-existing PR that targets this branch to see if we can update that.
const existingPrsForBranch = (await github.paginate('GET /repos/:owner/:repo/pulls', {
base: electronBranch.name,
Expand All @@ -193,11 +205,8 @@ export async function roll({
);

if (prs.length) {
// The bot only ever rolls into the branch it created itself, which it names
// `roller/<target>/<electron branch>` in the electron/electron repo. Derive
// the write target solely from this trusted naming rather than from any
// field of the (potentially untrusted) PR.
const rollBranchName = `roller/${rollTarget.name}/${electronBranch.name}`;
// Derive the write target solely from the bot's trusted roll branch naming
// rather than from any field of the (potentially untrusted) PR.
const electronRepoFullName = `${REPOS.electron.owner}/${REPOS.electron.repo}`;

// Update existing PR(s)
Expand Down Expand Up @@ -291,8 +300,7 @@ export async function roll({
} else {
d(`No existing PR found - raising a new PR`);
const sha = electronBranch.commit.sha;
const branchName = `roller/${rollTarget.name}/${electronBranch.name}`;
const shortRef = `heads/${branchName}`;
const shortRef = `heads/${rollBranchName}`;
const ref = `refs/${shortRef}`;

d(`Checking that no orphan ref exists from a previous roll`);
Expand All @@ -315,16 +323,16 @@ export async function roll({
const { previousDEPSVersion } = await updateDepsFile({
depName: rollTarget.name,
depKey: rollTarget.depsKey,
branch: branchName,
branch: rollBranchName,
targetVersion,
});

// Raise a PR
d(`Raising a PR for ${branchName} to ${electronBranch.name}`);
d(`Raising a PR for ${rollBranchName} to ${electronBranch.name}`);
const newPr = await github.pulls.create({
...REPOS.electron,
base: electronBranch.name,
head: `${REPOS.electron.owner}:${branchName}`,
head: `${REPOS.electron.owner}:${rollBranchName}`,
...getPRText(rollTarget, {
previousVersion: previousDEPSVersion,
newVersion: targetVersion,
Expand All @@ -349,8 +357,8 @@ export async function roll({
didRoll = true;
}

if (didRoll && rollTarget === ROLL_TARGETS.chromium && electronBranch.name === MAIN_BRANCH) {
await triggerChromiumUpgradeWorkflow(github);
if (didRoll && rollTarget === ROLL_TARGETS.chromium) {
await triggerChromiumUpgradeWorkflow(github, rollBranchName);
}

return coveredBranches;
Expand Down
74 changes: 67 additions & 7 deletions tests/utils/roll.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,10 @@ describe('roll()', () => {
});

expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledTimes(1);
expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledWith(
CHROMIUM_UPGRADE_WORKFLOW,
);
expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledWith({
...CHROMIUM_UPGRADE_WORKFLOW,
inputs: { 'base-ref': `roller/chromium/${MAIN_BRANCH}` },
});
});

it('dispatches when updating an existing chromium PR on main', async () => {
Expand All @@ -328,9 +329,10 @@ describe('roll()', () => {
});

expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledTimes(1);
expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledWith(
CHROMIUM_UPGRADE_WORKFLOW,
);
expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledWith({
...CHROMIUM_UPGRADE_WORKFLOW,
inputs: { 'base-ref': `roller/chromium/${MAIN_BRANCH}` },
});
});

it('does not dispatch for node rolls on main', async () => {
Expand All @@ -345,7 +347,7 @@ describe('roll()', () => {
expect(mockOctokit.actions.createWorkflowDispatch).not.toHaveBeenCalled();
});

it('does not dispatch for chromium rolls on a release branch', async () => {
it('dispatches for chromium rolls on a release branch with that roll branch as base-ref', async () => {
mockOctokit.paginate.mockReturnValue([]);

await roll({
Expand All @@ -354,6 +356,64 @@ describe('roll()', () => {
targetVersion: '120.0.0.0',
});

expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledTimes(1);
expect(mockOctokit.actions.createWorkflowDispatch).toHaveBeenCalledWith({
...CHROMIUM_UPGRADE_WORKFLOW,
inputs: { 'base-ref': `roller/chromium/${branch.name}` },
});
});

it('does not dispatch when the existing chromium PR is paused', async () => {
mockOctokit.paginate.mockReturnValue([
{
user: { login: 'electron-roller[bot]' },
title: `chore: bump ${ROLL_TARGETS.chromium.name} to bar`,
number: 1,
head: {
ref: `roller/${ROLL_TARGETS.chromium.name}/${mainBranch.name}`,
repo: { full_name: `${REPOS.electron.owner}/${REPOS.electron.repo}` },
},
body: 'Original-Version: 119.0.0.0',
labels: [{ name: 'roller/pause' }],
created_at: new Date().toISOString(),
},
]);

await roll({
rollTarget: ROLL_TARGETS.chromium,
electronBranch: mainBranch,
targetVersion: '120.0.0.0',
});

expect(mockOctokit.actions.createWorkflowDispatch).not.toHaveBeenCalled();
});

it('does not dispatch when the DEPS version is unchanged', async () => {
mockOctokit.paginate.mockReturnValue([
{
user: { login: 'electron-roller[bot]' },
title: `chore: bump ${ROLL_TARGETS.chromium.name} to bar`,
number: 1,
head: {
ref: `roller/${ROLL_TARGETS.chromium.name}/${mainBranch.name}`,
repo: { full_name: `${REPOS.electron.owner}/${REPOS.electron.repo}` },
},
body: 'Original-Version: 119.0.0.0',
labels: [],
created_at: new Date().toISOString(),
},
]);
vi.mocked(updateDepsFile).mockResolvedValue({
previousDEPSVersion: '120.0.0.0',
newDEPSVersion: '120.0.0.0',
});

await roll({
rollTarget: ROLL_TARGETS.chromium,
electronBranch: mainBranch,
targetVersion: '120.0.0.0',
});

expect(mockOctokit.actions.createWorkflowDispatch).not.toHaveBeenCalled();
});

Expand Down
Loading