diff --git a/build.fsx b/build.fsx index 355145e..665a25d 100644 --- a/build.fsx +++ b/build.fsx @@ -128,6 +128,41 @@ Target "PublishToGallery" ( fun _ -> run vsceTool "publish" "release" ) +#load "paket-files/fsharp/FAKE/modules/Octokit/Octokit.fsx" +open Octokit + +Target "ReleaseGitHub" (fun _ -> + let user = + match getBuildParam "github-user" with + | s when not (String.IsNullOrWhiteSpace s) -> s + | _ -> getUserInput "Username: " + let pw = + match getBuildParam "github-pw" with + | s when not (String.IsNullOrWhiteSpace s) -> s + | _ -> getUserPassword "Password: " + let remote = + Git.CommandHelper.getGitResult "" "remote -v" + |> Seq.filter (fun (s: string) -> s.EndsWith("(push)")) + |> Seq.tryFind (fun (s: string) -> s.Contains(gitOwner + "/" + gitName)) + |> function None -> gitHome + "/" + gitName | Some (s: string) -> s.Split().[0] + + StageAll "" + Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion) + Branches.pushBranch "" remote (Information.getBranchName "") + + Branches.tag "" release.NugetVersion + Branches.pushTag "" remote release.NugetVersion + + let file = !! ("./temp" "*.vsix") |> Seq.head + + // release on github + createClient user pw + |> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes + |> uploadFile file + |> releaseDraft + |> Async.RunSynchronously +) + // -------------------------------------------------------------------------------------- // Run generator by default. Invoke 'build ' to override // -------------------------------------------------------------------------------------- @@ -149,6 +184,7 @@ Target "Release" DoNothing "Default" ==> "InstallVSCE" ==> "BuildPackage" + ==> "ReleaseGitHub" // ==> "LoginToVSCE" ==> "PublishToGallery" ==> "Release" diff --git a/paket-files/fsharp/FAKE/modules/Octokit/Octokit.fsx b/paket-files/fsharp/FAKE/modules/Octokit/Octokit.fsx new file mode 100644 index 0000000..acca044 --- /dev/null +++ b/paket-files/fsharp/FAKE/modules/Octokit/Octokit.fsx @@ -0,0 +1,102 @@ +#I __SOURCE_DIRECTORY__ +#I @"../../../../../packages/Octokit/lib/net45" +#I @"../../../../../../packages/build/Octokit/lib/net45" +#r "Octokit.dll" + +open Octokit +open System +open System.IO + +type Draft = + { Client : GitHubClient + Owner : string + Project : string + DraftRelease : Release } + +let private isRunningOnMono = System.Type.GetType ("Mono.Runtime") <> null + +/// A version of 'reraise' that can work inside computation expressions +let private captureAndReraise ex = + System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw() + Unchecked.defaultof<_> + +/// Retry the Octokit action count times +let rec private retry count asyncF = + // This retry logic causes an exception on Mono: + // https://github.com/fsharp/fsharp/issues/440 + if isRunningOnMono then + asyncF + else + async { + try + return! asyncF + with ex -> + return! + match (ex, ex.InnerException) with + | (:? AggregateException, (:? AuthorizationException as ex)) -> captureAndReraise ex + | _ when count > 0 -> retry (count - 1) asyncF + | (ex, _) -> captureAndReraise ex + } + +/// Retry the Octokit action count times after input succeed +let private retryWithArg count input asycnF = + async { + let! choice = input |> Async.Catch + match choice with + | Choice1Of2 input' -> + return! (asycnF input') |> retry count + | Choice2Of2 ex -> + return captureAndReraise ex + } + +let createClient user password = + async { + let github = new GitHubClient(new ProductHeaderValue("FAKE")) + github.Credentials <- Credentials(user, password) + return github + } + +let createClientWithToken token = + async { + let github = new GitHubClient(new ProductHeaderValue("FAKE")) + github.Credentials <- Credentials(token) + return github + } + +let private makeRelease draft owner project version prerelease (notes:seq) (client : Async) = + retryWithArg 5 client <| fun client' -> async { + let data = new NewRelease(version) + data.Name <- version + data.Body <- String.Join(Environment.NewLine, notes) + data.Draft <- draft + data.Prerelease <- prerelease + let! draft = Async.AwaitTask <| client'.Release.Create(owner, project, data) + let draftWord = if data.Draft then " draft" else "" + printfn "Created%s release id %d" draftWord draft.Id + return { + Client = client' + Owner = owner + Project = project + DraftRelease = draft } + } + +let createDraft owner project version prerelease notes client = makeRelease true owner project version prerelease notes client +let createRelease owner project version prerelease notes client = makeRelease false owner project version prerelease notes client + +let uploadFile fileName (draft : Async) = + retryWithArg 5 draft <| fun draft' -> async { + let fi = FileInfo(fileName) + let archiveContents = File.OpenRead(fi.FullName) + let assetUpload = new ReleaseAssetUpload(fi.Name,"application/octet-stream",archiveContents,Nullable()) + let! asset = Async.AwaitTask <| draft'.Client.Release.UploadAsset(draft'.DraftRelease, assetUpload) + printfn "Uploaded %s" asset.Name + return draft' + } + +let releaseDraft (draft : Async) = + retryWithArg 5 draft <| fun draft' -> async { + let update = draft'.DraftRelease.ToUpdate() + update.Draft <- Nullable(false) + let! released = Async.AwaitTask <| draft'.Client.Release.Edit(draft'.Owner, draft'.Project, draft'.DraftRelease.Id, update) + printfn "Released %d on github" released.Id + } diff --git a/paket-files/fsharp/FAKE/modules/Octokit/paket.version b/paket-files/fsharp/FAKE/modules/Octokit/paket.version new file mode 100644 index 0000000..ab41686 --- /dev/null +++ b/paket-files/fsharp/FAKE/modules/Octokit/paket.version @@ -0,0 +1 @@ +752592c55d7f9e2b7a10f1782cb4128703d7a7d3 diff --git a/paket.dependencies b/paket.dependencies index 8707e24..ff8ebf2 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -2,4 +2,6 @@ source https://nuget.org/api/v2 nuget FAKE nuget FunScript -nuget Npm.js \ No newline at end of file +nuget Npm.js + +github fsharp/FAKE modules/Octokit/Octokit.fsx \ No newline at end of file diff --git a/paket.lock b/paket.lock index 4ef4cd8..667ce63 100644 --- a/paket.lock +++ b/paket.lock @@ -1,8 +1,21 @@ NUGET remote: https://nuget.org/api/v2 specs: - FAKE (4.0.0) + FAKE (4.9.3) FunScript (1.1.94) + Microsoft.Bcl (1.1.10) + Microsoft.Bcl.Build (>= 1.0.14) + Microsoft.Bcl.Build (1.0.21) - import_targets: false + Microsoft.Net.Http (2.2.29) + Microsoft.Bcl (>= 1.1.10) + Microsoft.Bcl.Build (>= 1.0.14) Node.js (4.0.0) - Npm.js (2.13.1.0) + Npm.js (2.13.1) Node.js (>= 0.12.7) + Octokit (0.16.0) + Microsoft.Net.Http +GITHUB + remote: fsharp/FAKE + specs: + modules/Octokit/Octokit.fsx (752592c55d7f9e2b7a10f1782cb4128703d7a7d3) + Octokit \ No newline at end of file