2019-11-17 16:17:24 +00:00
package main
import (
"log"
"os"
2021-02-14 22:42:22 +00:00
"path/filepath"
2021-03-04 03:42:51 +00:00
"reflect"
2019-11-17 16:17:24 +00:00
"sv4git/sv"
2021-02-14 22:42:22 +00:00
"github.com/imdario/mergo"
2020-02-01 21:37:16 +00:00
"github.com/urfave/cli/v2"
2019-11-17 16:17:24 +00:00
)
2019-12-04 23:18:38 +00:00
// Version for git-sv
var Version = ""
2021-02-14 22:42:22 +00:00
const (
configFilename = "config.yml"
repoConfigFilename = ".sv4git.yml"
)
2019-11-17 16:17:24 +00:00
func main ( ) {
2020-12-02 02:15:51 +00:00
log . SetFlags ( 0 )
2021-02-14 22:42:22 +00:00
envCfg := loadEnvConfig ( )
2019-11-17 16:17:24 +00:00
2021-02-14 22:42:22 +00:00
cfg := defaultConfig ( )
if envCfg . Home != "" {
if homeCfg , err := loadConfig ( filepath . Join ( envCfg . Home , configFilename ) ) ; err == nil {
2021-03-04 03:42:51 +00:00
if merr := mergo . Merge ( & cfg , homeCfg , mergo . WithOverride , mergo . WithTransformers ( & nullTransformer { } ) ) ; merr != nil {
2021-02-14 22:42:22 +00:00
log . Fatal ( merr )
}
}
2021-02-14 04:48:11 +00:00
}
2021-02-14 22:42:22 +00:00
repoPath , rerr := getRepoPath ( )
if rerr != nil {
log . Fatal ( rerr )
2021-02-14 02:35:31 +00:00
}
2021-02-14 22:42:22 +00:00
if repoCfg , err := loadConfig ( filepath . Join ( repoPath , repoConfigFilename ) ) ; err == nil {
2021-03-04 03:42:51 +00:00
if merr := mergo . Merge ( & cfg , repoCfg , mergo . WithOverride , mergo . WithTransformers ( & nullTransformer { } ) ) ; merr != nil {
2021-02-14 22:42:22 +00:00
log . Fatal ( merr )
}
2021-02-15 04:03:57 +00:00
if len ( repoCfg . ReleaseNotes . Headers ) > 0 { // mergo is merging maps, headers will be overwritten
cfg . ReleaseNotes . Headers = repoCfg . ReleaseNotes . Headers
}
2021-02-14 05:32:23 +00:00
}
2021-02-14 02:35:31 +00:00
2021-02-14 22:42:22 +00:00
messageProcessor := sv . NewMessageProcessor ( cfg . CommitMessage , cfg . Branches )
git := sv . NewGit ( messageProcessor , cfg . Tag )
2021-02-15 05:41:43 +00:00
semverProcessor := sv . NewSemVerCommitsProcessor ( cfg . Versioning , cfg . CommitMessage )
2021-02-14 22:42:22 +00:00
releasenotesProcessor := sv . NewReleaseNoteProcessor ( cfg . ReleaseNotes )
2020-02-02 01:40:31 +00:00
outputFormatter := sv . NewOutputFormatter ( )
2019-11-17 16:17:24 +00:00
app := cli . NewApp ( )
app . Name = "sv"
2019-12-04 23:18:38 +00:00
app . Version = Version
2019-11-17 16:17:24 +00:00
app . Usage = "semantic version for git"
2020-02-01 21:37:16 +00:00
app . Commands = [ ] * cli . Command {
2021-02-14 22:42:22 +00:00
{
Name : "config" ,
Aliases : [ ] string { "cfg" } ,
Usage : "cli configuration" ,
Subcommands : [ ] * cli . Command {
{
Name : "default" ,
Usage : "show default config" ,
Action : configDefaultHandler ( ) ,
} ,
{
Name : "show" ,
Usage : "show current config" ,
Action : configShowHandler ( cfg ) ,
} ,
} ,
} ,
2019-11-17 16:17:24 +00:00
{
Name : "current-version" ,
Aliases : [ ] string { "cv" } ,
Usage : "get last released version from git" ,
Action : currentVersionHandler ( git ) ,
} ,
{
Name : "next-version" ,
Aliases : [ ] string { "nv" } ,
Usage : "generate the next version based on git commit messages" ,
Action : nextVersionHandler ( git , semverProcessor ) ,
} ,
{
2021-01-25 20:16:56 +00:00
Name : "commit-log" ,
Aliases : [ ] string { "cl" } ,
Usage : "list all commit logs according to range as jsons" ,
2021-01-25 21:01:35 +00:00
Description : "The range filter is used based on git log filters, check https://git-scm.com/docs/git-log for more info. When flag range is \"tag\" and start is empty, last tag created will be used instead. When flag range is \"date\", if \"end\" is YYYY-MM-DD the range will be inclusive." ,
2021-01-25 20:16:56 +00:00
Action : commitLogHandler ( git , semverProcessor ) ,
2021-01-25 05:51:42 +00:00
Flags : [ ] cli . Flag {
& cli . StringFlag { Name : "t" , Aliases : [ ] string { "tag" } , Usage : "get commit log from a specific tag" } ,
2021-01-25 20:16:56 +00:00
& cli . StringFlag { Name : "r" , Aliases : [ ] string { "range" } , Usage : "type of range of commits, use: tag, date or hash" , Value : string ( sv . TagRange ) } ,
2021-01-25 21:01:35 +00:00
& cli . StringFlag { Name : "s" , Aliases : [ ] string { "start" } , Usage : "start range of git log revision range, if date, the value is used on since flag instead" } ,
& cli . StringFlag { Name : "e" , Aliases : [ ] string { "end" } , Usage : "end range of git log revision range, if date, the value is used on until flag instead" } ,
2021-01-25 20:16:56 +00:00
} ,
} ,
{
Name : "commit-notes" ,
Aliases : [ ] string { "cn" } ,
2021-01-25 20:22:20 +00:00
Usage : "generate a commit notes according to range" ,
2021-01-25 21:01:35 +00:00
Description : "The range filter is used based on git log filters, check https://git-scm.com/docs/git-log for more info. When flag range is \"tag\" and start is empty, last tag created will be used instead. When flag range is \"date\", if \"end\" is YYYY-MM-DD the range will be inclusive." ,
2021-01-25 20:16:56 +00:00
Action : commitNotesHandler ( git , releasenotesProcessor , outputFormatter ) ,
Flags : [ ] cli . Flag {
& cli . StringFlag { Name : "r" , Aliases : [ ] string { "range" } , Usage : "type of range of commits, use: tag, date or hash" , Required : true } ,
2021-01-25 21:01:35 +00:00
& cli . StringFlag { Name : "s" , Aliases : [ ] string { "start" } , Usage : "start range of git log revision range, if date, the value is used on since flag instead" } ,
& cli . StringFlag { Name : "e" , Aliases : [ ] string { "end" } , Usage : "end range of git log revision range, if date, the value is used on until flag instead" } ,
2021-01-25 05:51:42 +00:00
} ,
2019-11-17 16:17:24 +00:00
} ,
{
Name : "release-notes" ,
Aliases : [ ] string { "rn" } ,
Usage : "generate release notes" ,
2020-02-02 01:40:31 +00:00
Action : releaseNotesHandler ( git , semverProcessor , releasenotesProcessor , outputFormatter ) ,
2020-02-02 03:27:03 +00:00
Flags : [ ] cli . Flag { & cli . StringFlag { Name : "t" , Aliases : [ ] string { "tag" } , Usage : "get release note from tag" } } ,
2019-11-17 16:17:24 +00:00
} ,
2020-02-02 03:49:54 +00:00
{
Name : "changelog" ,
Aliases : [ ] string { "cgl" } ,
Usage : "generate changelog" ,
Action : changelogHandler ( git , semverProcessor , releasenotesProcessor , outputFormatter ) ,
Flags : [ ] cli . Flag {
& cli . IntFlag { Name : "size" , Value : 10 , Aliases : [ ] string { "n" } , Usage : "get changelog from last 'n' tags" } ,
& cli . BoolFlag { Name : "all" , Usage : "ignore size parameter, get changelog for every tag" } ,
2021-04-11 01:59:30 +00:00
& cli . BoolFlag { Name : "add-next-version" , Usage : "add next version on change log (commits since last tag, but only if there is a new version to release)" } ,
2020-02-02 03:49:54 +00:00
} ,
} ,
2019-12-04 22:37:50 +00:00
{
Name : "tag" ,
Aliases : [ ] string { "tg" } ,
Usage : "generate tag with version based on git commit messages" ,
2020-02-02 01:40:31 +00:00
Action : tagHandler ( git , semverProcessor ) ,
2019-12-04 22:37:50 +00:00
} ,
2020-12-02 02:15:51 +00:00
{
Name : "commit" ,
Aliases : [ ] string { "cmt" } ,
Usage : "execute git commit with convetional commit message helper" ,
2021-02-14 23:02:11 +00:00
Action : commitHandler ( cfg , git , messageProcessor ) ,
2020-12-02 02:15:51 +00:00
} ,
2020-08-28 01:57:55 +00:00
{
Name : "validate-commit-message" ,
Aliases : [ ] string { "vcm" } ,
2021-02-26 00:22:28 +00:00
Usage : "use as prepare-commit-message hook to validate and enhance commit message" ,
2020-12-02 02:52:15 +00:00
Action : validateCommitMessageHandler ( git , messageProcessor ) ,
2020-08-28 01:57:55 +00:00
Flags : [ ] cli . Flag {
& cli . StringFlag { Name : "path" , Required : true , Usage : "git working directory" } ,
& cli . StringFlag { Name : "file" , Required : true , Usage : "name of the file that contains the commit log message" } ,
& cli . StringFlag { Name : "source" , Required : true , Usage : "source of the commit message" } ,
} ,
} ,
2019-11-17 16:17:24 +00:00
}
apperr := app . Run ( os . Args )
if apperr != nil {
log . Fatal ( apperr )
}
}
2021-03-04 03:42:51 +00:00
type nullTransformer struct {
}
func ( t * nullTransformer ) Transformer ( typ reflect . Type ) func ( dst , src reflect . Value ) error {
if typ . Kind ( ) == reflect . Ptr {
return func ( dst , src reflect . Value ) error {
if dst . CanSet ( ) && ! src . IsNil ( ) {
dst . Set ( src )
}
return nil
}
}
return nil
}