Skip to content
This repository has been archived by the owner on Jun 30, 2021. It is now read-only.

Commit

Permalink
Prepare commands and docs for v1.1.0 release (#733)
Browse files Browse the repository at this point in the history
* Add upgrade instructions

* Add license headers

* Split release tasks into separate modules

* Add config migration

* Use the release command instead of mix in upgrade docs

* Add --settings to release task's seed

* Refactor release tasks to use unified puts functions

* Start required applications that are missing from the release tasks

* Add `ewallet config --migrate` command

* Fix missing originator for config migration

* Add support for -y, --yes, --assume_yes to config release task

* Fix release tasks failing silently when an unknown argument is given

* Refactor IO puts functions into EWallet.CLI

* Mirror `bin/ewallet config` into `mix omg.config`

* DEBUG=1 to show :debug log and above

* Fix `mix config --migrate` stopped at seeding and not respecting --yes

* Show mix task docs instead of invalid arguments message

* Add -- shift to initdb and seed

* Update mix omg.config docs

* Minor upgrade notes improvements

* Ain't no push without mix formatting

* Nope nope can't go without credo too

* Add missing mix task shortdoc

* Add a glossary for eWallet Suite and eWallet Server

* Update EWallet.CLI.confirm?/1 to use Helper.to_boolean/1 to parse the answer.

* Refactor set/migration conditions in config.sh

* Decouple ReleaseTasks.ConfigMigration from ReleaseTasks.Seed

* Shellcheck

* Remove seed from config.sh as it's already done as part of the release task

* Add message during seed-migration dead air

* Fix CLI.confirm?/1 not respecting the default value

* Fix shell script styling

* Remove default fallback for confirmed?/2, risky assumption

* Add some typespecs

* Add a bit of notice to v1.1.0 upgrade to perform the main upgrade instructions first
  • Loading branch information
unnawut authored Jan 28, 2019
1 parent a357e40 commit 96d847f
Show file tree
Hide file tree
Showing 24 changed files with 727 additions and 302 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ For other platforms or for a more advanced setup, see also manual installation b

- [Bare metal installation](docs/setup/bare_metal.md)

### Upgrade

Upgrading to a newer version? See [Upgrading the eWallet Server](docs/setup/upgrading).

## Commands

Docker image entrypoint is configured to recognize most commands that are used during normal operations. The way to invoke these commands depend on the installation method you choose.
Expand Down
4 changes: 4 additions & 0 deletions apps/ewallet/lib/ewallet/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ defmodule EWallet.Application do
settings = Application.get_env(:ewallet, :settings)
Config.register_and_load(:ewallet, settings)

ActivityLogger.configure(%{
EWallet.ReleaseTasks.CLIUser => %{type: "cli_user", identifier: nil}
})

# List all child processes to be supervised
children = [
worker(EWallet.Scheduler, [])
Expand Down
37 changes: 35 additions & 2 deletions apps/ewallet/lib/ewallet/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ defmodule EWallet.CLI do
@moduledoc """
Helper module for working with the command line interface.
"""

import IO
import IO.ANSI
alias EWallet.Helper
alias IO.ANSI.Docs

@yes_params ["-y", "--yes", "--assume_yes"]

def info(message), do: [:normal, message] |> format |> puts

def debug(message), do: [:faint, message] |> format |> puts
Expand All @@ -29,14 +31,45 @@ defmodule EWallet.CLI do

def warn(message), do: [:yellow, message] |> format |> puts

def error(message), do: [:red, message] |> format |> puts
def error(message, device \\ :stderr) do
formatted = format([:red, message])
IO.puts(device, formatted)
end

def color(messages), do: messages |> format |> puts

def heading(message), do: Docs.print_heading(message, width: 100)

def print(message), do: Docs.print(message, width: 100)

@spec assume_yes?([String.t()]) :: boolean()
def assume_yes?(args), do: Enum.any?(args, fn a -> a in @yes_params end)

@spec confirm?(String.t()) :: boolean()
def confirm?(message) do
(message <> " [Yn] ")
|> IO.gets()
|> String.trim()
|> confirmed?(true)
end

# Checks if the given input matches a confirmation statement.
# Returns the given fallback if the input is an empty string.
defp confirmed?("", fallback), do: fallback

defp confirmed?(input, _), do: Helper.to_boolean(input)

@spec configure_logger() :: :ok
def configure_logger do
"DEBUG"
|> System.get_env()
|> Helper.to_boolean()
|> case do
true -> Logger.configure(level: :debug)
false -> Logger.configure(level: :warn)
end
end

@spec halt(any()) :: no_return()
def halt(message) do
error(message)
Expand Down
170 changes: 26 additions & 144 deletions apps/ewallet/lib/ewallet/release_tasks.ex
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
# Copyright 2018 OmiseGO Pte Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule EWallet.ReleaseTasks do
@moduledoc """
Provides a task for use within release.
Provides utility function for release tasks.
"""
alias Ecto.Migrator
alias EWallet.Seeder.CLI
alias EWalletConfig.Config
alias ActivityLogger.System
alias EWallet.CLI

#
# Utils
#
defmacro __using__(_opts) do
quote do
import EWallet.ReleaseTasks
end
end

defp ensure_app_started({app_name, _}), do: ensure_app_started(app_name)
def ensure_app_started({app_name, _}), do: ensure_app_started(app_name)

defp ensure_app_started(app_name) do
def ensure_app_started(app_name) do
case Application.ensure_all_started(app_name) do
{:ok, _} ->
repos = Application.get_env(app_name, :ecto_repos, [])
Expand All @@ -24,140 +37,9 @@ defmodule EWallet.ReleaseTasks do
end
end

defp give_up do
IO.puts("Error: unknown error occured in release tasks. This is probably a bug.")
IO.puts("Please file a bug report at https://github.com/omisego/ewallet/issues/new")
def give_up do
CLI.error("Error: unknown error occured in release tasks. This is probably a bug.")
CLI.error("Please file a bug report at https://github.com/omisego/ewallet/issues/new")
:init.stop(1)
end

#
# Seed
#

@seed_start_apps [:crypto, :ssl, :postgrex, :ecto, :cloak, :ewallet]
@seed_std_spec [{:ewallet_config, :seeds_settings}, {:ewallet_db, :seeds}]
@seed_e2e_spec [{:ewallet_config, :seeds_settings}, {:ewallet_db, :seeds_test}]
@seed_sample_spec [
{:ewallet_config, :seeds_settings},
{:ewallet_db, :seeds},
{:ewallet_db, :seeds_sample}
]

def seed, do: seed_with(@seed_std_spec)
def seed_e2e, do: seed_with(@seed_e2e_spec)
def seed_sample, do: seed_with(@seed_sample_spec)

defp seed_with(spec) do
Enum.each(@seed_start_apps, &Application.ensure_all_started/1)
Enum.each(spec, &ensure_app_started/1)
_ = CLI.run(spec, true)
:init.stop()
end

#
# Initdb
#

@initdb_start_apps [:crypto, :ssl, :postgrex, :ecto]
@initdb_apps [:ewallet_config, :activity_logger, :ewallet_db, :local_ledger_db]

def initdb do
Enum.each(@initdb_start_apps, &Application.ensure_all_started/1)
Enum.each(@initdb_apps, &initdb/1)
:init.stop()
end

defp initdb(app_name) do
:ok = Application.load(app_name)
repos = Application.get_env(app_name, :ecto_repos, [])

Enum.each(repos, &run_create_for/1)
Enum.each(repos, & &1.start_link(pool_size: 1))
Enum.each(repos, &run_migrations_for/1)
end

defp run_create_for(repo) do
case repo.__adapter__.storage_up(repo.config) do
:ok ->
IO.puts("The database for #{inspect(repo)} has been created")

{:error, :already_up} ->
IO.puts("The database for #{inspect(repo)} has already been created")

{:error, term} when is_binary(term) ->
IO.puts("The database for #{inspect(repo)} couldn't be created: #{term}")

{:error, term} ->
IO.puts("The database for #{inspect(repo)} couldn't be created: #{inspect(term)}")
end
end

defp run_migrations_for(repo) do
migrations_path = priv_path_for(repo, "migrations")
IO.puts("Running migration for #{inspect(repo)}...")
Migrator.run(repo, migrations_path, :up, all: true)
end

defp priv_dir(app), do: "#{:code.priv_dir(app)}"

defp priv_path_for(repo, filename) do
app = Keyword.get(repo.config, :otp_app)
repo_underscore = repo |> Module.split() |> List.last() |> Macro.underscore()
Path.join([priv_dir(app), repo_underscore, filename])
end

#
# Config
#

@config_start_apps [:crypto, :ssl, :postgrex, :ecto, :cloak, :ewallet]
@config_apps [:activity_logger, :ewallet_config]

def config_base64 do
case :init.get_plain_arguments() do
[key, value] ->
config_base64(key, value)

_ ->
give_up()
end
end

defp config_base64(k, v) when is_list(k) do
case Base.decode64(to_string(k)) do
{:ok, key} ->
config_base64(key, v)

_ ->
give_up()
end
end

defp config_base64(k, v) when is_list(v) do
case Base.decode64(to_string(v)) do
{:ok, value} ->
config_base64(k, value)

_ ->
give_up()
end
end

defp config_base64(key, value) do
Enum.each(@config_start_apps, &Application.ensure_all_started/1)
Enum.each(@config_apps, &ensure_app_started/1)

case Config.update(%{key => value, originator: %System{}}) do
{:ok, [{key, {:ok, _}}]} ->
IO.puts("Successfully updated \"#{key}\" to \"#{value}\"")
:init.stop()

{:ok, [{key, {:error, :setting_not_found}}]} ->
IO.puts("Error: \"#{key}\" is not a valid settings")
:init.stop(1)

_ ->
give_up()
end
end
end
20 changes: 20 additions & 0 deletions apps/ewallet/lib/ewallet/release_tasks/cli_user.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2018 OmiseGO Pte Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule EWallet.ReleaseTasks.CLIUser do
@moduledoc """
Module representing the user invoking the command line interface as originator.
"""
defstruct uuid: "33333333-3333-3333-3333-333333333333"
end
76 changes: 76 additions & 0 deletions apps/ewallet/lib/ewallet/release_tasks/config.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright 2018 OmiseGO Pte Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule EWallet.ReleaseTasks.Config do
@moduledoc """
A release task that manages application configurations.
"""
use EWallet.ReleaseTasks
alias ActivityLogger.System
alias EWallet.CLI
alias EWalletConfig.Config

@start_apps [:crypto, :ssl, :postgrex, :ecto, :cloak, :ewallet]
@apps [:activity_logger, :ewallet_config]

def run do
case :init.get_plain_arguments() do
[key, value] ->
config_base64(key, value)

_ ->
give_up()
end
end

def run(key, value), do: config_base64(key, value)

defp config_base64(k, v) when is_list(k) do
case Base.decode64(to_string(k)) do
{:ok, key} ->
config_base64(key, v)

_ ->
give_up()
end
end

defp config_base64(k, v) when is_list(v) do
case Base.decode64(to_string(v)) do
{:ok, value} ->
config_base64(k, value)

_ ->
give_up()
end
end

defp config_base64(key, value) do
Enum.each(@start_apps, &Application.ensure_all_started/1)
Enum.each(@apps, &ensure_app_started/1)

case Config.update(%{key => value, originator: %System{}}) do
{:ok, [{key, {:ok, _}}]} ->
CLI.success("Successfully updated \"#{key}\" to \"#{value}\"")
:init.stop()

{:ok, [{key, {:error, :setting_not_found}}]} ->
CLI.error("Error: \"#{key}\" is not a valid settings")
:init.stop(1)

_ ->
give_up()
end
end
end
Loading

0 comments on commit 96d847f

Please sign in to comment.