From b601077231fc9a3368d49015597b9fd1594dcfdd Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Wed, 13 Sep 2017 18:39:30 -0300 Subject: [PATCH 1/7] Adds suport to semantic version comparing --- src/relflow.erl | 313 +++++++++++++++++++++++++----------------------- 1 file changed, 165 insertions(+), 148 deletions(-) diff --git a/src/relflow.erl b/src/relflow.erl index fd92b21..dd2f290 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -12,198 +12,215 @@ %% =================================================================== -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - Provider = providers:create([ - {name, ?PROVIDER}, % The 'user friendly' name of the task - {module, ?MODULE}, % The module implementation of the task - {bare, true}, % The task can be run by the user, always true - {deps, ?DEPS}, % The list of dependencies - {example, "rebar3 relflow"}, % How to use the plugin - {opts, opts()}, % list of options understood by the plugin - {short_desc, "release workflow util"}, - {desc, desc()} - ]), - {ok, rebar_state:add_provider(State, Provider)}. + Provider = providers:create([ + {name, ?PROVIDER}, % The 'user friendly' name of the task + {module, ?MODULE}, % The module implementation of the task + {bare, true}, % The task can be run by the user, always true + {deps, ?DEPS}, % The list of dependencies + {example, "rebar3 relflow"}, % How to use the plugin + {opts, opts()}, % list of options understood by the plugin + {short_desc, "release workflow util"}, + {desc, desc()} + ]), + {ok, rebar_state:add_provider(State, Provider)}. desc() -> " Relflow ======= Examples: - rebar3 relflow -u v1.2.3 # upgrade from last release, at git tag v1.2.3 - rebar3 relflow init-versions # reset all vsns using relflow format - rebar3 relflow --version # print relflow version + rebar3 relflow -u v1.2.3 # upgrade from last release, at git tag v1.2.3 + rebar3 relflow init-versions # reset all vsns using relflow format + rebar3 relflow --version # print relflow version ". opts() -> - [ - {upfrom, $u, "upfrom", string, - "Git revision/tag to upgrade from (for appup generation)"}, - {nextver, $x, "nextversion", {string, "auto"}, - "The version string to use for the next release"}, - {autogit, $g, "autogit", {boolean, true}, - "Automatically add and commit relflow changes to git"}, - {force, $f, "force", {boolean, false}, - "Force relflow to run even with uncommitted local changes"}, - {version, $v, "version", undefined, - "Print relflow version and exit"} - ]. + [ + {upfrom, $u, "upfrom", string, + "Git revision/tag to upgrade from (for appup generation)"}, + {nextver, $x, "nextversion", {string, "auto"}, + "The version string to use for the next release"}, + {autogit, $g, "autogit", {boolean, true}, + "Automatically add and commit relflow changes to git"}, + {force, $f, "force", {boolean, false}, + "Force relflow to run even with uncommitted local changes"}, + {version, $v, "version", undefined, + "Print relflow version and exit"}, + {semver, $s, "semver", {boolean, true}, + "Uses semantic versioning to compare versions"} + ]. relflow_version() -> - {ok, V} = application:get_key(relflow, vsn), - V. + {ok, V} = application:get_key(relflow, vsn), + V. do(RebarState) -> - Time = utctime(), - State0 = relflow_state:set_default_nextver(new_rel_vsn(Time), - relflow_state:nextappver(new_app_vsn(Time), - relflow_state:new(RebarState))), - - case relflow_state:version(State0) of - undefined -> - do_0(State0); - _ -> - io:format("~s\n",[relflow_version()]), - {ok, RebarState} - end. + Time = utctime(), + State0 = relflow_state:set_default_nextver(new_rel_vsn(Time), + relflow_state:nextappver(new_app_vsn(Time), + relflow_state:new(RebarState))), + + case relflow_state:version(State0) of + undefined -> + do_0(State0); + _ -> + io:format("~s\n",[relflow_version()]), + {ok, RebarState} + end. do_0(State) -> - case relflow_state:task(State) of - undefined -> - do_1(State); - "init-versions" -> - do_init_versions(State) - end. + case relflow_state:task(State) of + undefined -> + do_1(State); + "init-versions" -> + do_init_versions(State) + end. do_1(State0) -> - case relflow_state:upfrom(State0) of - undefined -> - ?PRV_ERROR(no_upfrom); - Rev -> - OldRelVer = relflow_git:relver_at(Rev), - State = relflow_state:oldrelver(OldRelVer, State0), - do_2(State) - end. + case relflow_state:upfrom(State0) of + undefined -> + ?PRV_ERROR(no_upfrom); + Rev -> + OldRelVer = relflow_git:relver_at(Rev), + State = relflow_state:oldrelver(OldRelVer, State0), + do_2(State) + end. do_2(State) -> - rebar_api:debug("relflow upgrading from release ~s to ~s",[ - relflow_state:oldrelver(State), - relflow_state:nextver(State)]), - rebar_api:debug("bumped applications will use vsn: ~s", [ - relflow_state:nextappver(State)]), - ChangesSinceRev = relflow_git:since(relflow_state:upfrom(State)), - ChangeMap = relflow_appup:generate_appups(ChangesSinceRev, State), - exec(ChangeMap, State, fun(A,B) -> exec_1(A,B,fun exec_2/3) end). + rebar_api:debug("relflow upgrading from release ~s to ~s",[ + relflow_state:oldrelver(State), + relflow_state:nextver(State)]), + rebar_api:debug("bumped applications will use vsn: ~s", [ + relflow_state:nextappver(State)]), + ChangesSinceRev = relflow_git:since(relflow_state:upfrom(State)), + ChangeMap = relflow_appup:generate_appups(ChangesSinceRev, State), + exec(ChangeMap, State, fun(A,B) -> exec_1(A,B,fun exec_2/3) end). do_init_versions(State0) -> - NextAppVer = relflow_state:nextappver(State0), - rebar_api:info("New application vsn: ~s", [NextAppVer]), - BumperFun = fun(_Map, State, NewRelVsn) -> - Apps = [ {rebar_app_info:name(A), rebar_app_info:app_file_src(A)} - || A <- rebar_state:project_apps(relflow_state:rebar_state(State0)) - ], - lists:foreach(fun({_AppName, AppFile}) -> - %rebar_api:info("Setting app vsn in ~s to ~s", [AppName, NextAppVer]), - ok = relflow_rewriter:set_appfile_version(AppFile, NextAppVer) - end, Apps), - rebar_api:info("Setting release vsn in rebar.config to ~s", [NewRelVsn]), - case relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn) of - {error, ErrReason} -> - ?PRV_ERROR(ErrReason); - _ -> - rebar_api:info("You are advised to commit and tag this as '~s'",[NewRelVsn]), - {ok, relflow_state:rebar_state(State)} - end - end, - Changes = #{}, - exec(Changes, State0, fun(A,B) -> exec_1(A,B,BumperFun) end). + NextAppVer = relflow_state:nextappver(State0), + rebar_api:info("New application vsn: ~s", [NextAppVer]), + BumperFun = fun(_Map, State, NewRelVsn) -> + Apps = [ {rebar_app_info:name(A), rebar_app_info:app_file_src(A)} + || A <- rebar_state:project_apps(relflow_state:rebar_state(State0)) + ], + lists:foreach(fun({_AppName, AppFile}) -> + %rebar_api:info("Setting app vsn in ~s to ~s", [AppName, NextAppVer]), + ok = relflow_rewriter:set_appfile_version(AppFile, NextAppVer) + end, Apps), + rebar_api:info("Setting release vsn in rebar.config to ~s", [NewRelVsn]), + case relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn) of + {error, ErrReason} -> + ?PRV_ERROR(ErrReason); + _ -> + rebar_api:info("You are advised to commit and tag this as '~s'",[NewRelVsn]), + {ok, relflow_state:rebar_state(State)} + end + end, + Changes = #{}, + exec(Changes, State0, fun(A,B) -> exec_1(A,B,BumperFun) end). format_error(relflow_marker_missing) -> - "You must have a '%% relflow-release-version-marker' line in rebar.config\n " ++ - "See the README at github.com/RJ/relflow"; + "You must have a '%% relflow-release-version-marker' line in rebar.config\n " ++ + "See the README at github.com/RJ/relflow"; format_error(unclean_git) -> - "Relflow modifies files in-place. Will not run with uncommitted changes."; + "Relflow modifies files in-place. Will not run with uncommitted changes."; format_error(no_upfrom) -> - "Missing git revision to upgrade from, eg: rebar3 relflow -u abc123\n " ++ - "(or try: rebar3 help relflow)"; + "Missing git revision to upgrade from, eg: rebar3 relflow -u abc123\n " ++ + "(or try: rebar3 help relflow)"; format_error({relvsn_ordering, Old, New}) -> - io_lib:format("New release vsn is less than old! (new:~s < old:~s)", [New, Old]); + io_lib:format("New release vsn is less than old! (new:~s < old:~s)", [New, Old]); format_error(Reason) -> - io_lib:format("Unhandled relflow error: ~p", [Reason]). + io_lib:format("Unhandled relflow error: ~p", [Reason]). utctime() -> erlang:localtime_to_universaltime(erlang:localtime()). new_rel_vsn({{Year,Month,Day},{Hour,Min,Sec}}) -> - lists:flatten( - io_lib:format("~4.10.0B~2.10.0B~2.10.0B.~2.10.0B~2.10.0B~2.10.0B", - [Year, Month, Day, Hour, Min, Sec])). + lists:flatten( + io_lib:format("~4.10.0B~2.10.0B~2.10.0B.~2.10.0B~2.10.0B~2.10.0B", + [Year, Month, Day, Hour, Min, Sec])). new_app_vsn({{Year,Month,Day},{Hour,Min,Sec}}) -> - lists:flatten( - io_lib:format("~4.10.0B~2.10.0B~2.10.0B-~2.10.0B~2.10.0B~2.10.0B-relflow", - [Year, Month, Day, Hour, Min, Sec])). + lists:flatten( + io_lib:format("~4.10.0B~2.10.0B~2.10.0B-~2.10.0B~2.10.0B~2.10.0B-relflow", + [Year, Month, Day, Hour, Min, Sec])). exec(Map, State, Next) -> - case relflow_state:force(State) orelse relflow_git:is_clean() of - true -> Next(Map, State); - false -> ?PRV_ERROR(unclean_git) - end. + case relflow_state:force(State) orelse relflow_git:is_clean() of + true -> Next(Map, State); + false -> ?PRV_ERROR(unclean_git) + end. exec_1(Map, State, Next) -> - NewRelVsn = relflow_state:nextver(State), - case NewRelVsn > relflow_state:oldrelver(State) of - true -> Next(Map, State, NewRelVsn); - false -> ?PRV_ERROR({relvsn_ordering, relflow_state:oldrelver(State), NewRelVsn}) - end. + NewRelVsn = relflow_state:nextver(State), + case greater_than(NewRelVsn, relflow_state:oldrelver(State)) of + true -> Next(Map, State, NewRelVsn); + false -> ?PRV_ERROR({relvsn_ordering, relflow_state:oldrelver(State), NewRelVsn}) + end. + +greater_than([NewMajor, ".", NewMinor, ".", NewPatch], [OldMajor, ".", OldMinor, ".", OldPatch]) -> + if + NewMajor > OldMajor -> true; + NewMajor < OldMajor -> false; + NewMajor == OldMajor -> + if + NewMinor > OldMinor -> true; + NewMinor < OldMinor -> false; + NewMinor == OldMinor -> NewPatch > OldPatch + end + end; + + +greater_than(NewVersion, OldVersion) -> NewVersion > OldVersion. exec_2(Map, State, NewRelVsn) -> - lists:foreach(fun({_AppName, #{appup_path := Path, - appup_term := T, - appsrc_path := AppSrc, - next_vsn := NextVsn}}) -> - rebar_api:info("Replace ~s",[Path]), - Contents = io_lib:format("~p.",[T]), - ok = filelib:ensure_dir(Path), - ok = file:write_file(Path, Contents), - %rebar_api:info("Bumping version in ~s", [AppSrc]), - ok = relflow_rewriter:set_appfile_version(AppSrc, NextVsn) - end, maps:to_list(Map)), - rebar_api:info("Rewriting release vsn in rebar.config: ~s", [NewRelVsn]), - relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn), - %% print summary - FilesTouched = lists:foldl( - fun(#{appup_path := F1, appsrc_path := F2}, Acc) -> - [F1, F2 | Acc] - end, ["rebar.config"], maps:values(Map)), - - %% git things - GitAddCmds = [ fmt("git add ~s", [AddFile]) || AddFile <- FilesTouched ], - GitCmds = GitAddCmds ++ [ - %fmt("git add ~s", [string:join(FilesTouched, " ")]), - fmt("git commit -m\"relflow ~s --> ~s\"", [relflow_state:oldrelver(State), NewRelVsn]), - fmt("git tag -a \"v~s\" -m \"~s\"", [NewRelVsn, NewRelVsn]) - ], - case {relflow_state:autogit(State), relflow_state:force(State)} of - {true, false} -> exec_git(GitCmds); - {false, true} -> exec_git(GitCmds); - {false, false} -> print_git(GitCmds); - {true, true} -> - rebar_api:warn("Not running git commands, because you --forced",[]), - print_git(GitCmds) - end, - {ok, relflow_state:rebar_state(State)}. + lists:foreach(fun({_AppName, #{appup_path := Path, + appup_term := T, + appsrc_path := AppSrc, + next_vsn := NextVsn}}) -> + rebar_api:info("Replace ~s",[Path]), + Contents = io_lib:format("~p.",[T]), + ok = filelib:ensure_dir(Path), + ok = file:write_file(Path, Contents), + %rebar_api:info("Bumping version in ~s", [AppSrc]), + ok = relflow_rewriter:set_appfile_version(AppSrc, NextVsn) + end, maps:to_list(Map)), + rebar_api:info("Rewriting release vsn in rebar.config: ~s", [NewRelVsn]), + relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn), + %% print summary + FilesTouched = lists:foldl( + fun(#{appup_path := F1, appsrc_path := F2}, Acc) -> + [F1, F2 | Acc] + end, ["rebar.config"], maps:values(Map)), + + %% git things + GitAddCmds = [ fmt("git add ~s", [AddFile]) || AddFile <- FilesTouched ], + GitCmds = GitAddCmds ++ [ + %fmt("git add ~s", [string:join(FilesTouched, " ")]), + fmt("git commit -m\"relflow ~s --> ~s\"", [relflow_state:oldrelver(State), NewRelVsn]), + fmt("git tag -a \"v~s\" -m \"~s\"", [NewRelVsn, NewRelVsn]) + ], + case {relflow_state:autogit(State), relflow_state:force(State)} of + {true, false} -> exec_git(GitCmds); + {false, true} -> exec_git(GitCmds); + {false, false} -> print_git(GitCmds); + {true, true} -> + rebar_api:warn("Not running git commands, because you --forced",[]), + print_git(GitCmds) + end, + {ok, relflow_state:rebar_state(State)}. exec_git(Cmds) -> - lists:foreach(fun(Cmd) -> - case os:cmd(Cmd) of - "" -> rebar_api:info("$ ~s", [Cmd]); - Res -> rebar_api:info("$ ~s\n~s", [Cmd, string:strip(Res, right)]) - end - end, Cmds). + lists:foreach(fun(Cmd) -> + case os:cmd(Cmd) of + "" -> rebar_api:info("$ ~s", [Cmd]); + Res -> rebar_api:info("$ ~s\n~s", [Cmd, string:strip(Res, right)]) + end + end, Cmds). print_git(Cmds) -> - S = iolist_to_binary([ [C, "\n"] || C <- Cmds ]), - rebar_api:info("Recommended git commands:\n~s", [S]). + S = iolist_to_binary([ [C, "\n"] || C <- Cmds ]), + rebar_api:info("Recommended git commands:\n~s", [S]). fmt(S,A) -> lists:flatten(io_lib:format(S,A)). From 7a1bb8a4ec1a9f177f5c8f8cb1f11199e7b55d7a Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Wed, 13 Sep 2017 18:45:50 -0300 Subject: [PATCH 2/7] Converts version to integer --- src/relflow.erl | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/relflow.erl b/src/relflow.erl index dd2f290..2ca4d34 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -160,14 +160,20 @@ exec_1(Map, State, Next) -> end. greater_than([NewMajor, ".", NewMinor, ".", NewPatch], [OldMajor, ".", OldMinor, ".", OldPatch]) -> + NewMajorAsInt = string:to_integer(NewMajor), + NewMinorAsInt = string:to_integer(NewMinor), + NewPatchAsInt = string:to_integer(NewPatch), + OldMajorAsInt = string:to_integer(OldMajor), + OldMinorAsInt = string:to_integer(OldMinor), + OldPatchAsInt = string:to_integer(OldPatch), if - NewMajor > OldMajor -> true; - NewMajor < OldMajor -> false; - NewMajor == OldMajor -> + NewMajorAsInt > OldMajorAsInt -> true; + NewMajorAsInt < OldMajorAsInt -> false; + NewMajorAsInt == OldMajorAsInt -> if - NewMinor > OldMinor -> true; - NewMinor < OldMinor -> false; - NewMinor == OldMinor -> NewPatch > OldPatch + NewMinorAsInt > OldMinorAsInt -> true; + NewMinorAsInt < OldMinorAsInt -> false; + NewMinorAsInt == OldMinorAsInt -> NewPatchAsInt > OldPatchAsInt end end; From 5489fbe5a77a565e6bb61712702e9cbe9178ab88 Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Thu, 14 Sep 2017 11:27:28 -0300 Subject: [PATCH 3/7] Splits string --- src/relflow.erl | 46 +++++++++++++++++++++++-------------------- src/relflow_state.erl | 3 +++ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/relflow.erl b/src/relflow.erl index 2ca4d34..2af8c41 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -154,31 +154,35 @@ exec(Map, State, Next) -> exec_1(Map, State, Next) -> NewRelVsn = relflow_state:nextver(State), - case greater_than(NewRelVsn, relflow_state:oldrelver(State)) of + OldRelVsn = relflow_state:oldrelver(State), + case greater_than(NewRelVsn, OldRelVsn, State) of true -> Next(Map, State, NewRelVsn); - false -> ?PRV_ERROR({relvsn_ordering, relflow_state:oldrelver(State), NewRelVsn}) + false -> ?PRV_ERROR({relvsn_ordering, OldRelVsn, NewRelVsn}) end. -greater_than([NewMajor, ".", NewMinor, ".", NewPatch], [OldMajor, ".", OldMinor, ".", OldPatch]) -> - NewMajorAsInt = string:to_integer(NewMajor), - NewMinorAsInt = string:to_integer(NewMinor), - NewPatchAsInt = string:to_integer(NewPatch), - OldMajorAsInt = string:to_integer(OldMajor), - OldMinorAsInt = string:to_integer(OldMinor), - OldPatchAsInt = string:to_integer(OldPatch), - if - NewMajorAsInt > OldMajorAsInt -> true; - NewMajorAsInt < OldMajorAsInt -> false; - NewMajorAsInt == OldMajorAsInt -> +greater_than(NewVersion, OldVersion, State) -> + case relflow_state:semver(State) of + true -> + [NewMajor, NewMinor, NewPatch] = string:split(NewVersion, "."), + [OldMajor, OldMinor, OldPatch] = string:split(OldVersion, "."), + NewMajorAsInt = string:to_integer(NewMajor), + NewMinorAsInt = string:to_integer(NewMinor), + NewPatchAsInt = string:to_integer(NewPatch), + OldMajorAsInt = string:to_integer(OldMajor), + OldMinorAsInt = string:to_integer(OldMinor), + OldPatchAsInt = string:to_integer(OldPatch), if - NewMinorAsInt > OldMinorAsInt -> true; - NewMinorAsInt < OldMinorAsInt -> false; - NewMinorAsInt == OldMinorAsInt -> NewPatchAsInt > OldPatchAsInt - end - end; - - -greater_than(NewVersion, OldVersion) -> NewVersion > OldVersion. + NewMajorAsInt > OldMajorAsInt -> true; + NewMajorAsInt < OldMajorAsInt -> false; + NewMajorAsInt == OldMajorAsInt -> + if + NewMinorAsInt > OldMinorAsInt -> true; + NewMinorAsInt < OldMinorAsInt -> false; + NewMinorAsInt == OldMinorAsInt -> NewPatchAsInt > OldPatchAsInt + end + end; + false -> NewVersion > OldVersion + end. exec_2(Map, State, NewRelVsn) -> lists:foreach(fun({_AppName, #{appup_path := Path, diff --git a/src/relflow_state.erl b/src/relflow_state.erl index 8399689..dcc5967 100644 --- a/src/relflow_state.erl +++ b/src/relflow_state.erl @@ -20,6 +20,7 @@ profile/1, force/1, autogit/1, + semver/1, rebar_state/1, nextver/1, set_default_nextver/2, @@ -45,6 +46,8 @@ upfrom(State) -> parg(upfrom, State). autogit(State) -> parg(autogit, State) == true. +semver(State) -> parg(semver, State) == true. + profile(State) -> lists:last(filename:split(build_dir(State))). nextappver(#relflow_st{nextappver=V}) -> V. From 2f7997e496ef7806a272642d1fde907f94ea18c5 Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Thu, 14 Sep 2017 11:32:55 -0300 Subject: [PATCH 4/7] Uses tokens --- src/relflow.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/relflow.erl b/src/relflow.erl index 2af8c41..a8fef38 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -163,8 +163,8 @@ exec_1(Map, State, Next) -> greater_than(NewVersion, OldVersion, State) -> case relflow_state:semver(State) of true -> - [NewMajor, NewMinor, NewPatch] = string:split(NewVersion, "."), - [OldMajor, OldMinor, OldPatch] = string:split(OldVersion, "."), + [NewMajor, NewMinor, NewPatch] = string:tokens(NewVersion, "."), + [OldMajor, OldMinor, OldPatch] = string:tokens(OldVersion, "."), NewMajorAsInt = string:to_integer(NewMajor), NewMinorAsInt = string:to_integer(NewMinor), NewPatchAsInt = string:to_integer(NewPatch), From b271df66af701333830f54ad86627ee6a514e8da Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Thu, 14 Sep 2017 12:34:35 -0300 Subject: [PATCH 5/7] Defaults to false --- src/relflow.erl | 346 ++++++++++++++++++++++++------------------------ 1 file changed, 173 insertions(+), 173 deletions(-) diff --git a/src/relflow.erl b/src/relflow.erl index a8fef38..134e54e 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -12,225 +12,225 @@ %% =================================================================== -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(State) -> - Provider = providers:create([ - {name, ?PROVIDER}, % The 'user friendly' name of the task - {module, ?MODULE}, % The module implementation of the task - {bare, true}, % The task can be run by the user, always true - {deps, ?DEPS}, % The list of dependencies - {example, "rebar3 relflow"}, % How to use the plugin - {opts, opts()}, % list of options understood by the plugin - {short_desc, "release workflow util"}, - {desc, desc()} - ]), - {ok, rebar_state:add_provider(State, Provider)}. + Provider = providers:create([ + {name, ?PROVIDER}, % The 'user friendly' name of the task + {module, ?MODULE}, % The module implementation of the task + {bare, true}, % The task can be run by the user, always true + {deps, ?DEPS}, % The list of dependencies + {example, "rebar3 relflow"}, % How to use the plugin + {opts, opts()}, % list of options understood by the plugin + {short_desc, "release workflow util"}, + {desc, desc()} + ]), + {ok, rebar_state:add_provider(State, Provider)}. desc() -> " Relflow ======= Examples: - rebar3 relflow -u v1.2.3 # upgrade from last release, at git tag v1.2.3 - rebar3 relflow init-versions # reset all vsns using relflow format - rebar3 relflow --version # print relflow version + rebar3 relflow -u v1.2.3 # upgrade from last release, at git tag v1.2.3 + rebar3 relflow init-versions # reset all vsns using relflow format + rebar3 relflow --version # print relflow version ". opts() -> - [ - {upfrom, $u, "upfrom", string, - "Git revision/tag to upgrade from (for appup generation)"}, - {nextver, $x, "nextversion", {string, "auto"}, - "The version string to use for the next release"}, - {autogit, $g, "autogit", {boolean, true}, - "Automatically add and commit relflow changes to git"}, - {force, $f, "force", {boolean, false}, - "Force relflow to run even with uncommitted local changes"}, - {version, $v, "version", undefined, - "Print relflow version and exit"}, - {semver, $s, "semver", {boolean, true}, - "Uses semantic versioning to compare versions"} - ]. + [ + {upfrom, $u, "upfrom", string, + "Git revision/tag to upgrade from (for appup generation)"}, + {nextver, $x, "nextversion", {string, "auto"}, + "The version string to use for the next release"}, + {autogit, $g, "autogit", {boolean, true}, + "Automatically add and commit relflow changes to git"}, + {force, $f, "force", {boolean, false}, + "Force relflow to run even with uncommitted local changes"}, + {version, $v, "version", undefined, + "Print relflow version and exit"}, + {semver, $s, "semver", {boolean, false}, + "Uses semantic versioning to compare versions"} + ]. relflow_version() -> - {ok, V} = application:get_key(relflow, vsn), - V. + {ok, V} = application:get_key(relflow, vsn), + V. do(RebarState) -> - Time = utctime(), - State0 = relflow_state:set_default_nextver(new_rel_vsn(Time), - relflow_state:nextappver(new_app_vsn(Time), - relflow_state:new(RebarState))), - - case relflow_state:version(State0) of - undefined -> - do_0(State0); - _ -> - io:format("~s\n",[relflow_version()]), - {ok, RebarState} - end. + Time = utctime(), + State0 = relflow_state:set_default_nextver(new_rel_vsn(Time), + relflow_state:nextappver(new_app_vsn(Time), + relflow_state:new(RebarState))), + + case relflow_state:version(State0) of + undefined -> + do_0(State0); + _ -> + io:format("~s\n",[relflow_version()]), + {ok, RebarState} + end. do_0(State) -> - case relflow_state:task(State) of - undefined -> - do_1(State); - "init-versions" -> - do_init_versions(State) - end. + case relflow_state:task(State) of + undefined -> + do_1(State); + "init-versions" -> + do_init_versions(State) + end. do_1(State0) -> - case relflow_state:upfrom(State0) of - undefined -> - ?PRV_ERROR(no_upfrom); - Rev -> - OldRelVer = relflow_git:relver_at(Rev), - State = relflow_state:oldrelver(OldRelVer, State0), - do_2(State) - end. + case relflow_state:upfrom(State0) of + undefined -> + ?PRV_ERROR(no_upfrom); + Rev -> + OldRelVer = relflow_git:relver_at(Rev), + State = relflow_state:oldrelver(OldRelVer, State0), + do_2(State) + end. do_2(State) -> - rebar_api:debug("relflow upgrading from release ~s to ~s",[ - relflow_state:oldrelver(State), - relflow_state:nextver(State)]), - rebar_api:debug("bumped applications will use vsn: ~s", [ - relflow_state:nextappver(State)]), - ChangesSinceRev = relflow_git:since(relflow_state:upfrom(State)), - ChangeMap = relflow_appup:generate_appups(ChangesSinceRev, State), - exec(ChangeMap, State, fun(A,B) -> exec_1(A,B,fun exec_2/3) end). + rebar_api:debug("relflow upgrading from release ~s to ~s",[ + relflow_state:oldrelver(State), + relflow_state:nextver(State)]), + rebar_api:debug("bumped applications will use vsn: ~s", [ + relflow_state:nextappver(State)]), + ChangesSinceRev = relflow_git:since(relflow_state:upfrom(State)), + ChangeMap = relflow_appup:generate_appups(ChangesSinceRev, State), + exec(ChangeMap, State, fun(A,B) -> exec_1(A,B,fun exec_2/3) end). do_init_versions(State0) -> - NextAppVer = relflow_state:nextappver(State0), - rebar_api:info("New application vsn: ~s", [NextAppVer]), - BumperFun = fun(_Map, State, NewRelVsn) -> - Apps = [ {rebar_app_info:name(A), rebar_app_info:app_file_src(A)} - || A <- rebar_state:project_apps(relflow_state:rebar_state(State0)) - ], - lists:foreach(fun({_AppName, AppFile}) -> - %rebar_api:info("Setting app vsn in ~s to ~s", [AppName, NextAppVer]), - ok = relflow_rewriter:set_appfile_version(AppFile, NextAppVer) - end, Apps), - rebar_api:info("Setting release vsn in rebar.config to ~s", [NewRelVsn]), - case relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn) of - {error, ErrReason} -> - ?PRV_ERROR(ErrReason); - _ -> - rebar_api:info("You are advised to commit and tag this as '~s'",[NewRelVsn]), - {ok, relflow_state:rebar_state(State)} - end - end, - Changes = #{}, - exec(Changes, State0, fun(A,B) -> exec_1(A,B,BumperFun) end). + NextAppVer = relflow_state:nextappver(State0), + rebar_api:info("New application vsn: ~s", [NextAppVer]), + BumperFun = fun(_Map, State, NewRelVsn) -> + Apps = [ {rebar_app_info:name(A), rebar_app_info:app_file_src(A)} + || A <- rebar_state:project_apps(relflow_state:rebar_state(State0)) + ], + lists:foreach(fun({_AppName, AppFile}) -> + %rebar_api:info("Setting app vsn in ~s to ~s", [AppName, NextAppVer]), + ok = relflow_rewriter:set_appfile_version(AppFile, NextAppVer) + end, Apps), + rebar_api:info("Setting release vsn in rebar.config to ~s", [NewRelVsn]), + case relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn) of + {error, ErrReason} -> + ?PRV_ERROR(ErrReason); + _ -> + rebar_api:info("You are advised to commit and tag this as '~s'",[NewRelVsn]), + {ok, relflow_state:rebar_state(State)} + end + end, + Changes = #{}, + exec(Changes, State0, fun(A,B) -> exec_1(A,B,BumperFun) end). format_error(relflow_marker_missing) -> - "You must have a '%% relflow-release-version-marker' line in rebar.config\n " ++ - "See the README at github.com/RJ/relflow"; + "You must have a '%% relflow-release-version-marker' line in rebar.config\n " ++ + "See the README at github.com/RJ/relflow"; format_error(unclean_git) -> - "Relflow modifies files in-place. Will not run with uncommitted changes."; + "Relflow modifies files in-place. Will not run with uncommitted changes."; format_error(no_upfrom) -> - "Missing git revision to upgrade from, eg: rebar3 relflow -u abc123\n " ++ - "(or try: rebar3 help relflow)"; + "Missing git revision to upgrade from, eg: rebar3 relflow -u abc123\n " ++ + "(or try: rebar3 help relflow)"; format_error({relvsn_ordering, Old, New}) -> - io_lib:format("New release vsn is less than old! (new:~s < old:~s)", [New, Old]); + io_lib:format("New release vsn is less than old! (new:~s < old:~s)", [New, Old]); format_error(Reason) -> - io_lib:format("Unhandled relflow error: ~p", [Reason]). + io_lib:format("Unhandled relflow error: ~p", [Reason]). utctime() -> erlang:localtime_to_universaltime(erlang:localtime()). new_rel_vsn({{Year,Month,Day},{Hour,Min,Sec}}) -> - lists:flatten( - io_lib:format("~4.10.0B~2.10.0B~2.10.0B.~2.10.0B~2.10.0B~2.10.0B", - [Year, Month, Day, Hour, Min, Sec])). + lists:flatten( + io_lib:format("~4.10.0B~2.10.0B~2.10.0B.~2.10.0B~2.10.0B~2.10.0B", + [Year, Month, Day, Hour, Min, Sec])). new_app_vsn({{Year,Month,Day},{Hour,Min,Sec}}) -> - lists:flatten( - io_lib:format("~4.10.0B~2.10.0B~2.10.0B-~2.10.0B~2.10.0B~2.10.0B-relflow", - [Year, Month, Day, Hour, Min, Sec])). + lists:flatten( + io_lib:format("~4.10.0B~2.10.0B~2.10.0B-~2.10.0B~2.10.0B~2.10.0B-relflow", + [Year, Month, Day, Hour, Min, Sec])). exec(Map, State, Next) -> - case relflow_state:force(State) orelse relflow_git:is_clean() of - true -> Next(Map, State); - false -> ?PRV_ERROR(unclean_git) - end. + case relflow_state:force(State) orelse relflow_git:is_clean() of + true -> Next(Map, State); + false -> ?PRV_ERROR(unclean_git) + end. exec_1(Map, State, Next) -> - NewRelVsn = relflow_state:nextver(State), - OldRelVsn = relflow_state:oldrelver(State), - case greater_than(NewRelVsn, OldRelVsn, State) of - true -> Next(Map, State, NewRelVsn); - false -> ?PRV_ERROR({relvsn_ordering, OldRelVsn, NewRelVsn}) - end. + NewRelVsn = relflow_state:nextver(State), + OldRelVsn = relflow_state:oldrelver(State), + case greater_than(NewRelVsn, OldRelVsn, State) of + true -> Next(Map, State, NewRelVsn); + false -> ?PRV_ERROR({relvsn_ordering, OldRelVsn, NewRelVsn}) + end. greater_than(NewVersion, OldVersion, State) -> - case relflow_state:semver(State) of - true -> - [NewMajor, NewMinor, NewPatch] = string:tokens(NewVersion, "."), - [OldMajor, OldMinor, OldPatch] = string:tokens(OldVersion, "."), - NewMajorAsInt = string:to_integer(NewMajor), - NewMinorAsInt = string:to_integer(NewMinor), - NewPatchAsInt = string:to_integer(NewPatch), - OldMajorAsInt = string:to_integer(OldMajor), - OldMinorAsInt = string:to_integer(OldMinor), - OldPatchAsInt = string:to_integer(OldPatch), - if - NewMajorAsInt > OldMajorAsInt -> true; - NewMajorAsInt < OldMajorAsInt -> false; - NewMajorAsInt == OldMajorAsInt -> - if - NewMinorAsInt > OldMinorAsInt -> true; - NewMinorAsInt < OldMinorAsInt -> false; - NewMinorAsInt == OldMinorAsInt -> NewPatchAsInt > OldPatchAsInt - end - end; - false -> NewVersion > OldVersion - end. + case relflow_state:semver(State) of + true -> + [NewMajor, NewMinor, NewPatch] = string:tokens(NewVersion, "."), + [OldMajor, OldMinor, OldPatch] = string:tokens(OldVersion, "."), + NewMajorAsInt = string:to_integer(NewMajor), + NewMinorAsInt = string:to_integer(NewMinor), + NewPatchAsInt = string:to_integer(NewPatch), + OldMajorAsInt = string:to_integer(OldMajor), + OldMinorAsInt = string:to_integer(OldMinor), + OldPatchAsInt = string:to_integer(OldPatch), + if + NewMajorAsInt > OldMajorAsInt -> true; + NewMajorAsInt < OldMajorAsInt -> false; + NewMajorAsInt == OldMajorAsInt -> + if + NewMinorAsInt > OldMinorAsInt -> true; + NewMinorAsInt < OldMinorAsInt -> false; + NewMinorAsInt == OldMinorAsInt -> NewPatchAsInt > OldPatchAsInt + end + end; + false -> NewVersion > OldVersion + end. exec_2(Map, State, NewRelVsn) -> - lists:foreach(fun({_AppName, #{appup_path := Path, - appup_term := T, - appsrc_path := AppSrc, - next_vsn := NextVsn}}) -> - rebar_api:info("Replace ~s",[Path]), - Contents = io_lib:format("~p.",[T]), - ok = filelib:ensure_dir(Path), - ok = file:write_file(Path, Contents), - %rebar_api:info("Bumping version in ~s", [AppSrc]), - ok = relflow_rewriter:set_appfile_version(AppSrc, NextVsn) - end, maps:to_list(Map)), - rebar_api:info("Rewriting release vsn in rebar.config: ~s", [NewRelVsn]), - relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn), - %% print summary - FilesTouched = lists:foldl( - fun(#{appup_path := F1, appsrc_path := F2}, Acc) -> - [F1, F2 | Acc] - end, ["rebar.config"], maps:values(Map)), - - %% git things - GitAddCmds = [ fmt("git add ~s", [AddFile]) || AddFile <- FilesTouched ], - GitCmds = GitAddCmds ++ [ - %fmt("git add ~s", [string:join(FilesTouched, " ")]), - fmt("git commit -m\"relflow ~s --> ~s\"", [relflow_state:oldrelver(State), NewRelVsn]), - fmt("git tag -a \"v~s\" -m \"~s\"", [NewRelVsn, NewRelVsn]) - ], - case {relflow_state:autogit(State), relflow_state:force(State)} of - {true, false} -> exec_git(GitCmds); - {false, true} -> exec_git(GitCmds); - {false, false} -> print_git(GitCmds); - {true, true} -> - rebar_api:warn("Not running git commands, because you --forced",[]), - print_git(GitCmds) - end, - {ok, relflow_state:rebar_state(State)}. + lists:foreach(fun({_AppName, #{appup_path := Path, + appup_term := T, + appsrc_path := AppSrc, + next_vsn := NextVsn}}) -> + rebar_api:info("Replace ~s",[Path]), + Contents = io_lib:format("~p.",[T]), + ok = filelib:ensure_dir(Path), + ok = file:write_file(Path, Contents), + %rebar_api:info("Bumping version in ~s", [AppSrc]), + ok = relflow_rewriter:set_appfile_version(AppSrc, NextVsn) + end, maps:to_list(Map)), + rebar_api:info("Rewriting release vsn in rebar.config: ~s", [NewRelVsn]), + relflow_rewriter:set_rebar_relx_version("rebar.config", NewRelVsn), + %% print summary + FilesTouched = lists:foldl( + fun(#{appup_path := F1, appsrc_path := F2}, Acc) -> + [F1, F2 | Acc] + end, ["rebar.config"], maps:values(Map)), + + %% git things + GitAddCmds = [ fmt("git add ~s", [AddFile]) || AddFile <- FilesTouched ], + GitCmds = GitAddCmds ++ [ + %fmt("git add ~s", [string:join(FilesTouched, " ")]), + fmt("git commit -m\"relflow ~s --> ~s\"", [relflow_state:oldrelver(State), NewRelVsn]), + fmt("git tag -a \"v~s\" -m \"~s\"", [NewRelVsn, NewRelVsn]) + ], + case {relflow_state:autogit(State), relflow_state:force(State)} of + {true, false} -> exec_git(GitCmds); + {false, true} -> exec_git(GitCmds); + {false, false} -> print_git(GitCmds); + {true, true} -> + rebar_api:warn("Not running git commands, because you --forced",[]), + print_git(GitCmds) + end, + {ok, relflow_state:rebar_state(State)}. exec_git(Cmds) -> - lists:foreach(fun(Cmd) -> - case os:cmd(Cmd) of - "" -> rebar_api:info("$ ~s", [Cmd]); - Res -> rebar_api:info("$ ~s\n~s", [Cmd, string:strip(Res, right)]) - end - end, Cmds). + lists:foreach(fun(Cmd) -> + case os:cmd(Cmd) of + "" -> rebar_api:info("$ ~s", [Cmd]); + Res -> rebar_api:info("$ ~s\n~s", [Cmd, string:strip(Res, right)]) + end + end, Cmds). print_git(Cmds) -> - S = iolist_to_binary([ [C, "\n"] || C <- Cmds ]), - rebar_api:info("Recommended git commands:\n~s", [S]). + S = iolist_to_binary([ [C, "\n"] || C <- Cmds ]), + rebar_api:info("Recommended git commands:\n~s", [S]). fmt(S,A) -> lists:flatten(io_lib:format(S,A)). From 05ae5808545386118e2f0e1a0252f3e5ed0a883a Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Thu, 14 Sep 2017 12:45:43 -0300 Subject: [PATCH 6/7] Improves readability --- src/relflow.erl | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/relflow.erl b/src/relflow.erl index 134e54e..8c08f15 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -155,34 +155,26 @@ exec(Map, State, Next) -> exec_1(Map, State, Next) -> NewRelVsn = relflow_state:nextver(State), OldRelVsn = relflow_state:oldrelver(State), - case greater_than(NewRelVsn, OldRelVsn, State) of + case greater_than(NewRelVsn, OldRelVsn, relflow_state:semver(State)) of true -> Next(Map, State, NewRelVsn); false -> ?PRV_ERROR({relvsn_ordering, OldRelVsn, NewRelVsn}) end. -greater_than(NewVersion, OldVersion, State) -> - case relflow_state:semver(State) of - true -> - [NewMajor, NewMinor, NewPatch] = string:tokens(NewVersion, "."), - [OldMajor, OldMinor, OldPatch] = string:tokens(OldVersion, "."), - NewMajorAsInt = string:to_integer(NewMajor), - NewMinorAsInt = string:to_integer(NewMinor), - NewPatchAsInt = string:to_integer(NewPatch), - OldMajorAsInt = string:to_integer(OldMajor), - OldMinorAsInt = string:to_integer(OldMinor), - OldPatchAsInt = string:to_integer(OldPatch), +greater_than(NewVersion, OldVersion, true) -> + [NewMajor, NewMinor, NewPatch] = lists:map(fun string:to_integer/1, string:tokens(NewVersion, ".")), + [OldMajor, OldMinor, OldPatch] = lists:map(fun string:to_integer/1, string:tokens(OldVersion, ".")), + if + NewMajor > OldMajor -> true; + NewMajor < OldMajor -> false; + NewMajor == OldMajor -> if - NewMajorAsInt > OldMajorAsInt -> true; - NewMajorAsInt < OldMajorAsInt -> false; - NewMajorAsInt == OldMajorAsInt -> - if - NewMinorAsInt > OldMinorAsInt -> true; - NewMinorAsInt < OldMinorAsInt -> false; - NewMinorAsInt == OldMinorAsInt -> NewPatchAsInt > OldPatchAsInt - end - end; - false -> NewVersion > OldVersion - end. + NewMinor > OldMinor -> true; + NewMinor < OldMinor -> false; + NewMinor == OldMinor -> NewPatch > OldPatch + end + end; +greater_than(NewVersion, OldVersion, _UsingSemanticVersion) -> NewVersion > OldVersion. + exec_2(Map, State, NewRelVsn) -> lists:foreach(fun({_AppName, #{appup_path := Path, From 3cd01bf8ba0d1d3620781328cbc9dce095e7aed1 Mon Sep 17 00:00:00 2001 From: Leonardo Wolter Date: Thu, 14 Sep 2017 12:56:08 -0300 Subject: [PATCH 7/7] Adds the new flag to readme --- README.md | 5 +++-- src/relflow.erl | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a651b83..cff44d0 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Help Usage: rebar3 relflow [-u ] [-x []] [-g []] - [-f []] + [-f []] [-s [semver]] -u, --upfrom Git revision/tag to upgrade from (for appup generation) @@ -144,9 +144,10 @@ Help [default: true] -f, --force Force relflow to run even with uncommitted local changes [default: false] + -s, --semver Compare the versions as semantic versions (0.0.9 < 0.0.10) + [default: false] -v, --version Print relflow version and exit - License ------- diff --git a/src/relflow.erl b/src/relflow.erl index 8c08f15..4cb4558 100644 --- a/src/relflow.erl +++ b/src/relflow.erl @@ -173,7 +173,7 @@ greater_than(NewVersion, OldVersion, true) -> NewMinor == OldMinor -> NewPatch > OldPatch end end; -greater_than(NewVersion, OldVersion, _UsingSemanticVersion) -> NewVersion > OldVersion. +greater_than(NewVersion, OldVersion, false) -> NewVersion > OldVersion. exec_2(Map, State, NewRelVsn) ->