Skip to content

Instantly share code, notes, and snippets.

@bronumski
Created October 28, 2020 23:34
Show Gist options
  • Save bronumski/4dc5b8d668c1dbdf007bc4b389c83437 to your computer and use it in GitHub Desktop.
Save bronumski/4dc5b8d668c1dbdf007bc4b389c83437 to your computer and use it in GitHub Desktop.
Trawls bitbucket repositories looking for stale branches and pull requests.
open System
open System.Text
open FSharp.Data
open FSharp.Json
let (username, password) = ("username", "password")
let repositoryRootUrl = "https://api.bitbucket.org/2.0/repositories/team_workspace"
let repositories = [ "RepoA"; "RepoB" ]
let lookBack = DateTime.Now.AddDays(-1.0)
let maxOutdatedToTake = 10
type Author = { display_name : string }
and Link = { href : string }
type Repository = { name : string; links : RepositoryLinks }
and RepositoryLinks = { branches : Link ; pullrequests : Link }
type PullRequest = { title : string; updated_on : DateTime; author : Author; links : PullRequestLinks }
and PullRequestLinks = { html : Link }
and PullRequests = { values : PullRequest[] }
type Branch = { name : string; links : BranchLinks; target : BranchTarget }
and BranchTarget = { author : BranchAuthor }
and Branches = { values : Branch[] }
and BranchLinks = { commits : Link; html: Link }
and BranchAuthor = { user : Author }
type Commit = { date : DateTime }
and Commits = { values : Commit[] }
let CreateBasicAuth =
sprintf "%s:%s" username password
|> Encoding.UTF8.GetBytes
|> Convert.ToBase64String
|> sprintf "Basic %s"
let authHeader = CreateBasicAuth
let GenerateRepositoryUrl repository =
Uri(sprintf "%s/%s" repositoryRootUrl repository)
type Endpoint =
| Link of Link
| Uri of Uri
let GetResource<'T>(address, query:Option<string>) =
let endpoint = match address with | Link(a) -> a.href | Uri(a) -> a.ToString()
let url = match query with | Some query -> sprintf "%s?%s" endpoint query | None -> endpoint
Json.deserialize<'T> (Http.RequestString( url, httpMethod = "GET", headers = [ "Authorization", authHeader ] ))
let GetRepositoryOutdatedPullRequests(repository:Repository) =
GetResource<PullRequests>(Link repository.links.pullrequests, Some "state=OPEN").values
|> Seq.filter(fun pr -> pr.updated_on < lookBack)
|> Seq.truncate maxOutdatedToTake
let GetBranchLatestCommit(branch:Branch) =
GetResource<Commits>(Link branch.links.commits, None).values |> Seq.head
let GetRepositoryOutdatedBranches (repository:Repository) =
GetResource<Branches>(Link repository.links.branches, None).values
|> Seq.filter(fun branch -> branch.name <> "master")
|> Seq.map(fun branch -> (branch, GetBranchLatestCommit branch))
|> Seq.filter(fun (_, commit) -> commit.date < lookBack)
|> Seq.truncate maxOutdatedToTake
let GetRepositoryData repositoryUrl =
let repository = GetResource<Repository>(repositoryUrl, None)
(repository, GetRepositoryOutdatedPullRequests(repository), GetRepositoryOutdatedBranches(repository))
[<EntryPoint>]
let main argv =
repositories
|> Seq.map(GenerateRepositoryUrl)
|> Seq.map(fun url -> GetRepositoryData(Uri url))
|> Seq.iter(fun (repo, outdatedPrs, outdatedBranch) ->
printfn "Repository: %s" repo.name
printfn "Outdated pull requests:"
outdatedPrs |> Seq.iter(fun pr -> printfn "\t%s - %s - %s" pr.title pr.author.display_name (pr.updated_on.ToString "yyyy-MM-dd"))
printfn "Outdated branches:"
outdatedBranch |> Seq.iter(fun (branch, commit) -> printfn "\t%s - %s - %s" branch.name branch.target.author.user.display_name (commit.date.ToString "yyyy-MM-dd"))
)
0 // return an integer exit code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment