From 137dc8cda65eb565db0bae5b1c8c30e466a28d44 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Mon, 11 Feb 2019 15:51:16 +0200 Subject: [PATCH 1/8] Allow seperate app versioning --- lib/eliver.ex | 1 + lib/eliver/git.ex | 48 +++++++++++- lib/eliver/multiple.ex | 11 +++ lib/mix/tasks/eliver.bump.ex | 141 ++++++++++++++++++++++++++++------- 4 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 lib/eliver/multiple.ex diff --git a/lib/eliver.ex b/lib/eliver.ex index 29908d9..b600ec8 100644 --- a/lib/eliver.ex +++ b/lib/eliver.ex @@ -3,6 +3,7 @@ defmodule Eliver do def next_version(version_number, bump_type) do [major, minor, patch] = String.split(version_number, ".") |> Enum.map(&String.to_integer/1) case bump_type do + :none -> version_number :major -> [major + 1, 0, 0] :minor -> [major, minor + 1, 0] :patch -> [major, minor, patch + 1] diff --git a/lib/eliver/git.ex b/lib/eliver/git.ex index 143fad5..34f13c9 100644 --- a/lib/eliver/git.ex +++ b/lib/eliver/git.ex @@ -41,6 +41,30 @@ defmodule Eliver.Git do git "tag", ["#{new_version}", "-a", "-m", "Version: #{new_version}"] end + def commit!(commit_changes) do + for change <- commit_changes do + git "add", "#{elem(change, 1)}/CHANGELOG.md" + git "add", "#{elem(change, 1)}/VERSION" + end + + umbrella_changes = Enum.find(commit_changes, + fn({app, app_path, current_version, new_version, changelog_entries}) -> + app == :umbrella + end + ) + app_changes = List.delete(commit_changes, umbrella_changes) + + git "commit", ["-m", aggregated_commit_message(umbrella_changes, app_changes)] + + for {app, app_path, _current_version, new_version, changelog_entries} <- commit_changes do + if app == :umbrella do + git "tag", ["#{new_version}", "-a", "-m", "Version: #{new_version}"] + else + git "tag", ["#{app_path}/#{new_version}", "-a", "-m", "Version(#{Atom.to_string(app)}): #{new_version}"] + end + end + end + def push!(new_version) do git "push", ["-q", "origin", current_branch(), new_version] end @@ -65,13 +89,33 @@ defmodule Eliver.Git do String.replace_trailing(str, "\n", "") end - defp commit_message(new_version, changelog_entries) do + def commit_message(new_version, changelog_entries) do """ Version #{new_version}: #{Enum.map(changelog_entries, fn(x) -> "* " <> x end) |> Enum.join("\n")} """ end + defp aggregated_commit_message(umbrella_changes, app_changes) do + """ +Version #{elem(umbrella_changes, 3)}: + +#{Enum.map(elem(umbrella_changes, 4), fn(x) -> "* " <> x end) |> Enum.join("\n")} +Nested Changes: + #{Enum.flat_map(app_changes, fn(app_change) -> + [nested_commit_version(elem(app_change, 1), elem(app_change, 3))] + ++ + nested_commit_messages(elem(umbrella_changes, 4)) + end) |> Enum.join("\n")} + """ + end + + defp nested_commit_version(app, version) do + "\t#{app} - #{version}" + end + defp nested_commit_messages(change_strings) do + Enum.map(change_strings, fn(change_string) -> "\t\t" <> change_string end) + end -end \ No newline at end of file +end diff --git a/lib/eliver/multiple.ex b/lib/eliver/multiple.ex new file mode 100644 index 0000000..eec5611 --- /dev/null +++ b/lib/eliver/multiple.ex @@ -0,0 +1,11 @@ +defmodule Eliver.Multiple do + + def list_sub_apps() do + Mix.Project.apps_paths() |> IO.inspect() + |> case do + nil -> {:error, :unknown_app_structure} + sub_apps -> {:ok, sub_apps} + end + end + +end diff --git a/lib/mix/tasks/eliver.bump.ex b/lib/mix/tasks/eliver.bump.ex index 22a3b1d..6849ef1 100644 --- a/lib/mix/tasks/eliver.bump.ex +++ b/lib/mix/tasks/eliver.bump.ex @@ -6,29 +6,81 @@ defmodule Mix.Tasks.Eliver.Bump do args |> parse_args |> bump end - defp bump(_) do + defp bump(args) do case check_for_git_problems() do {:error, message} -> say message, :red {:ok} -> - {new_version, changelog_entries} = get_changes() - if allow_changes?(new_version, changelog_entries) do - make_changes(new_version, changelog_entries) + do_bump(args) + end + end + + defp do_bump(args) do + case Keyword.get(args, :multi) do + true -> bump_multiple() + nil -> bump_normal() + end + end + + defp bump_multiple() do + Eliver.Multiple.list_sub_apps() + |> case do + {:ok, sub_apps} -> + sub_apps = Map.put(sub_apps, :umbrella, ".") + + changes = Enum.map(sub_apps, fn({app, app_path}) -> + + say "\n\n==============================================" + say "Bump details for #{Atom.to_string(app)}" + say "==============================================" + + {current_version, new_version, changelog_entries} = get_changes(app_path, :multi) + + {app, app_path, current_version, new_version, changelog_entries} + end) |> IO.inspect() + + if allow_changes?(changes) do + make_changes(changes) end + + {:error, :unknown_app_structure} -> + say "Please note that only standard umbrella app directory structures are supported. Please refer to the documentation for details", :red + end + end + defp bump_normal() do + {current_version, new_version, changelog_entries} = get_changes() + if allow_changes?(new_version, changelog_entries) do + make_changes(new_version, changelog_entries) end end - defp get_changes do - {get_new_version(), get_changelog_entries()} + defp get_changes(root_for_changes \\ ".", bump_type \\ :normal) do + {current_version, new_version} = get_new_version(root_for_changes, bump_type) + {current_version, new_version, get_changelog_entries()} end + defp allow_changes?(changes) when is_list(changes) do + say "\n" + say "==============================================" + say "Summary of changes:" + say "==============================================" + + Enum.each(changes, fn(app_changes) -> + display_change(app_changes) + end) + + say "\n" + result = ask "Continue?", false + case result do + {:ok, value} -> value + {:error, _} -> false + end + end defp allow_changes?(new_version, changelog_entries) do current_version = Eliver.VersionFile.version say "\n" say "Summary of changes:" - say "Bumping version #{current_version} → #{new_version}", :green - say ("#{Enum.map(changelog_entries, fn(x) -> "* " <> x end) |> Enum.join("\n")}"), :green - say "\n" + display_change(current_version, new_version, changelog_entries) result = ask "Continue?", false case result do {:ok, value} -> value @@ -36,6 +88,28 @@ defmodule Mix.Tasks.Eliver.Bump do end end + defp display_change({app, app_path, current_version, new_version, changelog_entries}) do + say "\n#{Atom.to_string(app)} (#{app_path})" + say "==============================================" + display_change(current_version, new_version, changelog_entries) + end + defp display_change(current_version, new_version, changelog_entries) do + say "Bumping version #{current_version} → #{new_version}", :green + say ("#{Enum.map(changelog_entries, fn(x) -> "* " <> x end) |> Enum.join("\n")}"), :green + say "\n" + end + + defp make_changes(changes) when is_list(changes) do + for {app, app_path, current_version, new_version, changelog_entries} <- changes do + Eliver.VersionFile.bump(new_version, "#{app_path}/VERSION") + Eliver.ChangeLogFile.bump(new_version, changelog_entries, "#{app_path}/CHANGELOG.md") + end + + Eliver.Git.commit!(changes) + say "Pushing to origin..." + Eliver.Git.push!(Eliver.VersionFile.version()) + end + defp make_changes(new_version, changelog_entries) do Eliver.VersionFile.bump(new_version) Eliver.ChangeLogFile.bump(new_version, changelog_entries) @@ -45,18 +119,18 @@ defmodule Mix.Tasks.Eliver.Bump do end defp check_for_git_problems do - cond do - !Eliver.Git.is_tracking_branch? -> - {:error, "This branch is not tracking a remote branch. Aborting..."} - !Eliver.Git.on_master? && !continue_on_branch?() -> - {:error, "Aborting"} - Eliver.Git.index_dirty? -> - {:error, "Git index dirty. Commit changes before continuing"} - Eliver.Git.fetch! && Eliver.Git.upstream_changes? -> - {:error, "This branch is not up to date with upstream"} - true -> + # cond do + # !Eliver.Git.is_tracking_branch? -> + # {:error, "This branch is not tracking a remote branch. Aborting..."} + # !Eliver.Git.on_master? && !continue_on_branch?() -> + # {:error, "Aborting"} + # Eliver.Git.index_dirty? -> + # {:error, "Git index dirty. Commit changes before continuing"} + # Eliver.Git.fetch! && Eliver.Git.upstream_changes? -> + # {:error, "This branch is not up to date with upstream"} + # true -> {:ok} - end + # end end defp continue_on_branch? do @@ -68,8 +142,11 @@ defmodule Mix.Tasks.Eliver.Bump do end end - defp get_new_version do - Eliver.VersionFile.version |> Eliver.next_version(get_bump_type()) + defp get_new_version(dir, type) do + { + Eliver.VersionFile.version("#{dir}/VERSION"), + Eliver.VersionFile.version("#{dir}/VERSION") |> Eliver.next_version(get_bump_type(type)) + } end defp get_changelog_entries do @@ -77,7 +154,21 @@ defmodule Mix.Tasks.Eliver.Bump do result end - defp get_bump_type do + defp get_bump_type(:multi) do + result = choose "Select release type", + patch: "Bug fixes, recommended for all", + minor: "New features, but backwards compatible", + major: "Breaking changes", + none: "None", + default: :none + + case result do + {:ok, value} -> value + {:error, _} -> get_bump_type(:multi) + end + end + + defp get_bump_type(:normal) do result = choose "Select release type", patch: "Bug fixes, recommended for all", minor: "New features, but backwards compatible", @@ -86,12 +177,12 @@ defmodule Mix.Tasks.Eliver.Bump do case result do {:ok, value} -> value - {:error, _} -> get_bump_type() + {:error, _} -> get_bump_type(:normal) end end defp parse_args(args) do - {_, args, _} = OptionParser.parse(args) + {args, _, _} = OptionParser.parse(args) args end end From 44c1fa7edea35fce3315cd3bff2a15076a79f294 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Mon, 11 Feb 2019 16:30:30 +0200 Subject: [PATCH 2/8] Add soe notes --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 19357ae..fa123ed 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,27 @@ end version: String.trim(File.read!("VERSION")), ``` -## Usage +## Usage - Normal Apps ```bash $ mix eliver.bump ``` +## Usage - Umbrella Apps + +In umbrella apps there are two supported use-cases: + + 1. A single version file is provided, with all sub-apps sharing the same version number. + 2. Sub-app versions are managed seperately. In this case, each app has a seperate `VERSION` and `CHANGELOG.md` file. + + For option 1, eliver is used in the same manner as for normal Elixir apps. + + For option 2, eliver provides a `--multi` flag. + +```bash +$ mix eliver.bump --multi +``` + ## Contributing Please do. From 76be5c8cdda5af341ed10ce768b20cd93b70b1f2 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Mon, 11 Feb 2019 16:31:50 +0200 Subject: [PATCH 3/8] Handle empty change definitions correctly --- lib/eliver.ex | 2 +- lib/eliver/git.ex | 9 ++++++++- lib/mix/tasks/eliver.bump.ex | 28 +++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/eliver.ex b/lib/eliver.ex index b600ec8..8e9ee7a 100644 --- a/lib/eliver.ex +++ b/lib/eliver.ex @@ -3,7 +3,7 @@ defmodule Eliver do def next_version(version_number, bump_type) do [major, minor, patch] = String.split(version_number, ".") |> Enum.map(&String.to_integer/1) case bump_type do - :none -> version_number + :none -> [major, minor, patch] :major -> [major + 1, 0, 0] :minor -> [major, minor + 1, 0] :patch -> [major, minor, patch + 1] diff --git a/lib/eliver/git.ex b/lib/eliver/git.ex index 34f13c9..22e0f75 100644 --- a/lib/eliver/git.ex +++ b/lib/eliver/git.ex @@ -96,7 +96,7 @@ Version #{new_version}: #{Enum.map(changelog_entries, fn(x) -> "* " <> x end) |> Enum.join("\n")} """ end - defp aggregated_commit_message(umbrella_changes, app_changes) do + defp aggregated_commit_message(umbrella_changes, app_changes) when not is_nil(app_changes) do """ Version #{elem(umbrella_changes, 3)}: @@ -110,6 +110,13 @@ Nested Changes: end) |> Enum.join("\n")} """ end + defp aggregated_commit_message(umbrella_changes, _app_changes) do + """ +Version #{elem(umbrella_changes, 3)}: + +#{Enum.map(elem(umbrella_changes, 4), fn(x) -> "* " <> x end) |> Enum.join("\n")} + """ + end defp nested_commit_version(app, version) do "\t#{app} - #{version}" diff --git a/lib/mix/tasks/eliver.bump.ex b/lib/mix/tasks/eliver.bump.ex index 6849ef1..69d95e0 100644 --- a/lib/mix/tasks/eliver.bump.ex +++ b/lib/mix/tasks/eliver.bump.ex @@ -28,16 +28,29 @@ defmodule Mix.Tasks.Eliver.Bump do {:ok, sub_apps} -> sub_apps = Map.put(sub_apps, :umbrella, ".") - changes = Enum.map(sub_apps, fn({app, app_path}) -> + changes = Enum.map(sub_apps, fn + + {:umbrella, app_path} -> + # Note changes re required for the umbrella app + {current_version, new_version, changelog_entries} = get_changes(app_path, :normal) + {:umbrella, app_path, current_version, new_version, changelog_entries} + + {app, app_path} -> say "\n\n==============================================" say "Bump details for #{Atom.to_string(app)}" say "==============================================" - {current_version, new_version, changelog_entries} = get_changes(app_path, :multi) + get_changes(app_path, :multi) + |> case do + nil -> nil + {current_version, new_version, changelog_entries} -> + {app, app_path, current_version, new_version, changelog_entries} + end + - {app, app_path, current_version, new_version, changelog_entries} - end) |> IO.inspect() + end) + |> Enum.filter(fn(change) -> not is_nil(change) end) if allow_changes?(changes) do make_changes(changes) @@ -56,7 +69,12 @@ defmodule Mix.Tasks.Eliver.Bump do defp get_changes(root_for_changes \\ ".", bump_type \\ :normal) do {current_version, new_version} = get_new_version(root_for_changes, bump_type) - {current_version, new_version, get_changelog_entries()} + + if current_version == new_version do + nil + else + {current_version, new_version, get_changelog_entries()} + end end defp allow_changes?(changes) when is_list(changes) do From 5b13a12e28813faa80c35581b0e7494dc2f674de Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Mon, 11 Feb 2019 16:37:53 +0200 Subject: [PATCH 4/8] Cleanup --- lib/eliver/git.ex | 2 +- lib/eliver/multiple.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eliver/git.ex b/lib/eliver/git.ex index 22e0f75..02c327f 100644 --- a/lib/eliver/git.ex +++ b/lib/eliver/git.ex @@ -89,7 +89,7 @@ defmodule Eliver.Git do String.replace_trailing(str, "\n", "") end - def commit_message(new_version, changelog_entries) do + defp commit_message(new_version, changelog_entries) do """ Version #{new_version}: diff --git a/lib/eliver/multiple.ex b/lib/eliver/multiple.ex index eec5611..3a1cd50 100644 --- a/lib/eliver/multiple.ex +++ b/lib/eliver/multiple.ex @@ -1,7 +1,7 @@ defmodule Eliver.Multiple do def list_sub_apps() do - Mix.Project.apps_paths() |> IO.inspect() + Mix.Project.apps_paths() |> case do nil -> {:error, :unknown_app_structure} sub_apps -> {:ok, sub_apps} From 0961c67652889f44bbfd9f33d7a70f05d6f41626 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Mon, 11 Feb 2019 16:39:26 +0200 Subject: [PATCH 5/8] Uncomment git checks --- lib/mix/tasks/eliver.bump.ex | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/mix/tasks/eliver.bump.ex b/lib/mix/tasks/eliver.bump.ex index 69d95e0..ab8698e 100644 --- a/lib/mix/tasks/eliver.bump.ex +++ b/lib/mix/tasks/eliver.bump.ex @@ -137,18 +137,18 @@ defmodule Mix.Tasks.Eliver.Bump do end defp check_for_git_problems do - # cond do - # !Eliver.Git.is_tracking_branch? -> - # {:error, "This branch is not tracking a remote branch. Aborting..."} - # !Eliver.Git.on_master? && !continue_on_branch?() -> - # {:error, "Aborting"} - # Eliver.Git.index_dirty? -> - # {:error, "Git index dirty. Commit changes before continuing"} - # Eliver.Git.fetch! && Eliver.Git.upstream_changes? -> - # {:error, "This branch is not up to date with upstream"} - # true -> + cond do + !Eliver.Git.is_tracking_branch? -> + {:error, "This branch is not tracking a remote branch. Aborting..."} + !Eliver.Git.on_master? && !continue_on_branch?() -> + {:error, "Aborting"} + Eliver.Git.index_dirty? -> + {:error, "Git index dirty. Commit changes before continuing"} + Eliver.Git.fetch! && Eliver.Git.upstream_changes? -> + {:error, "This branch is not up to date with upstream"} + true -> {:ok} - # end + end end defp continue_on_branch? do From 89584b453ded2989634e0319a3302d99aad3c183 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Thu, 14 Feb 2019 11:46:42 +0200 Subject: [PATCH 6/8] Push multiple tags --- lib/eliver/git.ex | 12 ++++++++---- lib/mix/tasks/eliver.bump.ex | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/eliver/git.ex b/lib/eliver/git.ex index 02c327f..711a713 100644 --- a/lib/eliver/git.ex +++ b/lib/eliver/git.ex @@ -56,17 +56,21 @@ defmodule Eliver.Git do git "commit", ["-m", aggregated_commit_message(umbrella_changes, app_changes)] - for {app, app_path, _current_version, new_version, changelog_entries} <- commit_changes do + Enum.map(commit_changes, fn({app, app_path, _current_version, new_version, changelog_entries}) -> if app == :umbrella do git "tag", ["#{new_version}", "-a", "-m", "Version: #{new_version}"] + + "#{new_version}" else git "tag", ["#{app_path}/#{new_version}", "-a", "-m", "Version(#{Atom.to_string(app)}): #{new_version}"] + + "#{app_path}/#{new_version}" end - end + end) end - def push!(new_version) do - git "push", ["-q", "origin", current_branch(), new_version] + def push!(tags) do + git "push", ["-q", "origin", current_branch()] ++ tags end defp git(command, args) when is_list(args) do diff --git a/lib/mix/tasks/eliver.bump.ex b/lib/mix/tasks/eliver.bump.ex index ab8698e..a73d535 100644 --- a/lib/mix/tasks/eliver.bump.ex +++ b/lib/mix/tasks/eliver.bump.ex @@ -123,9 +123,10 @@ defmodule Mix.Tasks.Eliver.Bump do Eliver.ChangeLogFile.bump(new_version, changelog_entries, "#{app_path}/CHANGELOG.md") end - Eliver.Git.commit!(changes) + tags = Eliver.Git.commit!(changes) + say "Pushing to origin..." - Eliver.Git.push!(Eliver.VersionFile.version()) + Eliver.Git.push!(tags) end defp make_changes(new_version, changelog_entries) do From 47e14869659ba67481af99f75d711ce5290b26e9 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Thu, 14 Feb 2019 11:56:11 +0200 Subject: [PATCH 7/8] Better handling of multiple tags --- lib/eliver/git.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/eliver/git.ex b/lib/eliver/git.ex index 711a713..08ffcbe 100644 --- a/lib/eliver/git.ex +++ b/lib/eliver/git.ex @@ -69,8 +69,12 @@ defmodule Eliver.Git do end) end - def push!(tags) do - git "push", ["-q", "origin", current_branch()] ++ tags + def push!(tags) when is_list(tags) do + attributes = ["-q", "origin", current_branch()] ++ tags + git "push", attributes + end + def push!(tag) do + git "push", ["-q", "origin", current_branch(), tag] end defp git(command, args) when is_list(args) do From e9ef765771f5765187f4d51cc1381564f4baccb5 Mon Sep 17 00:00:00 2001 From: Theuns Botha Date: Fri, 15 Feb 2019 08:38:14 +0200 Subject: [PATCH 8/8] Use correct nested change descriptions --- lib/eliver/git.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eliver/git.ex b/lib/eliver/git.ex index 08ffcbe..6abfa32 100644 --- a/lib/eliver/git.ex +++ b/lib/eliver/git.ex @@ -114,7 +114,7 @@ Nested Changes: #{Enum.flat_map(app_changes, fn(app_change) -> [nested_commit_version(elem(app_change, 1), elem(app_change, 3))] ++ - nested_commit_messages(elem(umbrella_changes, 4)) + nested_commit_messages(elem(app_change, 4)) end) |> Enum.join("\n")} """ end