blob: 9c277f14d4abaf9bac60b38bf6e25dd41368893e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const exec = require("@actions/exec");
const fs = require("fs");
const path = require("path");
const { Pr } = require("./pr");
const { ReviewersForLabel } = require("./reviewersForLabel");
const { BOT_NAME } = require("./constants");
function getPrFileName(prNumber) {
return `pr-${prNumber}.json`.toLowerCase();
}
function getReviewersForLabelFileName(label) {
return `reviewers-for-label-${label}.json`.toLowerCase();
}
async function commitStateToRepo() {
try {
await exec.exec("git pull origin pr-bot-state");
} catch (err) {
console.log(
`Unable to get most recent repo contents, commit may fail: ${err}`
);
}
// Print changes for observability
await exec.exec("git status", [], { ignoreReturnCode: true });
await exec.exec("git add state/*");
const changes = await exec.exec(
"git diff --quiet --cached origin/pr-bot-state state",
[],
{ ignoreReturnCode: true }
);
if (changes == 1) {
await exec.exec(`git commit -m "Updating config from bot" --allow-empty`);
await exec.exec("git push origin pr-bot-state");
} else {
console.log(
"Skipping updating state branch since there are no changes to commit"
);
}
}
export class PersistentState {
private switchedBranch = false;
// Returns a Pr object representing the current saved state of the pr.
async getPrState(prNumber: number): Promise<typeof Pr> {
var fileName = getPrFileName(prNumber);
return new Pr(await this.getState(fileName, "state/pr-state"));
}
// Writes a Pr object representing the current saved state of the pr to persistent storage.
async writePrState(prNumber: number, newState: any) {
var fileName = getPrFileName(prNumber);
await this.writeState(fileName, "state/pr-state", new Pr(newState));
}
// Returns a ReviewersForLabel object representing the current saved state of which reviewers have reviewed recently.
async getReviewersForLabelState(
label: string
): Promise<typeof ReviewersForLabel> {
var fileName = getReviewersForLabelFileName(label);
return new ReviewersForLabel(label, await this.getState(fileName, "state"));
}
// Writes a ReviewersForLabel object representing the current saved state of which reviewers have reviewed recently.
async writeReviewersForLabelState(label: string, newState: any) {
var fileName = getReviewersForLabelFileName(label);
await this.writeState(
fileName,
"state",
new ReviewersForLabel(label, newState)
);
}
private async getState(fileName, baseDirectory) {
await this.ensureCorrectBranch();
fileName = path.join(baseDirectory, fileName);
if (!fs.existsSync(fileName)) {
return null;
}
return JSON.parse(fs.readFileSync(fileName, { encoding: "utf-8" }));
}
private async writeState(fileName, baseDirectory, state) {
await this.ensureCorrectBranch();
fileName = path.join(baseDirectory, fileName);
if (!fs.existsSync(baseDirectory)) {
fs.mkdirSync(baseDirectory, { recursive: true });
}
fs.writeFileSync(fileName, JSON.stringify(state, null, 2), {
encoding: "utf-8",
});
await commitStateToRepo();
}
private async ensureCorrectBranch() {
if (this.switchedBranch) {
return;
}
console.log(
"Switching to branch pr-bot-state for reading/storing persistent state between runs"
);
try {
await exec.exec(`git config user.name ${BOT_NAME}`);
await exec.exec(`git config user.email ${BOT_NAME}@github.com`);
await exec.exec("git config pull.rebase false");
await exec.exec("git fetch origin pr-bot-state");
await exec.exec("git checkout pr-bot-state");
} catch {
console.log(
"Couldnt find branch pr-bot-state in origin, trying to create it"
);
await exec.exec("git checkout -b pr-bot-state");
// Ensure that if we've created or just checked out the branch that we can also push to it
await exec.exec("git push origin pr-bot-state");
}
this.switchedBranch = true;
}
}