@@ -356,6 +356,8 @@ pub struct Issue {
356356 /// Whether it is open or closed.
357357 pub state : IssueState ,
358358 pub milestone : Option < Milestone > ,
359+ /// Whether a PR has merge conflicts.
360+ pub mergeable : Option < bool > ,
359361}
360362
361363#[ derive( Debug , serde:: Deserialize , Eq , PartialEq ) ]
@@ -1826,6 +1828,101 @@ impl Repository {
18261828 . await
18271829 . with_context ( || format ! ( "{} failed to get issue {issue_num}" , self . full_name) )
18281830 }
1831+
1832+ /// Fetches information about merge conflicts on open PRs.
1833+ pub async fn get_merge_conflict_prs (
1834+ & self ,
1835+ client : & GithubClient ,
1836+ ) -> anyhow:: Result < Vec < MergeConflictInfo > > {
1837+ let mut prs = Vec :: new ( ) ;
1838+ let mut after = None ;
1839+ loop {
1840+ let mut data = client
1841+ . graphql_query (
1842+ "query($owner:String!, $repo:String!, $after:String) {
1843+ repository(owner: $owner, name: $repo) {
1844+ pullRequests(states: OPEN, first: 100, after: $after) {
1845+ edges {
1846+ node {
1847+ number
1848+ mergeable
1849+ baseRefName
1850+ }
1851+ }
1852+ pageInfo {
1853+ hasNextPage
1854+ endCursor
1855+ }
1856+ }
1857+ }
1858+ }" ,
1859+ serde_json:: json!( {
1860+ "owner" : self . owner( ) ,
1861+ "repo" : self . name( ) ,
1862+ "after" : after,
1863+ } ) ,
1864+ )
1865+ . await ?;
1866+ let edges = data[ "data" ] [ "repository" ] [ "pullRequests" ] [ "edges" ] . take ( ) ;
1867+ let serde_json:: Value :: Array ( edges) = edges else {
1868+ anyhow:: bail!( "expected array edges, got {edges:?}" ) ;
1869+ } ;
1870+ let this_page = edges
1871+ . into_iter ( )
1872+ . map ( |mut edge| {
1873+ serde_json:: from_value ( edge[ "node" ] . take ( ) )
1874+ . with_context ( || "failed to deserialize merge conflicts" )
1875+ } )
1876+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1877+ prs. extend ( this_page) ;
1878+ if !data[ "data" ] [ "repository" ] [ "pullRequests" ] [ "pageInfo" ] [ "hasNextPage" ]
1879+ . as_bool ( )
1880+ . unwrap_or ( false )
1881+ {
1882+ break ;
1883+ }
1884+ after = Some (
1885+ data[ "data" ] [ "repository" ] [ "pullRequests" ] [ "pageInfo" ] [ "endCursor" ]
1886+ . as_str ( )
1887+ . expect ( "endCursor is string" )
1888+ . to_string ( ) ,
1889+ ) ;
1890+ }
1891+ Ok ( prs)
1892+ }
1893+
1894+ /// Returns a list of PRs "associated" with a commit.
1895+ pub async fn pulls_for_commit (
1896+ & self ,
1897+ client : & GithubClient ,
1898+ sha : & str ,
1899+ ) -> anyhow:: Result < Vec < Issue > > {
1900+ let url = format ! ( "{}/commits/{sha}/pulls" , self . url( client) ) ;
1901+ client
1902+ . json ( client. get ( & url) )
1903+ . await
1904+ . with_context ( || format ! ( "{} failed to get pulls for commit {sha}" , self . full_name) )
1905+ }
1906+ }
1907+
1908+ /// Information about a merge conflict on a PR.
1909+ #[ derive( Debug , serde:: Deserialize ) ]
1910+ #[ serde( rename_all = "camelCase" ) ]
1911+ pub struct MergeConflictInfo {
1912+ /// Pull request number.
1913+ pub number : u64 ,
1914+ /// Whether this pull can be merged.
1915+ pub mergeable : MergeableState ,
1916+ /// The branch name where this PR is requesting to be merged to.
1917+ pub base_ref_name : String ,
1918+ }
1919+
1920+ #[ derive( Debug , serde:: Deserialize , PartialEq ) ]
1921+ #[ serde( rename_all = "SCREAMING_SNAKE_CASE" ) ]
1922+ pub enum MergeableState {
1923+ Conflicting ,
1924+ Mergeable ,
1925+ Unknown ,
18291926}
18301927
18311928pub struct Query < ' a > {
@@ -2081,9 +2178,14 @@ pub struct CreateEvent {
20812178
20822179#[ derive( Debug , serde:: Deserialize ) ]
20832180pub struct PushEvent {
2181+ /// The SHA of the most recent commit on `ref` after the push.
2182+ pub after : String ,
2183+ /// The full git ref that was pushed.
2184+ ///
2185+ /// Example: `refs/heads/main` or `refs/tags/v3.14.1`.
20842186 #[ serde( rename = "ref" ) ]
20852187 pub git_ref : String ,
2086- repository : Repository ,
2188+ pub repository : Repository ,
20872189 sender : User ,
20882190}
20892191
0 commit comments