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
9 changes: 8 additions & 1 deletion crates/squawk/src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ fn get_github_private_key(
}

fn create_gh_app(
github_api_url: Option<String>,
github_install_id: Option<i64>,
github_app_id: Option<i64>,
github_token: Option<String>,
Expand All @@ -51,7 +52,11 @@ fn create_gh_app(

if let Some(github_token) = github_token {
info!("using github actions client");
return Ok(Box::new(actions::GitHub::new(&github_token)));
let client = match github_api_url {
Some(github_api_url) => actions::GitHub::new_with_url(&github_api_url, &github_token),
None => actions::GitHub::new(&github_token),
};
return Ok(Box::new(client));
};
bail!(
"Missing GitHub credentials:
Expand Down Expand Up @@ -84,6 +89,7 @@ pub fn check_and_comment_on_pr(
paths,
fail_on_violations,
github_private_key,
github_api_url,
github_token,
github_app_id,
github_install_id,
Expand All @@ -101,6 +107,7 @@ pub fn check_and_comment_on_pr(
};

let github_app = create_gh_app(
github_api_url,
github_install_id,
github_app_id,
github_token,
Expand Down
3 changes: 3 additions & 0 deletions crates/squawk/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub struct UploadToGithubArgs {
github_private_key: Option<String>,
#[structopt(long, env = "SQUAWK_GITHUB_PRIVATE_KEY_BASE64")]
github_private_key_base64: Option<String>,
/// GitHub API url.
#[structopt(long, env = "SQUAWK_GITHUB_API_URL")]
github_api_url: Option<String>,
#[structopt(long, env = "SQUAWK_GITHUB_TOKEN")]
github_token: Option<String>,
/// GitHub App Id.
Expand Down
12 changes: 11 additions & 1 deletion crates/squawk_github/src/actions.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
use crate::app;
use crate::{Comment, GitHubApi, GithubError};
use crate::{Comment, DEFAULT_GITHUB_API_URL, GitHubApi, GithubError};

pub struct GitHub {
github_api_url: String,
github_token: String,
}
impl GitHub {
#[must_use]
pub fn new(github_token: &str) -> Self {
Self::new_with_url(DEFAULT_GITHUB_API_URL, github_token)
}

#[must_use]
pub fn new_with_url(github_api_url: &str, github_token: &str) -> Self {
GitHub {
github_api_url: github_api_url.to_string(),
github_token: github_token.to_string(),
}
}
Expand All @@ -24,6 +31,7 @@ impl GitHubApi for GitHub {
body: &str,
) -> Result<(), GithubError> {
app::create_comment(
&self.github_api_url,
app::CommentArgs {
owner: owner.to_string(),
repo: repo.to_string(),
Expand All @@ -40,6 +48,7 @@ impl GitHubApi for GitHub {
issue_id: i64,
) -> Result<Vec<Comment>, GithubError> {
app::list_comments(
&self.github_api_url,
&app::PullRequest {
issue: issue_id,
owner: owner.to_string(),
Expand All @@ -56,6 +65,7 @@ impl GitHubApi for GitHub {
body: &str,
) -> Result<(), GithubError> {
app::update_comment(
&self.github_api_url,
owner,
repo,
comment_id,
Expand Down
51 changes: 39 additions & 12 deletions crates/squawk_github/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(clippy::doc_markdown)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::single_match_else)]
use crate::{Comment, GitHubApi, GithubError};
use crate::{Comment, DEFAULT_GITHUB_API_URL, GitHubApi, GithubError};
use jsonwebtoken::{Algorithm, EncodingKey, Header};

use log::info;
Expand Down Expand Up @@ -32,10 +32,14 @@ pub struct GithubAccessToken {
pub token: String,
}
/// https://developer.github.com/v3/apps/#create-an-installation-access-token-for-an-app
fn create_access_token(jwt: &str, install_id: i64) -> Result<GithubAccessToken, GithubError> {
fn create_access_token(
github_api_url: &str,
jwt: &str,
install_id: i64,
) -> Result<GithubAccessToken, GithubError> {
Ok(reqwest::Client::new()
.post(&format!(
"https://api.github.com/app/installations/{install_id}/access_tokens",
"{github_api_url}/app/installations/{install_id}/access_tokens",
))
.header(AUTHORIZATION, format!("Bearer {jwt}"))
.header(ACCEPT, "application/vnd.github.machine-man-preview+json")
Expand All @@ -45,11 +49,15 @@ fn create_access_token(jwt: &str, install_id: i64) -> Result<GithubAccessToken,
}

/// https://developer.github.com/v3/issues/comments/#create-an-issue-comment
pub(crate) fn create_comment(comment: CommentArgs, secret: &str) -> Result<(), GithubError> {
pub(crate) fn create_comment(
github_api_url: &str,
comment: CommentArgs,
secret: &str,
) -> Result<(), GithubError> {
let comment_body = CommentBody { body: comment.body };
reqwest::Client::new()
.post(&format!(
"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/comments",
"{github_api_url}/repos/{owner}/{repo}/issues/{issue_number}/comments",
owner = comment.owner,
repo = comment.repo,
issue_number = comment.issue
Expand All @@ -68,9 +76,9 @@ pub struct GitHubAppInfo {
}

/// Get the bot name for finding existing comments on a PR
pub fn get_app_info(jwt: &str) -> Result<GitHubAppInfo, GithubError> {
pub fn get_app_info(github_api_url: &str, jwt: &str) -> Result<GitHubAppInfo, GithubError> {
Ok(reqwest::Client::new()
.get("https://api.github.com/app")
.get(&format!("{github_api_url}/app"))
.header(AUTHORIZATION, format!("Bearer {jwt}"))
.send()?
.error_for_status()?
Expand Down Expand Up @@ -142,12 +150,16 @@ pub struct PullRequest {
}

/// https://developer.github.com/v3/issues/comments/#list-issue-comments
pub(crate) fn list_comments(pr: &PullRequest, secret: &str) -> Result<Vec<Comment>, GithubError> {
pub(crate) fn list_comments(
github_api_url: &str,
pr: &PullRequest,
secret: &str,
) -> Result<Vec<Comment>, GithubError> {
// TODO(sbdchd): use the next links to get _all_ the comments
// see: https://developer.github.com/v3/guides/traversing-with-pagination/
Ok(reqwest::Client::new()
.get(&format!(
"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/comments",
"{github_api_url}/repos/{owner}/{repo}/issues/{issue_number}/comments",
owner = pr.owner,
repo = pr.repo,
issue_number = pr.issue
Expand All @@ -161,6 +173,7 @@ pub(crate) fn list_comments(pr: &PullRequest, secret: &str) -> Result<Vec<Commen

/// https://developer.github.com/v3/issues/comments/#update-an-issue-comment
pub(crate) fn update_comment(
github_api_url: &str,
owner: &str,
repo: &str,
comment_id: i64,
Expand All @@ -169,7 +182,7 @@ pub(crate) fn update_comment(
) -> Result<(), GithubError> {
reqwest::Client::new()
.patch(&format!(
"https://api.github.com/repos/{owner}/{repo}/issues/comments/{comment_id}",
"{github_api_url}/repos/{owner}/{repo}/issues/comments/{comment_id}",
))
.header(AUTHORIZATION, format!("Bearer {secret}"))
.json(&CommentBody { body })
Expand All @@ -179,19 +192,30 @@ pub(crate) fn update_comment(
}

pub struct GitHub {
github_api_url: String,
slug_name: String,
installation_access_token: String,
}

impl GitHub {
pub fn new(private_key: &str, app_id: i64, installation_id: i64) -> Result<Self, GithubError> {
Self::new_with_url(DEFAULT_GITHUB_API_URL, private_key, app_id, installation_id)
}

pub fn new_with_url(
github_api_url: &str,
private_key: &str,
app_id: i64,
installation_id: i64,
) -> Result<Self, GithubError> {
info!("generating jwt");
let jwt = generate_jwt(private_key, app_id)?;
info!("getting app info");
let app_info = get_app_info(&jwt)?;
let access_token = create_access_token(&jwt, installation_id)?;
let app_info = get_app_info(github_api_url, &jwt)?;
let access_token = create_access_token(github_api_url, &jwt, installation_id)?;

Ok(GitHub {
github_api_url: github_api_url.to_string(),
slug_name: format!("{}[bot]", app_info.slug),
installation_access_token: access_token.token,
})
Expand All @@ -210,6 +234,7 @@ impl GitHubApi for GitHub {
body: &str,
) -> Result<(), GithubError> {
create_comment(
&self.github_api_url,
CommentArgs {
owner: owner.to_string(),
repo: repo.to_string(),
Expand All @@ -226,6 +251,7 @@ impl GitHubApi for GitHub {
issue_id: i64,
) -> Result<Vec<Comment>, GithubError> {
list_comments(
&self.github_api_url,
&PullRequest {
owner: owner.to_string(),
repo: repo.to_string(),
Expand All @@ -242,6 +268,7 @@ impl GitHubApi for GitHub {
body: &str,
) -> Result<(), GithubError> {
update_comment(
&self.github_api_url,
owner,
repo,
comment_id,
Expand Down
2 changes: 2 additions & 0 deletions crates/squawk_github/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use std::error::Error;
use log::info;
use serde::{Deserialize, Serialize};

pub(crate) const DEFAULT_GITHUB_API_URL: &'static str = "https://api.github.com";

#[derive(Debug)]
pub enum GithubError {
JsonWebTokenCreation(jsonwebtoken::errors::Error),
Expand Down
Loading