review try-out: open a PR with the classifications on the page
The try-out page gets an "open a PR" button. It posts the page's classifications to the new POST /api/review-classifier/open-pr, which merges them by name into the repo's rules file on the default branch and has the review-classifier forge account commit the result on a new branch, review-classifier/<user>-<8 hex>, through the contents API. The commit's author is the forge account named like the session's Remote-User, read with the controller's admin token. The answer links to the forge's compare page, where the user opens the PR as themselves. The push uses the account's existing token from the store (swarm/services/review-classifier/forge/token, scope write:repository), so the account needs write access to the repo; a refused push answers 403 naming that. In a YAML rules file, the entries the merge leaves alone keep their text, as long as the result reads back as the merged list; otherwise the file is written out whole. DefaultBranchFiles now carries each file's blob sha, which the forge needs to replace a file, and the repo's web URL for the link. Fixes #5259 Refs #5096
This commit is contained in:
parent
6ed88ad70a
commit
49b15e7775
10 changed files with 1231 additions and 53 deletions
|
|
@ -123,9 +123,19 @@ pub struct DefaultBranchFiles {
|
|||
pub branch: String,
|
||||
/// The commit the files were read at.
|
||||
pub commit: String,
|
||||
/// Each asked-for path that exists there, with its bytes, in the order
|
||||
/// asked.
|
||||
pub files: Vec<(String, Vec<u8>)>,
|
||||
/// The repo's page on the forge, as a browser reaches it.
|
||||
pub web_url: Option<url::Url>,
|
||||
/// Each asked-for path that exists there, in the order asked.
|
||||
pub files: Vec<BranchFile>,
|
||||
}
|
||||
|
||||
/// One file of [`DefaultBranchFiles`].
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct BranchFile {
|
||||
pub path: String,
|
||||
/// The blob's sha, which the forge asks for to replace the file.
|
||||
pub sha: String,
|
||||
pub bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
/// One row of [`Client::issue_report`] — an open issue plus the two facts
|
||||
|
|
@ -1345,19 +1355,26 @@ impl Client {
|
|||
let mut trees = HashMap::new();
|
||||
let mut files = Vec::new();
|
||||
for path in paths {
|
||||
if let Some(bytes) = self.file_at(owner, repo, &commit, path, &mut trees).await? {
|
||||
files.push(((*path).to_owned(), bytes));
|
||||
if let Some((sha, bytes)) = self.file_at(owner, repo, &commit, path, &mut trees).await?
|
||||
{
|
||||
files.push(BranchFile {
|
||||
path: (*path).to_owned(),
|
||||
sha,
|
||||
bytes,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(Some(DefaultBranchFiles {
|
||||
branch,
|
||||
commit,
|
||||
web_url: info.html_url,
|
||||
files,
|
||||
}))
|
||||
}
|
||||
|
||||
/// The file at `path` in `owner/repo` at `commit`, or `None` when no
|
||||
/// blob is there. `trees` holds the tree listings already read, by sha.
|
||||
/// The blob sha and bytes of the file at `path` in `owner/repo` at
|
||||
/// `commit`, or `None` when no blob is there. `trees` holds the tree
|
||||
/// listings already read, by sha.
|
||||
async fn file_at(
|
||||
&self,
|
||||
owner: &str,
|
||||
|
|
@ -1365,7 +1382,7 @@ impl Client {
|
|||
commit: &str,
|
||||
path: &str,
|
||||
trees: &mut HashMap<String, Vec<GitEntry>>,
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
) -> Result<Option<(String, Vec<u8>)>> {
|
||||
let mut tree = commit.to_owned();
|
||||
let mut segments = path.split('/').peekable();
|
||||
while let Some(name) = segments.next() {
|
||||
|
|
@ -1383,7 +1400,10 @@ impl Client {
|
|||
return Ok(None);
|
||||
};
|
||||
if kind == "blob" {
|
||||
return self.blob(owner, repo, &sha).await.map(Some);
|
||||
return self
|
||||
.blob(owner, repo, &sha)
|
||||
.await
|
||||
.map(|bytes| Some((sha, bytes)));
|
||||
}
|
||||
tree = sha;
|
||||
}
|
||||
|
|
@ -2434,7 +2454,11 @@ mod tests {
|
|||
assert_eq!(read.commit, "def456");
|
||||
assert_eq!(
|
||||
read.files,
|
||||
[(RULES_YML.to_owned(), b"classifications: []\n".to_vec())]
|
||||
[BranchFile {
|
||||
path: RULES_YML.to_owned(),
|
||||
sha: "b1".to_owned(),
|
||||
bytes: b"classifications: []\n".to_vec(),
|
||||
}]
|
||||
);
|
||||
// Each tree is read once for both paths.
|
||||
let seen = seen.lock().unwrap();
|
||||
|
|
|
|||
Loading…
Reference in a new issue