From 9e8fd1f5dd8de2cb61e3543b81b79447568c1354 Mon Sep 17 00:00:00 2001 From: TheFirstAvenger Date: Fri, 25 Jan 2019 13:56:55 -0500 Subject: [PATCH 1/3] Add badges to readme. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d7effbe..bcc19de 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # Ironman +[![Build Status](https://travis-ci.com/TheFirstAvenger/ironman.svg?branch=master)](https://travis-ci.com/TheFirstAvenger/ironman) +[![Coverage Status](https://coveralls.io/repos/github/TheFirstAvenger/ironman/badge.svg?branch=master)](https://coveralls.io/github/TheFirstAvenger/ironman?branch=master) +[![Project license](https://img.shields.io/hexpm/l/ironman.svg)](https://unlicense.org/) +[![Hex.pm package](https://img.shields.io/hexpm/v/ironman.svg)](https://hex.pm/packages/ironman) +[![Hex.pm downloads](https://img.shields.io/hexpm/dt/ironman.svg)](https://hex.pm/packages/ironman) + `mix new` is like Tony Stark: Awesome and can do great things, but not bulletproof. When he suits up, however, his vulnerabilities are covered. Similarly, the Ironman project takes an elixir project (existing or newly created) and configures it in a way that protects it from getting in a bad state. It does this by adding dependencies for best practices such as `:credo` and `:dialyxir`, adding ci configuration for these tools, setting run configuration such as `warnings_as_errors`, etc... Each step of suiting up is confirmed with the end user before changing, and can be rejected individually. From 9864ebe00043693a5713240b08c89f5e66953d05 Mon Sep 17 00:00:00 2001 From: TheFirstAvenger Date: Thu, 7 Feb 2019 16:06:20 -0500 Subject: [PATCH 2/3] Change dep resolution to regex. Update IO question format. --- .dialyzer_ignore.exs | 5 +--- .travis.yml | 2 +- CHANGELOG.md | 6 ++++ lib/ironman/config.ex | 5 +--- lib/ironman/runner.ex | 1 + lib/ironman/utils.ex | 2 +- lib/ironman/utils/deps.ex | 39 +++++-------------------- test/ironman/checks/simple_dep_test.exs | 18 ++++++------ test/ironman/utils_test.exs | 4 +-- test/support/mix_builder.ex | 3 +- 10 files changed, 32 insertions(+), 53 deletions(-) diff --git a/.dialyzer_ignore.exs b/.dialyzer_ignore.exs index 1b07060..2ff4f4b 100644 --- a/.dialyzer_ignore.exs +++ b/.dialyzer_ignore.exs @@ -1,6 +1,3 @@ [ - ~r/Function :httpc\.request\/4 does not exist\./, - # https://github.com/elixir-lang/elixir/issues/8631 - ~r/Function with_deps\/0 has no local return/, - ~r/Function with_deps\/1 has no local return/ + ~r/Function :httpc\.request\/4 does not exist\./ ] diff --git a/.travis.yml b/.travis.yml index c662340..e7e9714 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: elixir elixir: - - 1.8 + - 1.8.1 otp_release: - 21.0 env: diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f5a13..3f1111d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Next + +* Change dependency checking to use regex +* Clear dialyzer ignores fixed in elixir 1.8.1 +* Change format of IO questions + ## 0.1.2 * Add self version checking diff --git a/lib/ironman/config.ex b/lib/ironman/config.ex index cf43ec0..5007026 100644 --- a/lib/ironman/config.ex +++ b/lib/ironman/config.ex @@ -5,17 +5,14 @@ defmodule Ironman.Config do """ @type t :: %__MODULE__{ mix_exs: String.t(), - deps: list(), changed: boolean() } defstruct mix_exs: nil, - deps: nil, changed: false def new!() do %__MODULE__{ - mix_exs: File.read!("mix.exs"), - deps: Mix.Project.config()[:deps] + mix_exs: File.read!("mix.exs") } end end diff --git a/lib/ironman/runner.ex b/lib/ironman/runner.ex index 7ece69e..77db620 100644 --- a/lib/ironman/runner.ex +++ b/lib/ironman/runner.ex @@ -40,6 +40,7 @@ defmodule Ironman.Runner do def run_check(%Config{} = config, :excoveralls), do: config |> SimpleDep.run(:excoveralls, only: :test) |> unwrap(:excoveralls) + @spec unwrap({atom(), Config.t()} | {:error, any()}, atom()) :: Config.t() def unwrap({:no, config}, _check), do: config def unwrap({:yes, config}, _check), do: config def unwrap({:up_to_date, config}, _check), do: config diff --git a/lib/ironman/utils.ex b/lib/ironman/utils.ex index 7412efc..3082e5a 100644 --- a/lib/ironman/utils.ex +++ b/lib/ironman/utils.ex @@ -85,7 +85,7 @@ defmodule Ironman.Utils do @spec ask(String.t(), function(), function(), function()) :: any() def ask(q, yes, no, other) do - case IIO.get("#{q} Yn\n") do + case IIO.get("#{q} [Yn] ") do x when x in ["Y\n", "y\n", "\n"] -> yes.() x when x in ["N\n", "n\n"] -> no.() _ -> other.() diff --git a/lib/ironman/utils/deps.ex b/lib/ironman/utils/deps.ex index 9812419..90d1584 100644 --- a/lib/ironman/utils/deps.ex +++ b/lib/ironman/utils/deps.ex @@ -37,12 +37,13 @@ defmodule Ironman.Utils.Deps do end @spec get_configured_version(Config.t(), dep()) :: String.t() | nil - def get_configured_version(%Config{deps: deps}, dep) do - deps - |> Enum.find(fn d -> elem(d, 0) == dep end) + def get_configured_version(%Config{mix_exs: mix_exs}, dep) do + "defp deps do.*?\\[.*?{:#{dep}, \"(.*?)\"" + |> Regex.compile!("s") + |> Regex.run(mix_exs) |> case do - nil -> nil - d -> elem(d, 1) + [_, version] -> version + _ -> nil end end @@ -82,7 +83,7 @@ defmodule Ironman.Utils.Deps do "defp deps do\n [{:#{dep}, \"#{new_version}\"#{dep_opts_str}}," ) - {:yes, %Config{config | mix_exs: mix_exs, changed: true} |> add_dep_to_state(dep, dep_opts, new_version)} + {:yes, %Config{config | mix_exs: mix_exs, changed: true}} end defp dep_opts_to_str(dep_opts) do @@ -118,31 +119,7 @@ defmodule Ironman.Utils.Deps do regex = Regex.compile!("{:#{dep}, \"~>.*?\"") mix_exs = Regex.replace(regex, mix_exs, "{:#{dep}, \"#{new_version}\"") - {:yes, %Config{config | mix_exs: mix_exs, changed: true} |> update_deps_state(dep, new_version)} - end - - @spec update_deps_state(Ironman.Config.t(), dep(), String.t()) :: Ironman.Config.t() - def update_deps_state(%Config{deps: deps} = config, dep, new_version) do - deps = - Enum.map(deps, fn d -> - case elem(d, 0) do - ^dep -> d |> Tuple.delete_at(1) |> Tuple.insert_at(1, new_version) - _ -> d - end - end) - - %Config{config | deps: deps} - end - - @spec add_dep_to_state(Ironman.Config.t(), dep(), keyword(), String.t()) :: Ironman.Config.t() - def add_dep_to_state(%Config{deps: deps} = config, dep, dep_opts, new_version) do - new_dep = - case dep_opts do - [] -> {dep, new_version} - _ -> {dep, new_version, dep_opts} - end - - %Config{config | deps: [new_dep | deps]} + {:yes, %Config{config | mix_exs: mix_exs, changed: true}} end @spec skip_upgrade(Config.t(), any()) :: {:no, Config.t()} diff --git a/test/ironman/checks/simple_dep_test.exs b/test/ironman/checks/simple_dep_test.exs index 266dcde..11a8a80 100644 --- a/test/ironman/checks/simple_dep_test.exs +++ b/test/ironman/checks/simple_dep_test.exs @@ -18,7 +18,7 @@ defmodule Ironman.Checks.SimpleDepTest do describe "out of date" do test "updates when y pressed" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Upgrade ex_doc from ~> 1.2.2 to 1.2.3? Yn\n", "y") + MoxHelpers.expect_io("Upgrade ex_doc from ~> 1.2.2 to 1.2.3? [Yn] ", "y") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps(ex_doc: "~> 1.2.2") assert "~> 1.2.2" == Deps.get_configured_version(config, :ex_doc) @@ -30,7 +30,7 @@ defmodule Ironman.Checks.SimpleDepTest do test "doesn't update when n pressed" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Upgrade ex_doc from ~> 1.2.2 to 1.2.3? Yn\n", "n") + MoxHelpers.expect_io("Upgrade ex_doc from ~> 1.2.2 to 1.2.3? [Yn] ", "n") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps(ex_doc: "~> 1.2.2") assert "~> 1.2.2" == Deps.get_configured_version(config, :ex_doc) @@ -42,9 +42,9 @@ defmodule Ironman.Checks.SimpleDepTest do test "multiple" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Upgrade ex_doc from ~> 1.2.2 to 1.2.3? Yn\n", "y") + MoxHelpers.expect_io("Upgrade ex_doc from ~> 1.2.2 to 1.2.3? [Yn] ", "y") MoxHelpers.expect_dep_http(:earmark, "2.3.6") - MoxHelpers.expect_io("Upgrade earmark from ~> 2.3.4 to 2.3.6? Yn\n", "y") + MoxHelpers.expect_io("Upgrade earmark from ~> 2.3.4 to 2.3.6? [Yn] ", "y") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps(ex_doc: "~> 1.2.2", earmark: "~> 2.3.4") @@ -65,7 +65,7 @@ defmodule Ironman.Checks.SimpleDepTest do describe "missing" do test "updates when y pressed" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Install ex_doc 1.2.3? Yn\n", "y") + MoxHelpers.expect_io("Install ex_doc 1.2.3? [Yn] ", "y") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps() assert nil == Deps.get_configured_version(config, :ex_doc) @@ -77,7 +77,7 @@ defmodule Ironman.Checks.SimpleDepTest do test "doesn't update when n pressed" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Install ex_doc 1.2.3? Yn\n", "n") + MoxHelpers.expect_io("Install ex_doc 1.2.3? [Yn] ", "n") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps() assert nil == Deps.get_configured_version(config, :ex_doc) @@ -90,9 +90,9 @@ defmodule Ironman.Checks.SimpleDepTest do test "multiple" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Install ex_doc 1.2.3? Yn\n", "y") + MoxHelpers.expect_io("Install ex_doc 1.2.3? [Yn] ", "y") MoxHelpers.expect_dep_http(:earmark, "2.3.6") - MoxHelpers.expect_io("Install earmark 2.3.6? Yn\n", "y") + MoxHelpers.expect_io("Install earmark 2.3.6? [Yn] ", "y") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps() @@ -111,7 +111,7 @@ defmodule Ironman.Checks.SimpleDepTest do test "Sets dep_opts" do MoxHelpers.expect_dep_http(:ex_doc, "1.2.3") - MoxHelpers.expect_io("Install ex_doc 1.2.3? Yn\n", "y") + MoxHelpers.expect_io("Install ex_doc 1.2.3? [Yn] ", "y") %Config{mix_exs: mix_exs} = config = MixBuilder.with_deps() assert nil == Deps.get_configured_version(config, :ex_doc) diff --git a/test/ironman/utils_test.exs b/test/ironman/utils_test.exs index 2b2a8f0..c375dd7 100644 --- a/test/ironman/utils_test.exs +++ b/test/ironman/utils_test.exs @@ -14,14 +14,14 @@ defmodule Ironman.UtilsTest do test "Upgrade when out of date" do MoxHelpers.expect_dep_http(:ironman, "0.0.0") - MoxHelpers.expect_io("Ironman is out of date. Upgrade? Yn\n", "y") + MoxHelpers.expect_io("Ironman is out of date. Upgrade? [Yn] ", "y") MoxHelpers.expect_cmd(["mix", "archive.install", "hex", "ironman", "--force"]) assert :exit == Utils.check_self_version() end test "Dont upgrade when out of date and n pressed" do MoxHelpers.expect_dep_http(:ironman, "0.0.0") - MoxHelpers.expect_io("Ironman is out of date. Upgrade? Yn\n", "n") + MoxHelpers.expect_io("Ironman is out of date. Upgrade? [Yn] ", "n") MoxHelpers.expect_cmd("hi") assert :declined == Utils.check_self_version() end diff --git a/test/support/mix_builder.ex b/test/support/mix_builder.ex index 658095e..2400bac 100644 --- a/test/support/mix_builder.ex +++ b/test/support/mix_builder.ex @@ -28,9 +28,10 @@ defmodule Ironman.Test.Helpers.MixBuilder do |> List.wrap() |> IO.iodata_to_binary() - %Config{mix_exs: mix_exs, deps: deps} + %Config{mix_exs: mix_exs} end + @spec mix_string(list()) :: String.t() def mix_string(deps) do deps |> Enum.map(fn {dep, ver} -> "{:#{dep}, \"#{ver}\"}" end) From 5a3749541135e9df4bee80835f05dc2133ea9669 Mon Sep 17 00:00:00 2001 From: TheFirstAvenger Date: Thu, 7 Feb 2019 17:06:52 -0500 Subject: [PATCH 3/3] Resolved dialyzer warning. --- test/support/mix_builder.ex | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/test/support/mix_builder.ex b/test/support/mix_builder.ex index 2400bac..f3af247 100644 --- a/test/support/mix_builder.ex +++ b/test/support/mix_builder.ex @@ -3,9 +3,8 @@ defmodule Ironman.Test.Helpers.MixBuilder do alias Ironman.Config def with_deps(deps \\ []) when is_list(deps) do - mix_exs = - """ - defmodule Test.MixProject do + mix_exs = """ + defmodule Test.MixProject do use Mix.Project def project do @@ -22,11 +21,8 @@ defmodule Ironman.Test.Helpers.MixBuilder do defp deps do #{mix_string(deps)} end - end - """ - |> Code.format_string!() - |> List.wrap() - |> IO.iodata_to_binary() + end + """ %Config{mix_exs: mix_exs} end @@ -34,10 +30,11 @@ defmodule Ironman.Test.Helpers.MixBuilder do @spec mix_string(list()) :: String.t() def mix_string(deps) do deps - |> Enum.map(fn {dep, ver} -> "{:#{dep}, \"#{ver}\"}" end) - |> Enum.join(",") + |> Enum.map(fn {dep, ver} -> " {:#{dep}, \"#{ver}\"}" end) + |> Enum.join(",\n") |> wrap_brackets() end - defp wrap_brackets(str), do: "[ #{str} ]" + defp wrap_brackets(""), do: "[]" + defp wrap_brackets(str), do: "[\n#{str}\n ]" end