Skip to content

Commit

Permalink
feat: add automatic resolution for Github remote (user can still conf…
Browse files Browse the repository at this point in the history
…igure it using Config file)
  • Loading branch information
MangelMaxime committed Nov 17, 2024
1 parent deff564 commit be8313e
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 45 deletions.
6 changes: 5 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<PackageVersion Include="BlackFox.CommandLine" Version="1.0.0" />
<PackageVersion Include="EasyBuild.CommitParser" Version="2.0.0" />
<PackageVersion Include="EasyBuild.FileSystemProvider" Version="0.3.0" />
<PackageVersion Include="EasyBuild.PackageReleaseNotes.Tasks" Version="2.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageVersion>
<PackageVersion Include="Expecto" Version="10.2.1" />
<PackageVersion Include="FSharp.Core" Version="8.0.101" />
<PackageVersion Include="FsToolkit.ErrorHandling" Version="4.18.0" />
Expand All @@ -16,4 +20,4 @@
<PackageVersion Include="Verify.Expecto" Version="28.2.0" />
<PackageVersion Include="YoloDev.Expecto.TestSdk" Version="0.14.3" />
</ItemGroup>
</Project>
</Project>
6 changes: 6 additions & 0 deletions EasyBuild.ChangelogGen.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EasyBuild.ChangelogGen", "s
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EasyBuild.ChangelogGen.Tests", "tests\EasyBuild.ChangelogGen.Tests.fsproj", "{70BE19B5-3E11-4CC2-9E3A-5D8792C092F7}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EasyBuild", "build\EasyBuild.fsproj", "{EF9785DD-EAEA-4C3E-9FE3-FAFCAD3D42E7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -24,5 +26,9 @@ Global
{70BE19B5-3E11-4CC2-9E3A-5D8792C092F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70BE19B5-3E11-4CC2-9E3A-5D8792C092F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70BE19B5-3E11-4CC2-9E3A-5D8792C092F7}.Release|Any CPU.Build.0 = Release|Any CPU
{EF9785DD-EAEA-4C3E-9FE3-FAFCAD3D42E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF9785DD-EAEA-4C3E-9FE3-FAFCAD3D42E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF9785DD-EAEA-4C3E-9FE3-FAFCAD3D42E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF9785DD-EAEA-4C3E-9FE3-FAFCAD3D42E7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
3 changes: 3 additions & 0 deletions src/Commands/Generate.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ type GenerateCommand() =
let res =
result {
let! config = ConfigLoader.tryLoadConfig settings.Config
// Apply automatic resolution of remote config if needed
let! config = Verify.resolveRemoteConfig config

let! changelogInfo = Changelog.load settings
do! Verify.dirty settings
do! Verify.branch settings
Expand Down
9 changes: 6 additions & 3 deletions src/Commands/Version.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ type VersionCommand() =
inherit Command<VersionSettings>()
interface ICommandLimiter<VersionSettings>

override __.Execute(context, settings) =
override __.Execute(_, _) =
let assembly = Assembly.GetEntryAssembly()
let versionAttribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()

let versionAttribute =
assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()

let version =
if versionAttribute <> null then
versionAttribute.InformationalVersion
else
"?"

Log.info($"Version: {version}")
Log.info ($"Version: {version}")
0
5 changes: 5 additions & 0 deletions src/EasyBuild.ChangelogGen.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<RollForward>Major</RollForward>
<PackAsTool>true</PackAsTool>
<ToolCommandName>changelog-gen</ToolCommandName>
<ChangelogFile>$(MSBuildThisFileDirectory)../CHANGELOG.md</ChangelogFile>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
Expand All @@ -29,6 +30,10 @@
<ItemGroup>
<PackageReference Include="BlackFox.CommandLine" />
<PackageReference Include="EasyBuild.CommitParser" />
<PackageReference Include="EasyBuild.PackageReleaseNotes.Tasks">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="Semver" />
<PackageReference Include="SimpleExec" />
Expand Down
35 changes: 34 additions & 1 deletion src/Generate/Verify.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module EasyBuild.ChangelogGen.Generate.Verify

open EasyBuild.ChangelogGen.Generate.Types
open FsToolkit.ErrorHandling
open EasyBuild.ChangelogGen

let branch (settings: GenerateSettings) =
let currentBranchName = Git.getHeadBranchName ()
Expand All @@ -28,3 +28,36 @@ let dirty (settings: GenerateSettings) =
You can use the --allow-dirty option to allow a dirty repository."""
else
Ok()

let resolveRemoteConfig (config: ConfigLoader.Config) =
match config.ChangelogGenConfig.Github with
| Some _ -> Ok config
| None ->
match Git.tryFindRemote () with
| Some remote ->
Ok
{ config with
ChangelogGenConfig.Github =
Some
{
Owner = remote.Owner
Repository = remote.Repository
}
}
| None ->
Error
"""Could not resolve the remote repository.
Automatic detection expected URL returned by `git config --get remote.origin.url` to be of the form 'https://hostname/owner/repo.git' or 'git@hostname:owner/repo.git'.
You can also provide the Github owner and repository in the configuration file:
```json
{
"changelog-gen": {
"github": {
"owner": "owner",
"repository": "repo"
}
}
}"""
81 changes: 81 additions & 0 deletions src/Git.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[<RequireQualifiedAccess>]
module Git

open System
open SimpleExec
open BlackFox.CommandLine
open Thoth.Json.Core
Expand Down Expand Up @@ -107,3 +108,83 @@ let getCommits (filter: GetCommitsFilter) =
|> Array.filter (fun x -> x.Length > 0)
|> Array.map readCommit
|> Array.toList

type Remote =
{
Owner: string
Repository: string
}

let private stripSuffix (suffix: string) (str: string) =
if str.EndsWith(suffix) then
str.Substring(0, str.Length - suffix.Length)
else
str

// Url needs to be in the format:
// https://hostname/owner/repo.git
let tryGetRemoteFromUrl (url: string) =
let normalizedUrl = url |> stripSuffix ".git"

match Uri.TryCreate(normalizedUrl, UriKind.Absolute) with
| true, uri ->
let segments =
uri.Segments
|> Seq.map _.Trim('/')
|> Seq.filter (String.IsNullOrEmpty >> not)
|> Seq.toList

if segments.Length < 2 then
None
else
let owner = segments.[segments.Length - 2]
let repo = segments.[segments.Length - 1]

Some
{
Owner = owner.Trim('/')
Repository = repo.Trim('/')
}
| false, _ -> None

let tryGetRemoteFromSSH (url: string) =
// Naive way to check the format
if url.Contains("@") && url.Contains(":") && url.Contains("/") then
let segments =
// Remove the .git extension and split the url
url |> stripSuffix ".git" |> _.Split(':') |> Seq.toList

match segments with
| _ :: owner_repo :: _ ->
let segments = owner_repo.Split('/') |> Array.rev |> Array.toList

match segments with
| repo :: owner :: _ ->
Some
{
Owner = owner
Repository = repo
}
| _ -> None
| _ -> None
else
None

let tryFindRemote () =

let struct (remoteStdout, _) =
Command.ReadAsync(
"git",
CmdLine.empty
|> CmdLine.appendRaw "config"
|> CmdLine.appendPrefix "--get" "remote.origin.url"
|> CmdLine.toString
)
|> Async.AwaitTask
|> Async.RunSynchronously

let remoteUrl = remoteStdout.Trim()

match tryGetRemoteFromUrl remoteUrl with
| Some remote -> Some remote
| None -> tryGetRemoteFromSSH remoteUrl
13 changes: 3 additions & 10 deletions src/Types.fs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
module EasyBuild.ChangelogGen.Types

open Thoth.Json.Core
open Semver
open System.IO
open System.Text.RegularExpressions

type BumpRule =
| Major
Expand Down Expand Up @@ -53,25 +50,21 @@ type GithubRemoteConfig =

type ChangelogGenConfig =
{
Github: GithubRemoteConfig
Github: GithubRemoteConfig option
Groups: Groups list
}

static member Decoder: Decoder<ChangelogGenConfig> =
Decode.object (fun get ->
{
Github = get.Required.Field "github" GithubRemoteConfig.Decoder
Github = get.Optional.Field "github" GithubRemoteConfig.Decoder
Groups = get.Required.Field "groups" (Decode.list Groups.Decoder)
}
)

static member Default =
{
Github =
{
Owner = "owner"
Repository = "repository"
}
Github = None
Groups =
[
{
Expand Down
6 changes: 6 additions & 0 deletions src/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
"Thoth.Json.Newtonsoft": "0.1.0"
}
},
"EasyBuild.PackageReleaseNotes.Tasks": {
"type": "Direct",
"requested": "[2.0.0, )",
"resolved": "2.0.0",
"contentHash": "jebz09lxa6pEJzft9Tr/PSNt5r7AVt5xmX3g4Ra+nLU1qtSrOh+hFgsywGn7fVME3LpbzhlX+2J8F7G9y3PxUQ=="
},
"FSharp.Core": {
"type": "Direct",
"requested": "[8.0.101, )",
Expand Down
26 changes: 19 additions & 7 deletions tests/Changelog.fs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ This goes into the changelog as well
}
]

let gitCommitToCommitForRelease (commit: Git.Commit) =
let private gitCommitToCommitForRelease (commit: Git.Commit) =
{
OriginalCommit = commit
SemanticCommit =
Expand All @@ -166,6 +166,16 @@ let gitCommitToCommitForRelease (commit: Git.Commit) =
| Error error -> failwith error
}

let private defaultConfigWithRemote =
{ ChangelogGenConfig.Default with
Github =
{
Owner = "owner"
Repository = "repository"
}
|> Some
}

let private generateNewVersionSectionTests =
testList
"Changelog.generateNewVersionSection"
Expand All @@ -174,7 +184,7 @@ let private generateNewVersionSectionTests =
"works for feat type commit",
(fun _ ->
Changelog.generateNewVersionSection
ChangelogGenConfig.Default
defaultConfigWithRemote
{
NewVersion = Semver.SemVersion(1, 0, 0)
CommitsForRelease =
Expand All @@ -199,7 +209,7 @@ let private generateNewVersionSectionTests =
"works for fix type commit",
(fun _ ->
Changelog.generateNewVersionSection
ChangelogGenConfig.Default
defaultConfigWithRemote
{
NewVersion = Semver.SemVersion(1, 0, 0)
CommitsForRelease =
Expand All @@ -224,7 +234,7 @@ let private generateNewVersionSectionTests =
"breaking change are going into their own section if configured",
(fun _ ->
Changelog.generateNewVersionSection
ChangelogGenConfig.Default
defaultConfigWithRemote
{
NewVersion = Semver.SemVersion(1, 0, 0)
CommitsForRelease =
Expand Down Expand Up @@ -265,6 +275,7 @@ let private generateNewVersionSectionTests =
Owner = "owner"
Repository = "repository"
}
|> Some
Groups =
[
{
Expand Down Expand Up @@ -319,6 +330,7 @@ let private generateNewVersionSectionTests =
Owner = "owner"
Repository = "repository"
}
|> Some
Groups =
[
{
Expand Down Expand Up @@ -367,7 +379,7 @@ let private generateNewVersionSectionTests =
"include changelog additional data when present",
(fun _ ->
Changelog.generateNewVersionSection
ChangelogGenConfig.Default
defaultConfigWithRemote
{
NewVersion = Semver.SemVersion(1, 0, 0)
CommitsForRelease =
Expand Down Expand Up @@ -419,7 +431,7 @@ let private updateChangelogWithNewVersionTests =
| Error _ -> failwith "Expected Ok"

Changelog.updateWithNewVersion
ChangelogGenConfig.Default
defaultConfigWithRemote
{
NewVersion = Semver.SemVersion(1, 1, 0)
CommitsForRelease =
Expand Down Expand Up @@ -466,7 +478,7 @@ let private updateChangelogWithNewVersionTests =
| Error _ -> failwith "Expected Ok"

Changelog.updateWithNewVersion
ChangelogGenConfig.Default
defaultConfigWithRemote
{
NewVersion = Semver.SemVersion(1, 1, 0)
CommitsForRelease =
Expand Down
Loading

0 comments on commit be8313e

Please sign in to comment.