From f7c2bf307209b7e6ed570325c44b814f9831f9e7 Mon Sep 17 00:00:00 2001 From: An Duong Date: Mon, 6 Jun 2022 14:34:28 +0700 Subject: [PATCH 01/61] Correct empty ident --- .github/workflows/apply_api_variant.yml | 10 +++--- .github/workflows/apply_live_variant.yml | 4 +-- .github/workflows/apply_mix_variant.yml | 10 +++--- .github/workflows/apply_web_variant.yml | 2 +- .github/workflows/publish_to_hex_pm.yml | 8 ++--- .github/workflows/reusable_mix_project.yml | 8 ++--- .../workflows/reusable_phoenix_project.yml | 22 ++++++------ .github/workflows/test_template.yml | 34 +++++++++---------- .github/workflows/verify_release_version.yml | 4 +-- .../.github/workflows/test.yml.eex | 30 ++++++++++++++++ .../.github/workflows/test.yml.mix.eex | 18 ++++++---- 11 files changed, 93 insertions(+), 57 deletions(-) diff --git a/.github/workflows/apply_api_variant.yml b/.github/workflows/apply_api_variant.yml index be7286c4..39d76810 100644 --- a/.github/workflows/apply_api_variant.yml +++ b/.github/workflows/apply_api_variant.yml @@ -16,7 +16,7 @@ jobs: with: new_project_options: "--no-html --no-assets --no-live --module=SampleCustomModule --app=sample_custom_app" variant: "api" - + short_custom_name_api_project: name: Test on a short custom name API project uses: ./.github/workflows/reusable_phoenix_project.yml @@ -37,15 +37,15 @@ jobs: with: new_project_options: "--no-live --module=SampleCustomModule --app=sample_custom_app" variant: "api" - + short_custom_name_web_project: name: Test on a short custom name Web project uses: ./.github/workflows/reusable_phoenix_project.yml with: new_project_options: "--no-live --module=Z --app=z" variant: "api" - - + + standard_live_project: name: Test on a Standard Live project uses: ./.github/workflows/reusable_phoenix_project.yml @@ -59,7 +59,7 @@ jobs: with: new_project_options: "--module=SampleCustomModule --app=sample_custom_app" variant: "api" - + short_custom_name_live_project: name: Test on a short custom name Live project uses: ./.github/workflows/reusable_phoenix_project.yml diff --git a/.github/workflows/apply_live_variant.yml b/.github/workflows/apply_live_variant.yml index b6620409..660f800c 100644 --- a/.github/workflows/apply_live_variant.yml +++ b/.github/workflows/apply_live_variant.yml @@ -9,14 +9,14 @@ jobs: with: new_project_options: "" variant: "live" - + long_custom_name_live_project: name: Test on a long custom name Live project uses: ./.github/workflows/reusable_phoenix_project.yml with: new_project_options: "--module=SampleCustomModule --app=sample_custom_app" variant: "live" - + short_custom_name_live_project: name: Test on a short custom name Live project uses: ./.github/workflows/reusable_phoenix_project.yml diff --git a/.github/workflows/apply_mix_variant.yml b/.github/workflows/apply_mix_variant.yml index 1595a2be..65cf5863 100644 --- a/.github/workflows/apply_mix_variant.yml +++ b/.github/workflows/apply_mix_variant.yml @@ -8,31 +8,31 @@ jobs: uses: ./.github/workflows/reusable_mix_project.yml with: new_project_options: "" - + long_custom_name_mix_project: name: Test on a long custom name Mix project uses: ./.github/workflows/reusable_mix_project.yml with: new_project_options: "--module=SampleCustomModule --app=sample_custom_app" - + short_custom_name_mix_project: name: Test on a short custom name Mix project uses: ./.github/workflows/reusable_mix_project.yml with: new_project_options: "--module=Z --app=z" - + standard_mix_supervision_project: name: Test on a Standard Supervision Mix project uses: ./.github/workflows/reusable_mix_project.yml with: new_project_options: "--sup" - + long_custom_name_mix_supervision_project: name: Test on a long custom name Supervision Mix project uses: ./.github/workflows/reusable_mix_project.yml with: new_project_options: "--sup --module=SampleCustomModule --app=sample_custom_app" - + short_custom_name_mix_supervision_project: name: Test on a short custom name Supervision Mix project uses: ./.github/workflows/reusable_mix_project.yml diff --git a/.github/workflows/apply_web_variant.yml b/.github/workflows/apply_web_variant.yml index 3a60821b..d653653e 100644 --- a/.github/workflows/apply_web_variant.yml +++ b/.github/workflows/apply_web_variant.yml @@ -16,7 +16,7 @@ jobs: with: new_project_options: "--no-live --module=SampleCustomModule --app=sample_custom_app" variant: "web" - + short_custom_name_web_project: name: Test on a short custom name Web project uses: ./.github/workflows/reusable_phoenix_project.yml diff --git a/.github/workflows/publish_to_hex_pm.yml b/.github/workflows/publish_to_hex_pm.yml index b8579cc7..8f9c8dba 100644 --- a/.github/workflows/publish_to_hex_pm.yml +++ b/.github/workflows/publish_to_hex_pm.yml @@ -15,9 +15,9 @@ jobs: name: Publish hex package runs-on: ubuntu-latest - + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} - + steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.9.1 @@ -41,10 +41,10 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force diff --git a/.github/workflows/reusable_mix_project.yml b/.github/workflows/reusable_mix_project.yml index 67aff6dd..7cdf74b5 100644 --- a/.github/workflows/reusable_mix_project.yml +++ b/.github/workflows/reusable_mix_project.yml @@ -10,7 +10,7 @@ on: env: BASE_PROJECT_DIRECTORY: sample_project MIX_ENV: test - + jobs: unit_test: name: Unit test @@ -39,13 +39,13 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force - + - name: Create Mix project run: make create_mix_project PROJECT_DIRECTORY=$BASE_PROJECT_DIRECTORY OPTIONS="${{ inputs.new_project_options }}" diff --git a/.github/workflows/reusable_phoenix_project.yml b/.github/workflows/reusable_phoenix_project.yml index 91e42831..ffa5d00f 100644 --- a/.github/workflows/reusable_phoenix_project.yml +++ b/.github/workflows/reusable_phoenix_project.yml @@ -14,7 +14,7 @@ env: PHOENIX_VERSION: 1.6.6 BASE_PROJECT_DIRECTORY: sample_project DB_HOST: localhost - + jobs: unit_test: name: Unit test @@ -54,19 +54,19 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force - + - name: Install Phoenix ${{ env.PHOENIX_VERSION }} run: make install_phoenix PHOENIX_VERSION=${{ env.PHOENIX_VERSION }} - + - name: Create a new project run: printf "Y\n" | make create_phoenix_project PROJECT_DIRECTORY=$BASE_PROJECT_DIRECTORY OPTIONS="${{ inputs.new_project_options }}" - + - name: Apply ${{ inputs.variant }} variant into the new project run: make apply_phoenix_template PROJECT_DIRECTORY=$BASE_PROJECT_DIRECTORY VARIANT="${{ inputs.variant }}" @@ -77,21 +77,21 @@ jobs: - name: Compile dependencies run: cd $BASE_PROJECT_DIRECTORY && mix compile --warnings-as-errors --all-warnings - + - name: Install Node Dependencies if: ${{ inputs.variant != 'api' }} run: cd $BASE_PROJECT_DIRECTORY && npm install --prefix assets - + - name: Run mix ecto.create run: cd $BASE_PROJECT_DIRECTORY && mix ecto.create env: MIX_ENV: test - + - name: Run mix ecto.migrate run: cd $BASE_PROJECT_DIRECTORY && mix ecto.migrate env: MIX_ENV: test - + - name: Run mix codebase run: cd $BASE_PROJECT_DIRECTORY && mix codebase @@ -100,6 +100,6 @@ jobs: - name: Remove nimble_template dependency run: make remove_nimble_template PROJECT_DIRECTORY=$BASE_PROJECT_DIRECTORY - + - name: Test Production Docker image build run: cd $BASE_PROJECT_DIRECTORY && docker-compose build diff --git a/.github/workflows/test_template.yml b/.github/workflows/test_template.yml index dcae2cb4..14b155b9 100644 --- a/.github/workflows/test_template.yml +++ b/.github/workflows/test_template.yml @@ -24,20 +24,20 @@ jobs: - name: Setup asdf uses: asdf-vm/actions/setup@v1 - + - name: Cache asdf uses: actions/cache@v3 with: path: /home/runner/.asdf key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} restore-keys: ${{ runner.os }}-asdf- - + - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force @@ -58,9 +58,9 @@ jobs: lint_codebase: name: Linting - + needs: install_and_compile_dependencies - + runs-on: ubuntu-latest steps: @@ -76,20 +76,20 @@ jobs: - name: Setup asdf uses: asdf-vm/actions/setup@v1 - + - name: Cache asdf uses: actions/cache@v3 with: path: /home/runner/.asdf key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} restore-keys: ${{ runner.os }}-asdf- - + - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force @@ -113,12 +113,12 @@ jobs: - name: Run codebase check run: mix codebase - + unit_test: name: Unit test - + needs: lint_codebase - + runs-on: ubuntu-latest steps: @@ -134,20 +134,20 @@ jobs: - name: Setup asdf uses: asdf-vm/actions/setup@v1 - + - name: Cache asdf uses: actions/cache@v3 with: path: /home/runner/.asdf key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} restore-keys: ${{ runner.os }}-asdf- - + - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force diff --git a/.github/workflows/verify_release_version.yml b/.github/workflows/verify_release_version.yml index 97290605..55e70103 100644 --- a/.github/workflows/verify_release_version.yml +++ b/.github/workflows/verify_release_version.yml @@ -37,10 +37,10 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 - + - name: Install rebar run: mix local.rebar --force - + - name: Install hex run: mix local.hex --force diff --git a/priv/templates/nimble_template/.github/workflows/test.yml.eex b/priv/templates/nimble_template/.github/workflows/test.yml.eex index c6b7a604..31c7a3d9 100644 --- a/priv/templates/nimble_template/.github/workflows/test.yml.eex +++ b/priv/templates/nimble_template/.github/workflows/test.yml.eex @@ -36,6 +36,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: @@ -102,6 +108,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: @@ -189,6 +201,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: @@ -264,6 +282,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: @@ -354,6 +378,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: diff --git a/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex b/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex index 2616376f..0c627b9c 100644 --- a/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex +++ b/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex @@ -49,12 +49,12 @@ jobs: - name: Compile dependencies run: mix compile - + lint_codebase: name: Linting - + needs: install_and_compile_dependencies - + runs-on: ubuntu-latest steps: @@ -76,6 +76,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: @@ -93,12 +99,12 @@ jobs: - name: Run codebase check run: mix codebase - + test: name: Unit Test - + needs: lint_codebase - + runs-on: ubuntu-latest steps: From ea274e5b980fd8b41fe658f4ab37206de7951ef6 Mon Sep 17 00:00:00 2001 From: An Duong Date: Mon, 6 Jun 2022 14:37:57 +0700 Subject: [PATCH 02/61] Install rebar and hex for the mix workflow --- .../.github/workflows/test.yml.mix.eex | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex b/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex index 0c627b9c..37554d70 100644 --- a/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex +++ b/priv/templates/nimble_template/.github/workflows/test.yml.mix.eex @@ -35,6 +35,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: @@ -126,6 +132,12 @@ jobs: - name: Install dependencies in .tool-versions uses: asdf-vm/actions/install@v1 + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + - name: Cache Elixir build uses: actions/cache@v3 with: From 4a03b277548e4cb62a94984f76ec32cb42bcd538 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 15:34:33 +0700 Subject: [PATCH 03/61] Add the condition into the seeds file --- .../addons/variants/phoenix/seeds.ex | 21 +++++++++++++++++++ .../templates/variants/phoenix/template.ex | 1 + .../.github/workflows/test.yml.eex | 2 +- .../addons/variants/seeds_test.exs | 21 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 lib/nimble_template/addons/variants/phoenix/seeds.ex create mode 100644 test/nimble_template/addons/variants/seeds_test.exs diff --git a/lib/nimble_template/addons/variants/phoenix/seeds.ex b/lib/nimble_template/addons/variants/phoenix/seeds.ex new file mode 100644 index 00000000..134b7c4c --- /dev/null +++ b/lib/nimble_template/addons/variants/phoenix/seeds.ex @@ -0,0 +1,21 @@ +defmodule NimbleTemplate.Addons.Phoenix.Seeds do + @moduledoc false + + use NimbleTemplate.Addons.Addon + + @impl true + def do_apply(%Project{} = project, _opts) do + edit_seeds_file(project) + + project + end + + defp edit_seeds_file(project) do + Generator.append_content("priv/repo/seeds.exs", """ + if Mix.env() == :dev || System.get_env("ENABLE_DB_SEED") == "true" do + end + """) + + project + end +end diff --git a/lib/nimble_template/templates/variants/phoenix/template.ex b/lib/nimble_template/templates/variants/phoenix/template.ex index 9f4d714c..72201043 100644 --- a/lib/nimble_template/templates/variants/phoenix/template.ex +++ b/lib/nimble_template/templates/variants/phoenix/template.ex @@ -50,6 +50,7 @@ defmodule NimbleTemplate.Templates.Phoenix.Template do |> PhoenixAddons.MixRelease.apply() |> PhoenixAddons.HealthPlug.apply() |> PhoenixAddons.Gettext.apply(project) + |> PhoenixAddons.Seeds.apply(project) end defp apply_optional_common_phoenix_addons(project) do diff --git a/priv/templates/nimble_template/.github/workflows/test.yml.eex b/priv/templates/nimble_template/.github/workflows/test.yml.eex index 31c7a3d9..89b0551e 100644 --- a/priv/templates/nimble_template/.github/workflows/test.yml.eex +++ b/priv/templates/nimble_template/.github/workflows/test.yml.eex @@ -180,7 +180,7 @@ jobs: --health-retries 5 env: - MIX_ENV: dev + ENABLE_DB_SEED: true steps: - name: Checkout repository diff --git a/test/nimble_template/addons/variants/seeds_test.exs b/test/nimble_template/addons/variants/seeds_test.exs new file mode 100644 index 00000000..c7fad03f --- /dev/null +++ b/test/nimble_template/addons/variants/seeds_test.exs @@ -0,0 +1,21 @@ +defmodule NimbleTemplate.Addons.Phoenix.SeedsTest do + use NimbleTemplate.AddonCase, async: false + + describe "#apply/2" do + test "adds the condition into the seeds.exs file", %{ + project: project, + test_project_path: test_project_path + } do + in_test_project(test_project_path, fn -> + PhoenixAddons.Seeds.apply(project) + + assert_file("priv/repo/seeds.exs", fn file -> + assert file =~ """ + if Mix.env() == :dev || System.get_env("ENABLE_DB_SEED") == "true" do + end + """ + end) + end) + end + end +end From 3427515d2acf9684c0fd35d5c4b28387418043b8 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 17:20:30 +0700 Subject: [PATCH 04/61] Add the BumpVersion helper --- README.md | 14 ++++- lib/mix/tasks/nimble_template.bump_version.ex | 35 +++++++++++ lib/nimble_template/version.ex | 52 +++++++++++++++ test/nimble_template/version_test.exs | 63 +++++++++++++++++++ 4 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 lib/mix/tasks/nimble_template.bump_version.ex create mode 100644 lib/nimble_template/version.ex create mode 100644 test/nimble_template/version_test.exs diff --git a/README.md b/README.md index e4bfe3d6..be39117a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Step 2: Add `nimble_template` dependency to `mix.exs`: ```elixir def deps do [ - {:nimble_template, "~> 4.2", only: :dev, runtime: false}, + {:nimble_template, "~> 4.2.0", only: :dev, runtime: false}, # other dependencies ... ] end @@ -71,9 +71,17 @@ Set the `HEX_API_KEY` as a Github secret (skip this step if it has been done). The release process follows the [Git flow](https://nimblehq.co/compass/development/version-control/release-management). -Once a `release/` is created, to publish the new version to Hex.pm, the version number in the `mix.ex` file needs to be updated on the release branch before merging. +1. Bump the new version on local -Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). + ```bash + mix nimble_template.bump_version new_version + ``` + +2. Open a PR to develop. + +3. Once that bump_version PR is merged, create the `release/` from the `develop` branch, points to the `master` branch. + +4. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). ## Contributing diff --git a/lib/mix/tasks/nimble_template.bump_version.ex b/lib/mix/tasks/nimble_template.bump_version.ex new file mode 100644 index 00000000..fd283ebf --- /dev/null +++ b/lib/mix/tasks/nimble_template.bump_version.ex @@ -0,0 +1,35 @@ +defmodule Mix.Tasks.NimbleTemplate.BumpVersion do + @shortdoc "Bump the template into specific version." + + @moduledoc """ + #{@shortdoc} + + - Hex package: https://hex.pm/packages/nimble_template + - Github: https://github.com/nimblehq/elixir-templates + + # Usage + + - mix help nimble_template.bump_version # Print help + - mix nimble_template.bump_version [new_version] # Bump the template into the [new_version]. + """ + + use Mix.Task + + alias NimbleTemplate.Version + + def run(args) do + new_version = parse_opts(args) + + Version.bump(new_version, %{included_git_action?: true}) + end + + defp parse_opts(args) do + case OptionParser.parse(args, strict: []) do + {[], [new_version], []} -> + new_version + + _ -> + Mix.raise("Invalid format. Please use `mix nimble_template.bump_version new_version`") + end + end +end diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex new file mode 100644 index 00000000..29d57e9c --- /dev/null +++ b/lib/nimble_template/version.ex @@ -0,0 +1,52 @@ +defmodule NimbleTemplate.Version do + @moduledoc false + + alias NimbleTemplate.Generator + + def bump(new_version, opts \\ %{}) do + current_version = Mix.Project.config()[:version] + + if new_version > current_version do + if included_git_action?(opts) do + git_checkout_chore_branch(new_version) + end + + bump_version_to(current_version, new_version) + + if included_git_action?(opts) do + git_add_and_push(new_version) + end + + :ok + else + Mix.raise("The new version must be greater than #{current_version}") + end + end + + defp included_git_action?(%{included_git_action?: true}), do: true + defp included_git_action?(_), do: false + + defp bump_version_to(current_version, new_version) do + Generator.replace_content( + "mix.exs", + "version: \"#{current_version}\",", + "version: \"#{new_version}\"," + ) + + Generator.replace_content( + "README.md", + "{:nimble_template, \"~> #{current_version}\", only: :dev, runtime: false},", + "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," + ) + end + + defp git_checkout_chore_branch(new_version) do + Mix.shell().cmd("git checkout develop") + Mix.shell().cmd("git checkout -b chore/bump-to-#{new_version}") + end + + defp git_add_and_push(new_version) do + Mix.shell().cmd("git add mix.exs README.md") + Mix.shell().cmd("git commit -m \"Bump to #{new_version}\"") + end +end diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs new file mode 100644 index 00000000..00229d34 --- /dev/null +++ b/test/nimble_template/version_test.exs @@ -0,0 +1,63 @@ +defmodule NimbleTemplate.VersionTest do + use NimbleTemplate.AddonCase, async: false + + alias NimbleTemplate.Version + + describe "bump/1" do + test "updates the version in mix.exs and README.md files given a valid version number" do + current_version = Mix.Project.config()[:version] + + patch_number = + current_version + |> String.split(".") + |> List.last() + |> String.to_integer() + + # Increase the patch version to 1 + new_version = + current_version + |> String.split(".") + |> List.replace_at(2, patch_number + 1) + |> Enum.join(".") + + assert Version.bump(new_version) == :ok + + assert_file("mix.exs", fn file -> + assert file =~ "version: \"#{new_version}\"" + end) + + assert_file("README.md", fn file -> + assert file =~ "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," + end) + end + + test "raises Mix.Error exception given an invalid version number" do + current_version = Mix.Project.config()[:version] + + major_number = + current_version + |> String.split(".") + |> List.first() + |> String.to_integer() + + # Decrease the major version to 1 + new_version = + current_version + |> String.split(".") + |> List.replace_at(0, major_number - 1) + |> Enum.join(".") + + assert_raise Mix.Error, "The new version must be greater than #{current_version}", fn -> + Version.bump(new_version) + end + + assert_file("mix.exs", fn file -> + assert file =~ "version: \"#{current_version}\"" + end) + + assert_file("README.md", fn file -> + assert file =~ "{:nimble_template, \"~> #{current_version}\", only: :dev, runtime: false}," + end) + end + end +end From af6d50ddba3a18c8cc852615dc6fea7c56cc9266 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 17:20:40 +0700 Subject: [PATCH 05/61] Bump to 4.2.1 --- README.md | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be39117a..280e9dd9 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Step 2: Add `nimble_template` dependency to `mix.exs`: ```elixir def deps do [ - {:nimble_template, "~> 4.2.0", only: :dev, runtime: false}, + {:nimble_template, "~> 4.2.1", only: :dev, runtime: false}, # other dependencies ... ] end diff --git a/mix.exs b/mix.exs index 0209912a..7defcd9b 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule NimbleTemplate.MixProject do def project do [ app: :nimble_template, - version: "4.2.0", + version: "4.2.1", description: "Phoenix/Mix template for projects at [Nimble](https://nimblehq.co/).", elixir: "~> 1.13.3", elixirc_paths: elixirc_paths(Mix.env()), From ff82e8a7b03d9fbc762fc522beafd9d892651d38 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 17:23:22 +0700 Subject: [PATCH 06/61] Fix credo warning --- lib/mix/tasks/nimble_template.bump_version.ex | 2 +- lib/nimble_template/version.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/nimble_template.bump_version.ex b/lib/mix/tasks/nimble_template.bump_version.ex index fd283ebf..61b6a728 100644 --- a/lib/mix/tasks/nimble_template.bump_version.ex +++ b/lib/mix/tasks/nimble_template.bump_version.ex @@ -28,7 +28,7 @@ defmodule Mix.Tasks.NimbleTemplate.BumpVersion do {[], [new_version], []} -> new_version - _ -> + _other -> Mix.raise("Invalid format. Please use `mix nimble_template.bump_version new_version`") end end diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index 29d57e9c..85dfd293 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -24,7 +24,7 @@ defmodule NimbleTemplate.Version do end defp included_git_action?(%{included_git_action?: true}), do: true - defp included_git_action?(_), do: false + defp included_git_action?(_opts), do: false defp bump_version_to(current_version, new_version) do Generator.replace_content( From 272bb14aaac965ddd9bb54fd2851f7e6c64358e5 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 17:42:34 +0700 Subject: [PATCH 07/61] Adjust the test --- test/nimble_template/version_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index 00229d34..59fd108d 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -52,11 +52,11 @@ defmodule NimbleTemplate.VersionTest do end assert_file("mix.exs", fn file -> - assert file =~ "version: \"#{current_version}\"" + refute file =~ "version: \"#{new_version}\"" end) assert_file("README.md", fn file -> - assert file =~ "{:nimble_template, \"~> #{current_version}\", only: :dev, runtime: false}," + refute file =~ "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," end) end end From 8d6bb025fc2f9789fbb0318cecd45d24dddc2e9b Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 17:50:17 +0700 Subject: [PATCH 08/61] Add the git push action --- lib/nimble_template/version.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index 85dfd293..54125731 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -48,5 +48,7 @@ defmodule NimbleTemplate.Version do defp git_add_and_push(new_version) do Mix.shell().cmd("git add mix.exs README.md") Mix.shell().cmd("git commit -m \"Bump to #{new_version}\"") + + Mix.shell().cmd("git push origin chore/bump-to-#{new_version} -f") end end From 10a94f998436ba2b937f770512445882f6a35ff4 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 23:06:57 +0700 Subject: [PATCH 09/61] Adjust the test file --- lib/mix/tasks/nimble_template.bump_version.ex | 4 +++- test/nimble_template/version_test.exs | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/mix/tasks/nimble_template.bump_version.ex b/lib/mix/tasks/nimble_template.bump_version.ex index 61b6a728..1d31cf57 100644 --- a/lib/mix/tasks/nimble_template.bump_version.ex +++ b/lib/mix/tasks/nimble_template.bump_version.ex @@ -29,7 +29,9 @@ defmodule Mix.Tasks.NimbleTemplate.BumpVersion do new_version _other -> - Mix.raise("Invalid format. Please use `mix nimble_template.bump_version new_version`") + Mix.raise( + "Invalid command. Check `mix help nimble_template.bump_version` for more information." + ) end end end diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index 59fd108d..a3051474 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -3,6 +3,12 @@ defmodule NimbleTemplate.VersionTest do alias NimbleTemplate.Version + setup do + on_exit(fn -> + Mix.shell().cmd("git checkout mix.exs README.md") + end) + end + describe "bump/1" do test "updates the version in mix.exs and README.md files given a valid version number" do current_version = Mix.Project.config()[:version] @@ -24,10 +30,12 @@ defmodule NimbleTemplate.VersionTest do assert_file("mix.exs", fn file -> assert file =~ "version: \"#{new_version}\"" + refute file =~ "version: \"#{current_version}\"" end) assert_file("README.md", fn file -> assert file =~ "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," + refute file =~ "{:nimble_template, \"~> #{current_version}\", only: :dev, runtime: false}," end) end @@ -52,10 +60,12 @@ defmodule NimbleTemplate.VersionTest do end assert_file("mix.exs", fn file -> + assert file =~ "version: \"#{current_version}\"" refute file =~ "version: \"#{new_version}\"" end) assert_file("README.md", fn file -> + assert file =~ "{:nimble_template, \"~> #{current_version}\", only: :dev, runtime: false}," refute file =~ "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," end) end From da7de39ffeda51d20697c941ab5ba8908d1a66a3 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 23:42:47 +0700 Subject: [PATCH 10/61] Add the Bump version workflow --- .github/workflows/bump_version.yml | 91 ++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .github/workflows/bump_version.yml diff --git a/.github/workflows/bump_version.yml b/.github/workflows/bump_version.yml new file mode 100644 index 00000000..0fff71f5 --- /dev/null +++ b/.github/workflows/bump_version.yml @@ -0,0 +1,91 @@ +name: Bump Version + +on: + workflow_dispatch: + inputs: + newVersion: + description: "New version" + required: true + type: string + +env: + PHOENIX_VERSION: 1.6.6 + MIX_ENV: test + +jobs: + release_version_test: + name: Bump version + runs-on: ubuntu-latest + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: ${{ github.head_ref }} + + - name: Setup asdf + uses: asdf-vm/actions/setup@v1 + + - name: Cache asdf + uses: actions/cache@v3 + with: + path: /home/runner/.asdf + key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} + restore-keys: ${{ runner.os }}-asdf- + + - name: Install dependencies in .tool-versions + uses: asdf-vm/actions/install@v1 + + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + + - name: Cache Elixir build + uses: actions/cache@v3 + with: + path: | + _build + deps + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix- + + - name: Install Dependencies + run: mix deps.get + + - name: Compile dependencies + run: mix compile --warnings-as-errors --all-warnings + + - name: Install Phoenix ${{ env.PHOENIX_VERSION }} + run: make install_phoenix PHOENIX_VERSION=${{ env.PHOENIX_VERSION }} + + - name: Bump version + run: mix nimble_template.bump_version ${{ github.event.inputs.newVersion }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.WIKI_ACTION_TOKEN }} + commit-message: Bump to ${{ github.event.inputs.newVersion }} + committer: Dev Nimble + branch: chore/bump-to-${{ github.event.inputs.newVersion }} + delete-branch: true + title: [Chore] Bump to ${{ github.event.inputs.newVersion }} + body: | + ## What happened + + Bump to ${{ github.event.inputs.newVersion }} + + ## Insight + + Created by the Bump Version workflow. + + ## Proof Of Work + + Check the file changes From 694a0e2d8e76229a539ce867cee2fa9b61048317 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 7 Jun 2022 23:44:53 +0700 Subject: [PATCH 11/61] Remove the git action --- lib/mix/tasks/nimble_template.bump_version.ex | 4 +-- lib/nimble_template/version.ex | 25 +------------------ 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/mix/tasks/nimble_template.bump_version.ex b/lib/mix/tasks/nimble_template.bump_version.ex index 1d31cf57..e7a5d290 100644 --- a/lib/mix/tasks/nimble_template.bump_version.ex +++ b/lib/mix/tasks/nimble_template.bump_version.ex @@ -15,12 +15,12 @@ defmodule Mix.Tasks.NimbleTemplate.BumpVersion do use Mix.Task - alias NimbleTemplate.Version +alias NimbleTemplate.Version def run(args) do new_version = parse_opts(args) - Version.bump(new_version, %{included_git_action?: true}) + Version.bump(new_version) end defp parse_opts(args) do diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index 54125731..0681b455 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -3,29 +3,18 @@ defmodule NimbleTemplate.Version do alias NimbleTemplate.Generator - def bump(new_version, opts \\ %{}) do + def bump(new_version) do current_version = Mix.Project.config()[:version] if new_version > current_version do - if included_git_action?(opts) do - git_checkout_chore_branch(new_version) - end - bump_version_to(current_version, new_version) - if included_git_action?(opts) do - git_add_and_push(new_version) - end - :ok else Mix.raise("The new version must be greater than #{current_version}") end end - defp included_git_action?(%{included_git_action?: true}), do: true - defp included_git_action?(_opts), do: false - defp bump_version_to(current_version, new_version) do Generator.replace_content( "mix.exs", @@ -39,16 +28,4 @@ defmodule NimbleTemplate.Version do "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," ) end - - defp git_checkout_chore_branch(new_version) do - Mix.shell().cmd("git checkout develop") - Mix.shell().cmd("git checkout -b chore/bump-to-#{new_version}") - end - - defp git_add_and_push(new_version) do - Mix.shell().cmd("git add mix.exs README.md") - Mix.shell().cmd("git commit -m \"Bump to #{new_version}\"") - - Mix.shell().cmd("git push origin chore/bump-to-#{new_version} -f") - end end From fa86d75ce4360d27efe58baeee514f6aafcdc1ed Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 08:57:42 +0700 Subject: [PATCH 12/61] Mix format --- lib/mix/tasks/nimble_template.bump_version.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/nimble_template.bump_version.ex b/lib/mix/tasks/nimble_template.bump_version.ex index e7a5d290..7ab2ee2b 100644 --- a/lib/mix/tasks/nimble_template.bump_version.ex +++ b/lib/mix/tasks/nimble_template.bump_version.ex @@ -15,7 +15,7 @@ defmodule Mix.Tasks.NimbleTemplate.BumpVersion do use Mix.Task -alias NimbleTemplate.Version + alias NimbleTemplate.Version def run(args) do new_version = parse_opts(args) From 8a0f97488fdf4bc0da852e8eeab73f737e256c55 Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 09:41:31 +0700 Subject: [PATCH 13/61] Correct the workflow syntax --- .github/workflows/bump_version.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/bump_version.yml b/.github/workflows/bump_version.yml index 0fff71f5..8d5dcdac 100644 --- a/.github/workflows/bump_version.yml +++ b/.github/workflows/bump_version.yml @@ -70,22 +70,25 @@ jobs: - name: Create Pull Request uses: peter-evans/create-pull-request@v4 - with: + with: + assignees: andyduong1920 token: ${{ secrets.WIKI_ACTION_TOKEN }} - commit-message: Bump to ${{ github.event.inputs.newVersion }} - committer: Dev Nimble - branch: chore/bump-to-${{ github.event.inputs.newVersion }} + commit-message: Bump version to ${{ github.event.inputs.newVersion }} + committer: Nimble Bot + branch: chore/bump-version-to-${{ github.event.inputs.newVersion }} delete-branch: true - title: [Chore] Bump to ${{ github.event.inputs.newVersion }} + title: '[Chore] Bump version to ${{ github.event.inputs.newVersion }}' + labels: | + type : chore body: | ## What happened - Bump to ${{ github.event.inputs.newVersion }} + Bump version to ${{ github.event.inputs.newVersion }} ## Insight - Created by the Bump Version workflow. + Automated creates by the Bump Version workflow. ## Proof Of Work - Check the file changes + On the Files changed tab From 4b0f3f281db7c58f8b52e4e75f6ab469ff79e985 Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 09:59:12 +0700 Subject: [PATCH 14/61] Update the help content --- lib/mix/tasks/nimble_template.bump_version.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/nimble_template.bump_version.ex b/lib/mix/tasks/nimble_template.bump_version.ex index 7ab2ee2b..24337757 100644 --- a/lib/mix/tasks/nimble_template.bump_version.ex +++ b/lib/mix/tasks/nimble_template.bump_version.ex @@ -10,7 +10,7 @@ defmodule Mix.Tasks.NimbleTemplate.BumpVersion do # Usage - mix help nimble_template.bump_version # Print help - - mix nimble_template.bump_version [new_version] # Bump the template into the [new_version]. + - mix nimble_template.bump_version [new_version] # Bump the template version to the [new_version]. """ use Mix.Task From 8399948d9cb34c35145331802d22d4cf42ca86c9 Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 10:11:04 +0700 Subject: [PATCH 15/61] Update README and adjust the Insight for the Bump version PR --- .github/workflows/bump_version.yml | 2 +- README.md | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/workflows/bump_version.yml b/.github/workflows/bump_version.yml index 8d5dcdac..f9e5c236 100644 --- a/.github/workflows/bump_version.yml +++ b/.github/workflows/bump_version.yml @@ -87,7 +87,7 @@ jobs: ## Insight - Automated creates by the Bump Version workflow. + Automatically created by the Bump Version workflow. ## Proof Of Work diff --git a/README.md b/README.md index 280e9dd9..af762ce9 100644 --- a/README.md +++ b/README.md @@ -65,23 +65,19 @@ mix nimble_template.gen --mix # Apply the Mix template The testing documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki) -### Release +### Release process -Set the `HEX_API_KEY` as a Github secret (skip this step if it has been done). +1. Set the `HEX_API_KEY` as a Github secret (skip this step if it has been done). -The release process follows the [Git flow](https://nimblehq.co/compass/development/version-control/release-management). +2. Visit the [Bump Version Github Action Workflow](https://github.com/nimblehq/elixir-templates/actions/workflows/bump_version.yml). -1. Bump the new version on local +3. Trigger the workflow with the next ``. That workflow will create a PR into the `develop` branch with the title `[Chore] Bump version to `. - ```bash - mix nimble_template.bump_version new_version - ``` +4. Merge the Bump version PR above into the `develop` branch. -2. Open a PR to develop. +5. Create the `release/` from the `develop` branch, pointing to the `master` branch. -3. Once that bump_version PR is merged, create the `release/` from the `develop` branch, points to the `master` branch. - -4. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). +6. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). ## Contributing From 683cf15f1141e0b5376cc17670d450e1d7694b00 Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 16:23:10 +0700 Subject: [PATCH 16/61] Update the codeowner --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f8972bfe..cacd98c6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,7 +2,7 @@ * @andyduong1920 # Team Members -* @bterone @byhbt @hanam1ni @junan @longnd @rosle @topnimble +* @bterone @byhbt @hanam1ni @junan @longnd @rosle @topnimble @Nihisil @nvminhtue @liamstevens111 # Engineering Leads CODEOWNERS @nimblehq/engineering-leads From b832993fe85c58307c8ad913f872a7ae78e08fd7 Mon Sep 17 00:00:00 2001 From: Tue Nguyen Date: Mon, 30 May 2022 10:58:31 +0700 Subject: [PATCH 17/61] [214] Add FAQ section into Readme --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index e4bfe3d6..d3889523 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,19 @@ Once the release branch is merged into the `master` branch, Github Action automa Contributions, issues, and feature requests are welcome!
Feel free to check [issues page](https://github.com/nimblehq/elixir-templates/issues). +## FAQ + +### 1. Getting `(Mix) The task "phx.new" could not be found` error + +The Phoenix application generator is missing. By solving this problem, you need to run +``` bash +mix archive.install hex phx_new +``` +or +```bash +mix archive.install hex phx_new #{specific-version} +``` + ## License This project is Copyright (c) 2014 and onwards. It is free software, and may be redistributed under the terms specified in the [LICENSE] file. From d34b9b366a8711f4f5451ef9482dbf2c474351f1 Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 16:18:59 +0700 Subject: [PATCH 18/61] Add the Git addon --- lib/nimble_template/addons/git.ex | 22 ++++++++ .../templates/variants/mix/template.ex | 1 + .../templates/variants/phoenix/template.ex | 1 + test/nimble_template/addons/git_test.exs | 55 +++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 lib/nimble_template/addons/git.ex create mode 100644 test/nimble_template/addons/git_test.exs diff --git a/lib/nimble_template/addons/git.ex b/lib/nimble_template/addons/git.ex new file mode 100644 index 00000000..0953d4b5 --- /dev/null +++ b/lib/nimble_template/addons/git.ex @@ -0,0 +1,22 @@ +defmodule NimbleTemplate.Addons.Git do + @moduledoc false + + use NimbleTemplate.Addons.Addon + + @impl true + def do_apply(%Project{} = project, _opts) do + Generator.append_content(".gitignore", """ + # Mac OS + .DS_Store + + # IDE + .idea + .vscode + + # Iex + .iex.exs + """) + + project + end +end diff --git a/lib/nimble_template/templates/variants/mix/template.ex b/lib/nimble_template/templates/variants/mix/template.ex index 43b796cd..a619330e 100644 --- a/lib/nimble_template/templates/variants/mix/template.ex +++ b/lib/nimble_template/templates/variants/mix/template.ex @@ -21,6 +21,7 @@ defmodule NimbleTemplate.Templates.Mix.Template do |> Addons.Dialyxir.apply() |> Addons.ExCoveralls.apply() |> Addons.Faker.apply() + |> Addons.Git.apply() end defp apply_optional_mix_addons(project) do diff --git a/lib/nimble_template/templates/variants/phoenix/template.ex b/lib/nimble_template/templates/variants/phoenix/template.ex index 9f4d714c..9290a114 100644 --- a/lib/nimble_template/templates/variants/phoenix/template.ex +++ b/lib/nimble_template/templates/variants/phoenix/template.ex @@ -39,6 +39,7 @@ defmodule NimbleTemplate.Templates.Phoenix.Template do |> Addons.ExCoveralls.apply() |> Addons.Mimic.apply() |> Addons.Faker.apply() + |> Addons.Git.apply() end defp apply_default_phoenix_addons(project) do diff --git a/test/nimble_template/addons/git_test.exs b/test/nimble_template/addons/git_test.exs new file mode 100644 index 00000000..786a3073 --- /dev/null +++ b/test/nimble_template/addons/git_test.exs @@ -0,0 +1,55 @@ +defmodule NimbleTemplate.Addons.GitTest do + use NimbleTemplate.AddonCase, async: false + + describe "#apply/2" do + test "adjusts the .gitignore file", %{ + project: project, + test_project_path: test_project_path + } do + in_test_project(test_project_path, fn -> + Addons.Git.apply(project) + + assert_file(".gitignore", fn file -> + assert file =~ """ + # Mac OS + .DS_Store + + # IDE + .idea + .vscode + + # Iex + .iex.exs + """ + end) + end) + end + end + + describe "#apply/2 with mix_project" do + @describetag mix_project?: true + + test "adjusts the .gitignore file", %{ + project: project, + test_project_path: test_project_path + } do + in_test_project(test_project_path, fn -> + Addons.Git.apply(project) + + assert_file(".gitignore", fn file -> + assert file =~ """ + # Mac OS + .DS_Store + + # IDE + .idea + .vscode + + # Iex + .iex.exs + """ + end) + end) + end + end +end From 0e563b31acd24edbd02325824e938080346bafee Mon Sep 17 00:00:00 2001 From: An Duong Date: Wed, 8 Jun 2022 18:22:05 +0700 Subject: [PATCH 19/61] Add .idea and .vscode into .prettierignore --- priv/templates/nimble_template/.prettierignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/priv/templates/nimble_template/.prettierignore b/priv/templates/nimble_template/.prettierignore index 63c8d9aa..3c62f8cc 100644 --- a/priv/templates/nimble_template/.prettierignore +++ b/priv/templates/nimble_template/.prettierignore @@ -6,3 +6,5 @@ priv cover/ .github/ README.md +.idea +.vscode From 8969ed50a1c46caa3953de5ced782627c4b87770 Mon Sep 17 00:00:00 2001 From: An Duong Date: Thu, 9 Jun 2022 17:40:25 +0700 Subject: [PATCH 20/61] Add the VersionUpgradeHelper --- lib/nimble_template/helpers/generator.ex | 18 ++- lib/nimble_template/projects/project.ex | 20 +++- lib/nimble_template/version.ex | 144 +++++++++++++++++++++++ test/nimble_template/version_test.exs | 85 ++++++++++++- 4 files changed, 261 insertions(+), 6 deletions(-) diff --git a/lib/nimble_template/helpers/generator.ex b/lib/nimble_template/helpers/generator.ex index 5787be83..20d7b670 100644 --- a/lib/nimble_template/helpers/generator.ex +++ b/lib/nimble_template/helpers/generator.ex @@ -24,7 +24,7 @@ defmodule NimbleTemplate.Generator do def rename_file(old_path, new_path), do: File.rename(old_path, new_path) - def replace_content(file_path, anchor, content) do + def replace_content(file_path, anchor, content, raise_exception \\ true) do file = Path.join([file_path]) file_content = @@ -40,7 +40,21 @@ defmodule NimbleTemplate.Generator do File.write!(file, [left, content, right]) :error -> - Mix.raise(~s[Could not find #{anchor} in #{file_path}]) + if raise_exception do + Mix.raise(~s[Could not find #{anchor} in #{file_path}]) + else + :error + end + end + end + + def replace_content_all(file_path, anchor, content) do + case replace_content(file_path, anchor, content, false) do + :ok -> + replace_content_all(file_path, anchor, content) + + :error -> + nil end end diff --git a/lib/nimble_template/projects/project.ex b/lib/nimble_template/projects/project.ex index ef31774b..86453c33 100644 --- a/lib/nimble_template/projects/project.ex +++ b/lib/nimble_template/projects/project.ex @@ -16,10 +16,9 @@ defmodule NimbleTemplate.Projects.Project do # Dependency Versions alpine_version: @alpine_version, elixir_version: @elixir_version, - elixir_asdf_version: - "#{@elixir_version}-otp-#{@erlang_version |> String.split(".") |> List.first()}", erlang_version: @erlang_version, node_asdf_version: @node_asdf_version, + elixir_asdf_version: nil, # Variants api_project?: false, live_project?: false, @@ -38,10 +37,25 @@ defmodule NimbleTemplate.Projects.Project do api_project?: api_project?(opts), web_project?: web_project?(opts), live_project?: live_project?(opts), - mix_project?: mix_project?(opts) + mix_project?: mix_project?(opts), + elixir_asdf_version: "#{@elixir_version}-otp-#{get_otp_major_version(@erlang_version)}" } end + def alpine_version, do: @alpine_version + + def elixir_version, do: @elixir_version + + def erlang_version, do: @erlang_version + + def node_asdf_version, do: @node_asdf_version + + def get_otp_major_version(erlang_version) do + erlang_version + |> String.split(".") + |> List.first() + end + defp api_project?(opts), do: opts[:api] === true defp web_project?(opts), do: opts[:web] === true || opts[:live] === true diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index 0681b455..c5abfd7e 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -2,6 +2,7 @@ defmodule NimbleTemplate.Version do @moduledoc false alias NimbleTemplate.Generator + alias NimbleTemplate.Projects.Project def bump(new_version) do current_version = Mix.Project.config()[:version] @@ -15,6 +16,31 @@ defmodule NimbleTemplate.Version do end end + def upgrade_elixir_erlang_node_and_alpine(versions) do + elixir_version = Map.get(versions, :elixir_version, nil) + erlang_version = Map.get(versions, :erlang_version, nil) + node_version = Map.get(versions, :node_version, nil) + alpine_version = Map.get(versions, :alpine_version, nil) + + if elixir_version do + upgrade_elixir(elixir_version) + end + + if erlang_version do + upgrade_erlang(erlang_version) + end + + if alpine_version do + upgrade_alpine(alpine_version) + end + + if node_version do + upgrade_node(node_version) + end + + :ok + end + defp bump_version_to(current_version, new_version) do Generator.replace_content( "mix.exs", @@ -28,4 +54,122 @@ defmodule NimbleTemplate.Version do "{:nimble_template, \"~> #{new_version}\", only: :dev, runtime: false}," ) end + + defp upgrade_elixir(new_version) do + current_version = Project.elixir_version() + + Generator.replace_content( + "lib/nimble_template/projects/project.ex", + "@elixir_version \"#{current_version}\"", + "@elixir_version \"#{new_version}\"" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/asdf_tool_version_test.exs", + "elixir #{current_version}-otp-#{}", + "elixir #{new_version}-otp-#{}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/github_test.exs", + "Elixir #{current_version}", + "Elixir #{new_version}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/readme_test.exs", + "Elixir #{current_version}", + "Elixir #{new_version}" + ) + + Generator.replace_content( + "test/nimble_template/addons/variants/docker_test.exs", + "ELIXIR_IMAGE_VERSION=#{current_version}", + "ELIXIR_IMAGE_VERSION=#{new_version}" + ) + end + + defp upgrade_erlang(new_version) do + current_version = Project.erlang_version() + + Generator.replace_content( + "lib/nimble_template/projects/project.ex", + "@erlang_version \"#{current_version}\"", + "@erlang_version \"#{new_version}\"" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/asdf_tool_version_test.exs", + "erlang #{current_version}", + "erlang #{new_version}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/asdf_tool_version_test.exs", + "-otp-#{Project.get_otp_major_version(current_version)}", + "-otp-#{Project.get_otp_major_version(new_version)}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/github_test.exs", + "Erlang #{current_version}", + "Erlang #{new_version}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/readme_test.exs", + "Erlang #{current_version}", + "Erlang #{new_version}" + ) + + Generator.replace_content( + "test/nimble_template/addons/variants/docker_test.exs", + "ERLANG_IMAGE_VERSION=#{current_version}", + "ERLANG_IMAGE_VERSION=#{new_version}" + ) + end + + defp upgrade_alpine(new_version) do + current_version = Project.alpine_version() + + Generator.replace_content( + "lib/nimble_template/projects/project.ex", + "@alpine_version \"#{current_version}\"", + "@alpine_version \"#{new_version}\"" + ) + + Generator.replace_content( + "test/nimble_template/addons/variants/docker_test.exs", + "RELEASE_IMAGE_VERSION=#{current_version}", + "RELEASE_IMAGE_VERSION=#{new_version}" + ) + end + + defp upgrade_node(new_version) do + current_version = Project.node_asdf_version() + + Generator.replace_content( + "lib/nimble_template/projects/project.ex", + "@node_asdf_version \"#{current_version}\"", + "@node_asdf_version \"#{new_version}\"" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/asdf_tool_version_test.exs", + "nodejs #{current_version}", + "nodejs #{new_version}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/github_test.exs", + "Node #{current_version}", + "Node #{new_version}" + ) + + Generator.replace_content_all( + "test/nimble_template/addons/readme_test.exs", + "Node #{current_version}", + "Node #{new_version}" + ) + end end diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index a3051474..7ef94aad 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -5,7 +5,7 @@ defmodule NimbleTemplate.VersionTest do setup do on_exit(fn -> - Mix.shell().cmd("git checkout mix.exs README.md") + Mix.shell().cmd("git checkout .") end) end @@ -70,4 +70,87 @@ defmodule NimbleTemplate.VersionTest do end) end end + + describe "upgrade_elixir_erlang_node_and_alpine/1" do + test "upgrade elixir version given the new elixir_version" do + assert Version.upgrade_elixir_erlang_node_and_alpine(%{elixir_version: "130.13.4"}) == :ok + + assert_file("lib/nimble_template/projects/project.ex", fn file -> + assert file =~ "@elixir_version \"130.13.4\"" + end) + + assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> + assert file =~ "elixir 130.13.4-otp-" + end) + + assert_file("test/nimble_template/addons/github_test.exs", fn file -> + assert file =~ "Elixir 130.13.4" + end) + + assert_file("test/nimble_template/addons/readme_test.exs", fn file -> + assert file =~ "Elixir 130.13.4" + end) + + assert_file("test/nimble_template/addons/variants/docker_test.exs", fn file -> + assert file =~ "ELIXIR_IMAGE_VERSION=130.13.4" + end) + end + + test "upgrade erlang version given the new erlang_version" do + assert Version.upgrade_elixir_erlang_node_and_alpine(%{erlang_version: "250.0.1"}) == :ok + + assert_file("lib/nimble_template/projects/project.ex", fn file -> + assert file =~ "@erlang_version \"250.0.1\"" + end) + + assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> + assert file =~ "erlang 250.0.1" + assert file =~ "-otp-250" + end) + + assert_file("test/nimble_template/addons/github_test.exs", fn file -> + assert file =~ "Erlang 250.0.1" + end) + + assert_file("test/nimble_template/addons/readme_test.exs", fn file -> + assert file =~ "Erlang 250.0.1" + end) + + assert_file("test/nimble_template/addons/variants/docker_test.exs", fn file -> + assert file =~ "ERLANG_IMAGE_VERSION=250.0.1" + end) + end + + test "upgrade node version given the new node_version" do + assert Version.upgrade_elixir_erlang_node_and_alpine(%{node_version: "180.3.0"}) == :ok + + assert_file("lib/nimble_template/projects/project.ex", fn file -> + assert file =~ "@node_asdf_version \"180.3.0\"" + end) + + assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> + assert file =~ "nodejs 180.3.0" + end) + + assert_file("test/nimble_template/addons/github_test.exs", fn file -> + assert file =~ "Node 180.3.0" + end) + + assert_file("test/nimble_template/addons/readme_test.exs", fn file -> + assert file =~ "Node 180.3.0" + end) + end + + test "upgrade alpine version given the new alpine_version" do + assert Version.upgrade_elixir_erlang_node_and_alpine(%{alpine_version: "300.14.6"}) == :ok + + assert_file("lib/nimble_template/projects/project.ex", fn file -> + assert file =~ "@alpine_version \"300.14.6\"" + end) + + assert_file("test/nimble_template/addons/variants/docker_test.exs", fn file -> + assert file =~ "RELEASE_IMAGE_VERSION=300.14.6" + end) + end + end end From 2cf658f605a02c9f2125e746298a23fee909d389 Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 09:56:05 +0700 Subject: [PATCH 21/61] Adjust the .tool-version --- lib/nimble_template/version.ex | 24 ++++++++++++++++++++++++ test/nimble_template/version_test.exs | 13 +++++++++++++ 2 files changed, 37 insertions(+) diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index c5abfd7e..4b0631d8 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -64,6 +64,12 @@ defmodule NimbleTemplate.Version do "@elixir_version \"#{new_version}\"" ) + Generator.replace_content( + ".tool-versions", + "elixir #{current_version}", + "elixir #{new_version}" + ) + Generator.replace_content_all( "test/nimble_template/addons/asdf_tool_version_test.exs", "elixir #{current_version}-otp-#{}", @@ -98,6 +104,18 @@ defmodule NimbleTemplate.Version do "@erlang_version \"#{new_version}\"" ) + Generator.replace_content( + ".tool-versions", + "erlang #{current_version}", + "erlang #{new_version}" + ) + + Generator.replace_content( + ".tool-versions", + "-otp-#{Project.get_otp_major_version(current_version)}", + "-otp-#{Project.get_otp_major_version(new_version)}" + ) + Generator.replace_content_all( "test/nimble_template/addons/asdf_tool_version_test.exs", "erlang #{current_version}", @@ -154,6 +172,12 @@ defmodule NimbleTemplate.Version do "@node_asdf_version \"#{new_version}\"" ) + Generator.replace_content( + ".tool-versions", + "nodejs #{current_version}", + "nodejs #{new_version}" + ) + Generator.replace_content_all( "test/nimble_template/addons/asdf_tool_version_test.exs", "nodejs #{current_version}", diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index 7ef94aad..39f068da 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -79,6 +79,10 @@ defmodule NimbleTemplate.VersionTest do assert file =~ "@elixir_version \"130.13.4\"" end) + assert_file(".tool-versions", fn file -> + assert file =~ "elixir 130.13.4-otp-" + end) + assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> assert file =~ "elixir 130.13.4-otp-" end) @@ -103,6 +107,11 @@ defmodule NimbleTemplate.VersionTest do assert file =~ "@erlang_version \"250.0.1\"" end) + assert_file(".tool-versions", fn file -> + assert file =~ "erlang 250.0.1" + assert file =~ "-otp-250" + end) + assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> assert file =~ "erlang 250.0.1" assert file =~ "-otp-250" @@ -128,6 +137,10 @@ defmodule NimbleTemplate.VersionTest do assert file =~ "@node_asdf_version \"180.3.0\"" end) + assert_file(".tool-versions", fn file -> + assert file =~ "nodejs 180.3.0" + end) + assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> assert file =~ "nodejs 180.3.0" end) From 0065a70cc1a28b8c3e0a440c6cb12cc4c284586e Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 10:10:25 +0700 Subject: [PATCH 22/61] Rename the method --- lib/nimble_template/version.ex | 10 +++++----- test/nimble_template/version_test.exs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index 4b0631d8..fc0e9517 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -16,11 +16,11 @@ defmodule NimbleTemplate.Version do end end - def upgrade_elixir_erlang_node_and_alpine(versions) do - elixir_version = Map.get(versions, :elixir_version, nil) - erlang_version = Map.get(versions, :erlang_version, nil) - node_version = Map.get(versions, :node_version, nil) - alpine_version = Map.get(versions, :alpine_version, nil) + def upgrade_stack(elixir_erlang_node_alpine_versions) do + elixir_version = Map.get(elixir_erlang_node_alpine_versions, :elixir_version, nil) + erlang_version = Map.get(elixir_erlang_node_alpine_versions, :erlang_version, nil) + node_version = Map.get(elixir_erlang_node_alpine_versions, :node_version, nil) + alpine_version = Map.get(elixir_erlang_node_alpine_versions, :alpine_version, nil) if elixir_version do upgrade_elixir(elixir_version) diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index 39f068da..4a57a16b 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -71,9 +71,9 @@ defmodule NimbleTemplate.VersionTest do end end - describe "upgrade_elixir_erlang_node_and_alpine/1" do + describe "upgrade_stack/1" do test "upgrade elixir version given the new elixir_version" do - assert Version.upgrade_elixir_erlang_node_and_alpine(%{elixir_version: "130.13.4"}) == :ok + assert Version.upgrade_stack(%{elixir_version: "130.13.4"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@elixir_version \"130.13.4\"" @@ -101,7 +101,7 @@ defmodule NimbleTemplate.VersionTest do end test "upgrade erlang version given the new erlang_version" do - assert Version.upgrade_elixir_erlang_node_and_alpine(%{erlang_version: "250.0.1"}) == :ok + assert Version.upgrade_stack(%{erlang_version: "250.0.1"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@erlang_version \"250.0.1\"" @@ -131,7 +131,7 @@ defmodule NimbleTemplate.VersionTest do end test "upgrade node version given the new node_version" do - assert Version.upgrade_elixir_erlang_node_and_alpine(%{node_version: "180.3.0"}) == :ok + assert Version.upgrade_stack(%{node_version: "180.3.0"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@node_asdf_version \"180.3.0\"" @@ -155,7 +155,7 @@ defmodule NimbleTemplate.VersionTest do end test "upgrade alpine version given the new alpine_version" do - assert Version.upgrade_elixir_erlang_node_and_alpine(%{alpine_version: "300.14.6"}) == :ok + assert Version.upgrade_stack(%{alpine_version: "300.14.6"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@alpine_version \"300.14.6\"" From 5c87752e7eb346c52503c67cfe9d1cd5e41620c4 Mon Sep 17 00:00:00 2001 From: An Duong Date: Thu, 9 Jun 2022 17:51:07 +0700 Subject: [PATCH 23/61] Upgrade Elixir, Erlang and Alpine version --- lib/nimble_template/projects/project.ex | 6 +++--- .../addons/asdf_tool_version_test.exs | 12 ++++++------ test/nimble_template/addons/github_test.exs | 12 ++++++------ test/nimble_template/addons/readme_test.exs | 12 ++++++------ test/nimble_template/addons/variants/docker_test.exs | 6 +++--- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/nimble_template/projects/project.ex b/lib/nimble_template/projects/project.ex index 86453c33..a9a5dfaa 100644 --- a/lib/nimble_template/projects/project.ex +++ b/lib/nimble_template/projects/project.ex @@ -1,9 +1,9 @@ defmodule NimbleTemplate.Projects.Project do @moduledoc false - @alpine_version "3.15.0" - @elixir_version "1.13.3" - @erlang_version "24.2.2" + @alpine_version "3.14.6" + @elixir_version "1.13.4" + @erlang_version "25.0.1" @node_asdf_version "16.15.0" defstruct base_module: nil, diff --git a/test/nimble_template/addons/asdf_tool_version_test.exs b/test/nimble_template/addons/asdf_tool_version_test.exs index a566a312..3923bf60 100644 --- a/test/nimble_template/addons/asdf_tool_version_test.exs +++ b/test/nimble_template/addons/asdf_tool_version_test.exs @@ -11,8 +11,8 @@ defmodule NimbleTemplate.Addons.AsdfToolVersionTest do assert_file(".tool-versions", fn file -> assert file =~ """ - erlang 24.2.2 - elixir 1.13.3-otp-24 + erlang 25.0.1 + elixir 1.13.4-otp-25 nodejs 16.15.0 """ end) @@ -32,8 +32,8 @@ defmodule NimbleTemplate.Addons.AsdfToolVersionTest do assert_file(".tool-versions", fn file -> assert file =~ """ - erlang 24.2.2 - elixir 1.13.3-otp-24 + erlang 25.0.1 + elixir 1.13.4-otp-25 """ refute file =~ "nodejs 16.15.0" @@ -54,8 +54,8 @@ defmodule NimbleTemplate.Addons.AsdfToolVersionTest do assert_file(".tool-versions", fn file -> assert file =~ """ - erlang 24.2.2 - elixir 1.13.3-otp-24 + erlang 25.0.1 + elixir 1.13.4-otp-25 """ refute file =~ "nodejs 16.15.0" diff --git a/test/nimble_template/addons/github_test.exs b/test/nimble_template/addons/github_test.exs index cff6c3c1..36fc6d9e 100644 --- a/test/nimble_template/addons/github_test.exs +++ b/test/nimble_template/addons/github_test.exs @@ -366,8 +366,8 @@ defmodule NimbleTemplate.Addons.GithubTest do assert_file(".github/workflows/publish_wiki.yml") assert_file(".github/wiki/Getting-Started.md", fn file -> - assert file =~ "Erlang 24.2.2" - assert file =~ "Elixir 1.13.3" + assert file =~ "Erlang 25.0.1" + assert file =~ "Elixir 1.13.4" assert file =~ "Node 16.15.0" assert file =~ "- [asdf-node](https://github.com/asdf-vm/asdf-node)" @@ -442,8 +442,8 @@ defmodule NimbleTemplate.Addons.GithubTest do assert_file(".github/workflows/publish_wiki.yml") assert_file(".github/wiki/Getting-Started.md", fn file -> - assert file =~ "Erlang 24.2.2" - assert file =~ "Elixir 1.13.3" + assert file =~ "Erlang 25.0.1" + assert file =~ "Elixir 1.13.4" refute file =~ "Node 16.15.0" refute file =~ "- [asdf-node](https://github.com/asdf-vm/asdf-node)" @@ -501,8 +501,8 @@ defmodule NimbleTemplate.Addons.GithubTest do assert_file(".github/workflows/publish_wiki.yml") assert_file(".github/wiki/Getting-Started.md", fn file -> - assert file =~ "Erlang 24.2.2" - assert file =~ "Elixir 1.13.3" + assert file =~ "Erlang 25.0.1" + assert file =~ "Elixir 1.13.4" refute file =~ "Node 16.15.0" refute file =~ "- [asdf-node](https://github.com/asdf-vm/asdf-node)" diff --git a/test/nimble_template/addons/readme_test.exs b/test/nimble_template/addons/readme_test.exs index 0f67bbe7..f294c4bb 100644 --- a/test/nimble_template/addons/readme_test.exs +++ b/test/nimble_template/addons/readme_test.exs @@ -10,8 +10,8 @@ defmodule NimbleTemplate.Addons.ReadmeTest do Addons.Readme.apply(project) assert_file("README.md", fn file -> - assert file =~ "Erlang 24.2.2" - assert file =~ "Elixir 1.13.3" + assert file =~ "Erlang 25.0.1" + assert file =~ "Elixir 1.13.4" assert file =~ "Node 16.15.0" assert file =~ "- [asdf-node](https://github.com/asdf-vm/asdf-node)" @@ -47,8 +47,8 @@ defmodule NimbleTemplate.Addons.ReadmeTest do Addons.Readme.apply(project) assert_file("README.md", fn file -> - assert file =~ "Erlang 24.2.2" - assert file =~ "Elixir 1.13.3" + assert file =~ "Erlang 25.0.1" + assert file =~ "Elixir 1.13.4" refute file =~ "Node 16.15.0" refute file =~ "- [asdf-node](https://github.com/asdf-vm/asdf-node)" @@ -84,8 +84,8 @@ defmodule NimbleTemplate.Addons.ReadmeTest do Addons.Readme.apply(project) assert_file("README.md", fn file -> - assert file =~ "Erlang 24.2.2" - assert file =~ "Elixir 1.13.3" + assert file =~ "Erlang 25.0.1" + assert file =~ "Elixir 1.13.4" refute file =~ "Node 16.15.0" refute file =~ "- [asdf-node](https://github.com/asdf-vm/asdf-node)" diff --git a/test/nimble_template/addons/variants/docker_test.exs b/test/nimble_template/addons/variants/docker_test.exs index 06910cf8..c3f84b1a 100644 --- a/test/nimble_template/addons/variants/docker_test.exs +++ b/test/nimble_template/addons/variants/docker_test.exs @@ -58,9 +58,9 @@ defmodule NimbleTemplate.Addons.Phoenix.DockerTest do assert_file("Dockerfile", fn file -> assert file =~ """ - ARG ELIXIR_IMAGE_VERSION=1.13.3 - ARG ERLANG_IMAGE_VERSION=24.2.2 - ARG RELEASE_IMAGE_VERSION=3.15.0 + ARG ELIXIR_IMAGE_VERSION=1.13.4 + ARG ERLANG_IMAGE_VERSION=25.0.1 + ARG RELEASE_IMAGE_VERSION=3.14.6 FROM hexpm/elixir:${ELIXIR_IMAGE_VERSION}-erlang-${ERLANG_IMAGE_VERSION}-alpine-${RELEASE_IMAGE_VERSION} AS build """ From 17259a5fcd2b527d305ba30bafb03050ed6cfa58 Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 09:57:54 +0700 Subject: [PATCH 24/61] Upgrade the .tool-versions --- .tool-versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.tool-versions b/.tool-versions index df3c3a3d..2921fffd 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ -erlang 24.2.2 -elixir 1.13.3-otp-24 +erlang 25.0.1 +elixir 1.13.4-otp-25 nodejs 16.15.0 From 4d277b04f10924591e74eaff645ceef32343eeac Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 10:37:04 +0700 Subject: [PATCH 25/61] Add the hex_formatter --- .../variants/phoenix/web/heex_formatter.ex | 29 +++++++++++++++++++ .../variants/phoenix/web/template.ex | 1 + .../phoenix/web/hex_formatter_test.exs | 24 +++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 lib/nimble_template/addons/variants/phoenix/web/heex_formatter.ex create mode 100644 test/nimble_template/addons/variants/phoenix/web/hex_formatter_test.exs diff --git a/lib/nimble_template/addons/variants/phoenix/web/heex_formatter.ex b/lib/nimble_template/addons/variants/phoenix/web/heex_formatter.ex new file mode 100644 index 00000000..e35d73a4 --- /dev/null +++ b/lib/nimble_template/addons/variants/phoenix/web/heex_formatter.ex @@ -0,0 +1,29 @@ +defmodule NimbleTemplate.Addons.Phoenix.Web.HeexFormatter do + @moduledoc false + + use NimbleTemplate.Addons.Addon + + @impl true + def do_apply(%Project{} = project, _opts) do + Generator.replace_content(".formatter.exs", "\"*.{ex,exs}\"", "\"*.{heex,ex,exs}\"") + + Generator.replace_content( + ".formatter.exs", + "\"{config,lib,test}/**/*.{ex,exs}\"", + "\"{config,lib,test}/**/*.{heex,ex,exs}\"" + ) + + Generator.replace_content( + ".formatter.exs", + """ + import_deps: [:ecto, :phoenix], + """, + """ + import_deps: [:ecto, :phoenix], + plugins: [Phoenix.LiveView.HTMLFormatter], + """ + ) + + project + end +end diff --git a/lib/nimble_template/templates/variants/phoenix/web/template.ex b/lib/nimble_template/templates/variants/phoenix/web/template.ex index 7d753f38..b7242ebf 100644 --- a/lib/nimble_template/templates/variants/phoenix/web/template.ex +++ b/lib/nimble_template/templates/variants/phoenix/web/template.ex @@ -24,6 +24,7 @@ defmodule NimbleTemplate.Templates.Phoenix.Web.Template do |> Web.StyleLint.apply() |> Web.EsBuild.apply() |> Web.PostCSS.apply() + |> Web.HeexFormatter.apply() end defp apply_optional_web_addons(project) do diff --git a/test/nimble_template/addons/variants/phoenix/web/hex_formatter_test.exs b/test/nimble_template/addons/variants/phoenix/web/hex_formatter_test.exs new file mode 100644 index 00000000..da40d2a2 --- /dev/null +++ b/test/nimble_template/addons/variants/phoenix/web/hex_formatter_test.exs @@ -0,0 +1,24 @@ +defmodule NimbleTemplate.Addons.Phoenix.Web.HeexFormatterTest do + use NimbleTemplate.AddonCase, async: false + + describe "#apply/2" do + test "adds the HTMLFormatter into the .formatter.exs", %{ + project: project, + test_project_path: test_project_path + } do + in_test_project(test_project_path, fn -> + WebAddons.HeexFormatter.apply(project) + + assert_file(".formatter.exs", fn file -> + assert file =~ """ + plugins: [Phoenix.LiveView.HTMLFormatter], + """ + + assert file =~ """ + inputs: ["*.{heex,ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{heex,ex,exs}"], + """ + end) + end) + end + end +end From e4bf3275a581622b66731ea473bce28f3b0b7b65 Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 10:46:02 +0700 Subject: [PATCH 26/61] fix the conflict version --- test/nimble_template/version_test.exs | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index 4a57a16b..f5614321 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -73,96 +73,96 @@ defmodule NimbleTemplate.VersionTest do describe "upgrade_stack/1" do test "upgrade elixir version given the new elixir_version" do - assert Version.upgrade_stack(%{elixir_version: "130.13.4"}) == :ok + assert Version.upgrade_stack(%{elixir_version: "a.b.c"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> - assert file =~ "@elixir_version \"130.13.4\"" + assert file =~ "@elixir_version \"a.b.c\"" end) assert_file(".tool-versions", fn file -> - assert file =~ "elixir 130.13.4-otp-" + assert file =~ "elixir a.b.c-otp-" end) assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> - assert file =~ "elixir 130.13.4-otp-" + assert file =~ "elixir a.b.c-otp-" end) assert_file("test/nimble_template/addons/github_test.exs", fn file -> - assert file =~ "Elixir 130.13.4" + assert file =~ "Elixir a.b.c" end) assert_file("test/nimble_template/addons/readme_test.exs", fn file -> - assert file =~ "Elixir 130.13.4" + assert file =~ "Elixir a.b.c" end) assert_file("test/nimble_template/addons/variants/docker_test.exs", fn file -> - assert file =~ "ELIXIR_IMAGE_VERSION=130.13.4" + assert file =~ "ELIXIR_IMAGE_VERSION=a.b.c" end) end test "upgrade erlang version given the new erlang_version" do - assert Version.upgrade_stack(%{erlang_version: "250.0.1"}) == :ok + assert Version.upgrade_stack(%{erlang_version: "x.y.z"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> - assert file =~ "@erlang_version \"250.0.1\"" + assert file =~ "@erlang_version \"x.y.z\"" end) assert_file(".tool-versions", fn file -> - assert file =~ "erlang 250.0.1" - assert file =~ "-otp-250" + assert file =~ "erlang x.y.z" + assert file =~ "-otp-x" end) assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> - assert file =~ "erlang 250.0.1" - assert file =~ "-otp-250" + assert file =~ "erlang x.y.z" + assert file =~ "-otp-x" end) assert_file("test/nimble_template/addons/github_test.exs", fn file -> - assert file =~ "Erlang 250.0.1" + assert file =~ "Erlang x.y.z" end) assert_file("test/nimble_template/addons/readme_test.exs", fn file -> - assert file =~ "Erlang 250.0.1" + assert file =~ "Erlang x.y.z" end) assert_file("test/nimble_template/addons/variants/docker_test.exs", fn file -> - assert file =~ "ERLANG_IMAGE_VERSION=250.0.1" + assert file =~ "ERLANG_IMAGE_VERSION=x.y.z" end) end test "upgrade node version given the new node_version" do - assert Version.upgrade_stack(%{node_version: "180.3.0"}) == :ok + assert Version.upgrade_stack(%{node_version: "a.s.d"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> - assert file =~ "@node_asdf_version \"180.3.0\"" + assert file =~ "@node_asdf_version \"a.s.d\"" end) assert_file(".tool-versions", fn file -> - assert file =~ "nodejs 180.3.0" + assert file =~ "nodejs a.s.d" end) assert_file("test/nimble_template/addons/asdf_tool_version_test.exs", fn file -> - assert file =~ "nodejs 180.3.0" + assert file =~ "nodejs a.s.d" end) assert_file("test/nimble_template/addons/github_test.exs", fn file -> - assert file =~ "Node 180.3.0" + assert file =~ "Node a.s.d" end) assert_file("test/nimble_template/addons/readme_test.exs", fn file -> - assert file =~ "Node 180.3.0" + assert file =~ "Node a.s.d" end) end test "upgrade alpine version given the new alpine_version" do - assert Version.upgrade_stack(%{alpine_version: "300.14.6"}) == :ok + assert Version.upgrade_stack(%{alpine_version: "z.x.c"}) == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> - assert file =~ "@alpine_version \"300.14.6\"" + assert file =~ "@alpine_version \"z.x.c\"" end) assert_file("test/nimble_template/addons/variants/docker_test.exs", fn file -> - assert file =~ "RELEASE_IMAGE_VERSION=300.14.6" + assert file =~ "RELEASE_IMAGE_VERSION=z.x.c" end) end end From dab94373f6b700d4926272526b9311e165b722cc Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 14:32:19 +0700 Subject: [PATCH 27/61] Add the upgrade_stack task --- .../tasks/nimble_template.upgrade_stack.ex | 48 +++++++++++++++++++ lib/nimble_template/version.ex | 8 ++-- test/nimble_template/version_test.exs | 8 ++-- 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 lib/mix/tasks/nimble_template.upgrade_stack.ex diff --git a/lib/mix/tasks/nimble_template.upgrade_stack.ex b/lib/mix/tasks/nimble_template.upgrade_stack.ex new file mode 100644 index 00000000..2bace0f1 --- /dev/null +++ b/lib/mix/tasks/nimble_template.upgrade_stack.ex @@ -0,0 +1,48 @@ +defmodule Mix.Tasks.NimbleTemplate.UpgradeStack do + @shortdoc "Upgrade Elixir, Erlang, Alpine or Node version." + + @moduledoc """ + #{@shortdoc} + + - Hex package: https://hex.pm/packages/nimble_template + - Github: https://github.com/nimblehq/elixir-templates + + # Usage + + - mix help nimble_template.upgrade_stack # Print help + - mix nimble_template.upgrade_stack elixir x.x.x # Upgrade Elixir to x.x.x + - mix nimble_template.upgrade_stack erlang x.x.x # Upgrade Erlang to x.x.x + - mix nimble_template.upgrade_stack alpine x.x.x # Upgrade Alpine to x.x.x + - mix nimble_template.upgrade_stack node x.x.x # Upgrade Node to x.x.x + - mix nimble_template.upgrade_stack elixir x.x.x erlang y.y.y alpine z.z.z node w.w.w # Upgrade Elixir, Erlang, Alpine and Node + """ + + use Mix.Task + + alias NimbleTemplate.Version + + def run(args) do + stack_versions = parse_opts(args) + + Version.upgrade_stack(stack_versions) + end + + defp parse_opts(args) do + case OptionParser.parse(args, + strict: [ + elixir: :string, + erlang: :string, + alpine: :string, + node: :string + ] + ) do + {stack_versions, [], []} -> + stack_versions + + _other -> + Mix.raise( + "Invalid command. Check `mix help nimble_template.upgrade_stack` for more information." + ) + end + end +end diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index fc0e9517..e263808b 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -17,10 +17,10 @@ defmodule NimbleTemplate.Version do end def upgrade_stack(elixir_erlang_node_alpine_versions) do - elixir_version = Map.get(elixir_erlang_node_alpine_versions, :elixir_version, nil) - erlang_version = Map.get(elixir_erlang_node_alpine_versions, :erlang_version, nil) - node_version = Map.get(elixir_erlang_node_alpine_versions, :node_version, nil) - alpine_version = Map.get(elixir_erlang_node_alpine_versions, :alpine_version, nil) + elixir_version = Keyword.get(elixir_erlang_node_alpine_versions, :elixir, nil) + erlang_version = Keyword.get(elixir_erlang_node_alpine_versions, :erlang, nil) + node_version = Keyword.get(elixir_erlang_node_alpine_versions, :node, nil) + alpine_version = Keyword.get(elixir_erlang_node_alpine_versions, :alpine, nil) if elixir_version do upgrade_elixir(elixir_version) diff --git a/test/nimble_template/version_test.exs b/test/nimble_template/version_test.exs index f5614321..a631404b 100644 --- a/test/nimble_template/version_test.exs +++ b/test/nimble_template/version_test.exs @@ -73,7 +73,7 @@ defmodule NimbleTemplate.VersionTest do describe "upgrade_stack/1" do test "upgrade elixir version given the new elixir_version" do - assert Version.upgrade_stack(%{elixir_version: "a.b.c"}) == :ok + assert Version.upgrade_stack(elixir: "a.b.c") == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@elixir_version \"a.b.c\"" @@ -101,7 +101,7 @@ defmodule NimbleTemplate.VersionTest do end test "upgrade erlang version given the new erlang_version" do - assert Version.upgrade_stack(%{erlang_version: "x.y.z"}) == :ok + assert Version.upgrade_stack(erlang: "x.y.z") == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@erlang_version \"x.y.z\"" @@ -131,7 +131,7 @@ defmodule NimbleTemplate.VersionTest do end test "upgrade node version given the new node_version" do - assert Version.upgrade_stack(%{node_version: "a.s.d"}) == :ok + assert Version.upgrade_stack(node: "a.s.d") == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@node_asdf_version \"a.s.d\"" @@ -155,7 +155,7 @@ defmodule NimbleTemplate.VersionTest do end test "upgrade alpine version given the new alpine_version" do - assert Version.upgrade_stack(%{alpine_version: "z.x.c"}) == :ok + assert Version.upgrade_stack(alpine: "z.x.c") == :ok assert_file("lib/nimble_template/projects/project.ex", fn file -> assert file =~ "@alpine_version \"z.x.c\"" From 049ae6d94ddad19874045d873d55ddaa8023d07b Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 14:36:56 +0700 Subject: [PATCH 28/61] Add the upgrade_stack task --- .github/workflows/upgrade_stack.yml | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/upgrade_stack.yml diff --git a/.github/workflows/upgrade_stack.yml b/.github/workflows/upgrade_stack.yml new file mode 100644 index 00000000..6ba2f90a --- /dev/null +++ b/.github/workflows/upgrade_stack.yml @@ -0,0 +1,94 @@ +name: Upgrade Stack + +on: + workflow_dispatch: + inputs: + newVersion: + description: "New version" + required: true + type: string + +env: + PHOENIX_VERSION: 1.6.6 + MIX_ENV: test + +jobs: + release_version_test: + name: Bump version + runs-on: ubuntu-latest + + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: ${{ github.head_ref }} + + - name: Setup asdf + uses: asdf-vm/actions/setup@v1 + + - name: Cache asdf + uses: actions/cache@v3 + with: + path: /home/runner/.asdf + key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} + restore-keys: ${{ runner.os }}-asdf- + + - name: Install dependencies in .tool-versions + uses: asdf-vm/actions/install@v1 + + - name: Install rebar + run: mix local.rebar --force + + - name: Install hex + run: mix local.hex --force + + - name: Cache Elixir build + uses: actions/cache@v3 + with: + path: | + _build + deps + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix- + + - name: Install Dependencies + run: mix deps.get + + - name: Compile dependencies + run: mix compile --warnings-as-errors --all-warnings + + - name: Install Phoenix ${{ env.PHOENIX_VERSION }} + run: make install_phoenix PHOENIX_VERSION=${{ env.PHOENIX_VERSION }} + + - name: Bump version + run: mix nimble_template.bump_version ${{ github.event.inputs.newVersion }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + assignees: andyduong1920 + token: ${{ secrets.WIKI_ACTION_TOKEN }} + commit-message: Bump version to ${{ github.event.inputs.newVersion }} + committer: Nimble Bot + branch: chore/bump-version-to-${{ github.event.inputs.newVersion }} + delete-branch: true + title: '[Chore] Bump version to ${{ github.event.inputs.newVersion }}' + labels: | + type : chore + body: | + ## What happened + + Bump version to ${{ github.event.inputs.newVersion }} + + ## Insight + + Automatically created by the Bump Version workflow. + + ## Proof Of Work + + On the Files changed tab From 7db111725438a75a2d8509043793e3c7f34f729c Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 14:38:04 +0700 Subject: [PATCH 29/61] Add the upgrade_stack task --- lib/nimble_template/version.ex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/nimble_template/version.ex b/lib/nimble_template/version.ex index e263808b..9dcce2ea 100644 --- a/lib/nimble_template/version.ex +++ b/lib/nimble_template/version.ex @@ -17,24 +17,24 @@ defmodule NimbleTemplate.Version do end def upgrade_stack(elixir_erlang_node_alpine_versions) do - elixir_version = Keyword.get(elixir_erlang_node_alpine_versions, :elixir, nil) - erlang_version = Keyword.get(elixir_erlang_node_alpine_versions, :erlang, nil) - node_version = Keyword.get(elixir_erlang_node_alpine_versions, :node, nil) - alpine_version = Keyword.get(elixir_erlang_node_alpine_versions, :alpine, nil) + elixir_version = Keyword.get(elixir_erlang_node_alpine_versions, :elixir, "") + erlang_version = Keyword.get(elixir_erlang_node_alpine_versions, :erlang, "") + node_version = Keyword.get(elixir_erlang_node_alpine_versions, :node, "") + alpine_version = Keyword.get(elixir_erlang_node_alpine_versions, :alpine, "") - if elixir_version do + if elixir_version != "" do upgrade_elixir(elixir_version) end - if erlang_version do + if erlang_version != "" do upgrade_erlang(erlang_version) end - if alpine_version do + if alpine_version != "" do upgrade_alpine(alpine_version) end - if node_version do + if node_version != "" do upgrade_node(node_version) end From 937f954370a961413bc56846576d75c598aa953f Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 14:42:29 +0700 Subject: [PATCH 30/61] Add the upgrade_stack task workflow --- .github/workflows/upgrade_stack.yml | 37 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/.github/workflows/upgrade_stack.yml b/.github/workflows/upgrade_stack.yml index 6ba2f90a..d99722cc 100644 --- a/.github/workflows/upgrade_stack.yml +++ b/.github/workflows/upgrade_stack.yml @@ -3,9 +3,24 @@ name: Upgrade Stack on: workflow_dispatch: inputs: - newVersion: - description: "New version" - required: true + elixirVersion: + description: "Elixir version" + required: false + type: string + + erlangVersion: + description: "Erlang version" + required: false + type: string + + alpineVersion: + description: "Alpine version" + required: false + type: string + + nodeVersion: + description: "Node version" + required: false type: string env: @@ -14,7 +29,7 @@ env: jobs: release_version_test: - name: Bump version + name: Upgrade Stack runs-on: ubuntu-latest steps: @@ -65,29 +80,29 @@ jobs: - name: Install Phoenix ${{ env.PHOENIX_VERSION }} run: make install_phoenix PHOENIX_VERSION=${{ env.PHOENIX_VERSION }} - - name: Bump version - run: mix nimble_template.bump_version ${{ github.event.inputs.newVersion }} + - name: Upgrade Stack + run: mix nimble_template.upgrade_stack --elixir ${{ github.event.inputs.elixirVersion }} --erlang ${{ github.event.inputs.erlangVersion }} --node ${{ github.event.inputs.nodeVersion }} --alpine ${{ github.event.inputs.alpineVersion }} - name: Create Pull Request uses: peter-evans/create-pull-request@v4 with: assignees: andyduong1920 token: ${{ secrets.WIKI_ACTION_TOKEN }} - commit-message: Bump version to ${{ github.event.inputs.newVersion }} + commit-message: Upgrade stack versions committer: Nimble Bot - branch: chore/bump-version-to-${{ github.event.inputs.newVersion }} + branch: chore/upgrade-stack-versions delete-branch: true - title: '[Chore] Bump version to ${{ github.event.inputs.newVersion }}' + title: '[Chore] Upgrade stack versions labels: | type : chore body: | ## What happened - Bump version to ${{ github.event.inputs.newVersion }} + Upgrade stack versions ## Insight - Automatically created by the Bump Version workflow. + Automatically created by the Upgrade stacks workflow. ## Proof Of Work From be2a1442febffbb781d057e3b7a1225ec602715f Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 14:44:04 +0700 Subject: [PATCH 31/61] Add the upgrade_stack task workflow --- .github/workflows/upgrade_stack.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upgrade_stack.yml b/.github/workflows/upgrade_stack.yml index d99722cc..4ec42dce 100644 --- a/.github/workflows/upgrade_stack.yml +++ b/.github/workflows/upgrade_stack.yml @@ -92,7 +92,7 @@ jobs: committer: Nimble Bot branch: chore/upgrade-stack-versions delete-branch: true - title: '[Chore] Upgrade stack versions + title: '[Chore] Upgrade stack versions' labels: | type : chore body: | From 535080ea00ca95b745ce4de3eb6557a1b51801bf Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 14:56:45 +0700 Subject: [PATCH 32/61] Improve the task --- lib/mix/tasks/nimble_template.upgrade_stack.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/nimble_template.upgrade_stack.ex b/lib/mix/tasks/nimble_template.upgrade_stack.ex index 2bace0f1..7a159667 100644 --- a/lib/mix/tasks/nimble_template.upgrade_stack.ex +++ b/lib/mix/tasks/nimble_template.upgrade_stack.ex @@ -36,7 +36,7 @@ defmodule Mix.Tasks.NimbleTemplate.UpgradeStack do node: :string ] ) do - {stack_versions, [], []} -> + {stack_versions, _, _} -> stack_versions _other -> From 657d512f063b17ac90ffd9af0ae190b91ea7c1ab Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 15:01:03 +0700 Subject: [PATCH 33/61] Fix codebase --- lib/mix/tasks/nimble_template.upgrade_stack.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/nimble_template.upgrade_stack.ex b/lib/mix/tasks/nimble_template.upgrade_stack.ex index 7a159667..7cfd9a55 100644 --- a/lib/mix/tasks/nimble_template.upgrade_stack.ex +++ b/lib/mix/tasks/nimble_template.upgrade_stack.ex @@ -36,7 +36,7 @@ defmodule Mix.Tasks.NimbleTemplate.UpgradeStack do node: :string ] ) do - {stack_versions, _, _} -> + {stack_versions, _args, _invalid} -> stack_versions _other -> From 9d5c59ce602d3d3de2e460d1e7ae5880adba039d Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 10 Jun 2022 15:13:58 +0700 Subject: [PATCH 34/61] Add Wiki --- .github/wiki/Release.md | 15 +++++++++++++++ .github/wiki/Upgrade-Stack.md | 9 +++++++++ .github/wiki/_Sidebar.md | 7 +++++++ .../assets/images/bump-version-workflow.png | Bin 0 -> 65375 bytes .../images/upgrade-stack-versions-workflow.png | Bin 0 -> 96208 bytes README.md | 12 +----------- 6 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 .github/wiki/Release.md create mode 100644 .github/wiki/Upgrade-Stack.md create mode 100644 .github/wiki/assets/images/bump-version-workflow.png create mode 100644 .github/wiki/assets/images/upgrade-stack-versions-workflow.png diff --git a/.github/wiki/Release.md b/.github/wiki/Release.md new file mode 100644 index 00000000..1d4e7a7d --- /dev/null +++ b/.github/wiki/Release.md @@ -0,0 +1,15 @@ +1. Set the `HEX_API_KEY` as a Github secret (skip this step if it has been done). + +2. Visit the [Bump Version Github Action Workflow](https://github.com/nimblehq/elixir-templates/actions/workflows/bump_version.yml). + +3. Choose `develop` branch. + +4. Trigger the workflow with the next ``. That workflow will create a PR into the `develop` branch with the title `[Chore] Bump version to `. + +![bump-version-workflow](assets/images/bump-version-workflow.png) + +5. Merge the Bump version PR above into the `develop` branch. + +6. Create the `release/` from the `develop` branch, pointing to the `master` branch. + +7. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). diff --git a/.github/wiki/Upgrade-Stack.md b/.github/wiki/Upgrade-Stack.md new file mode 100644 index 00000000..29d3a511 --- /dev/null +++ b/.github/wiki/Upgrade-Stack.md @@ -0,0 +1,9 @@ +1. Visit the [Upgrade Stack Github Action Workflow](https://github.com/nimblehq/elixir-templates/actions/workflows/upgrade_stack.yml). + +2. Choose `develop` branch. + +3. Trigger the workflow with the new stack versions. That workflow will create a PR into the `develop` branch with the title `[Chore] Upgrade stack versions`. + +![upgrade-stack-versions-workflow](assets/images/upgrade-stack-versions-workflow.png) + +4. Merge the PR above into the `develop` branch. diff --git a/.github/wiki/_Sidebar.md b/.github/wiki/_Sidebar.md index aa70a3b1..95317319 100644 --- a/.github/wiki/_Sidebar.md +++ b/.github/wiki/_Sidebar.md @@ -8,3 +8,10 @@ - [[Docker]] - [[Testing]] + +## Release + +- [[Release]] + +## Upgrade stack (Elixir, Erlang, Alpine, Node version) +- [[Upgrade-Stack]] diff --git a/.github/wiki/assets/images/bump-version-workflow.png b/.github/wiki/assets/images/bump-version-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..7265e0bdea33df3c2455151ad7a62a83343ec27e GIT binary patch literal 65375 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 TnQz8mz?Y1Kym+~&Vc`D)CRqp1 literal 0 HcmV?d00001 diff --git a/.github/wiki/assets/images/upgrade-stack-versions-workflow.png b/.github/wiki/assets/images/upgrade-stack-versions-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..92cae8d2752740ae329eab3828d98018b1a7940a GIT binary patch literal 96208 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�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. That workflow will create a PR into the `develop` branch with the title `[Chore] Bump version to `. - -4. Merge the Bump version PR above into the `develop` branch. - -5. Create the `release/` from the `develop` branch, pointing to the `master` branch. - -6. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). +The release documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki) ## Contributing From c6f24afced8ad8fd3f70e5b44e2c3495c3be116c Mon Sep 17 00:00:00 2001 From: andyduong1920 Date: Mon, 20 Jun 2022 08:41:58 +0000 Subject: [PATCH 35/61] Bump version to 4.3.0 --- README.md | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db67fed8..cd1bce40 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Step 2: Add `nimble_template` dependency to `mix.exs`: ```elixir def deps do [ - {:nimble_template, "~> 4.2.1", only: :dev, runtime: false}, + {:nimble_template, "~> 4.3.0", only: :dev, runtime: false}, # other dependencies ... ] end diff --git a/mix.exs b/mix.exs index 7defcd9b..09a5b99f 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule NimbleTemplate.MixProject do def project do [ app: :nimble_template, - version: "4.2.1", + version: "4.3.0", description: "Phoenix/Mix template for projects at [Nimble](https://nimblehq.co/).", elixir: "~> 1.13.3", elixirc_paths: elixirc_paths(Mix.env()), From 3ef7ea66707751b06f4c08edf13e39be45e746dd Mon Sep 17 00:00:00 2001 From: nvminhtue Date: Tue, 21 Jun 2022 20:57:13 +0700 Subject: [PATCH 36/61] [214] Add Chromedriver error guildline in readme --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index d3889523..3198ed38 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,29 @@ The Phoenix application generator is missing. By solving this problem, you need ``` bash mix archive.install hex phx_new ``` + or + ```bash mix archive.install hex phx_new #{specific-version} ``` +### 2. Getting `Wallaby can't find chromedriver` error +Your OS is missing/not installing `chromedriver`, you need to run: + +Brew +``` bash +brew install --cask chromedriver +``` + +Apt +``` bash +apt install chromium-chromedriver +``` + +Or download the package on the official site: +https://chromedriver.chromium.org/downloads + ## License This project is Copyright (c) 2014 and onwards. It is free software, and may be redistributed under the terms specified in the [LICENSE] file. From a907d6220d210757af4a250804e858b5ea2a5cd8 Mon Sep 17 00:00:00 2001 From: An Duong Date: Tue, 12 Jul 2022 09:13:13 +0700 Subject: [PATCH 37/61] Update the PR Request Template --- .github/PULL_REQUEST_TEMPLATE.md | 12 ++++++------ .../.github/PULL_REQUEST_TEMPLATE.md | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 01a7b0ac..4981fc1a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,13 +1,13 @@ https://github.com/nimblehq/elixir-templates/issues/?? -## What happened +## What happened 👀 -Describe the big picture of your changes here to communicate to the team why we should accept this pull request. +Provide a description of the **changes** this pull request brings to the codebase. Additionally, when the pull request is still being worked on, a checklist of the planned changes is welcome to track progress. -## Insight +## Insight 📝 -Describe in details how to test the changes, which solution you tried but did not go with, referenced documentation is welcome as well. +Describe in detail why this solution is the most appropriate, which solution you tried but did not go with, and how to test the changes. References to relevant documentation are welcome as well. -## Proof Of Work +## Proof Of Work 📹 -Show us the implementation: screenshots, gif, etc. +Show us the implementation: screenshots, GIFs, etc. diff --git a/priv/templates/nimble_template/.github/PULL_REQUEST_TEMPLATE.md b/priv/templates/nimble_template/.github/PULL_REQUEST_TEMPLATE.md index 84d066cb..1e1dc3a0 100644 --- a/priv/templates/nimble_template/.github/PULL_REQUEST_TEMPLATE.md +++ b/priv/templates/nimble_template/.github/PULL_REQUEST_TEMPLATE.md @@ -1,13 +1,13 @@ -Add the story URL here. Prefer the short link format, e.g. https://app.clubhouse.io/acme/story/1234/ +Add the story URL here. Prefer the short link format, e.g. https://app.shortcut.com/acme/story/1234/ -## What happened +## What happened 👀 -Describe the big picture of your changes here to communicate to the team why we should accept this pull request. - -## Insight +Provide a description of the **changes** this pull request brings to the codebase. Additionally, when the pull request is still being worked on, a checklist of the planned changes is welcome to track progress. -Describe in details how to test the changes, which solution you tried but did not go with, referenced documentation is welcome as well. - -## Proof Of Work +## Insight 📝 -Show us the implementation: screenshots, gif, etc. +Describe in detail why this solution is the most appropriate, which solution you tried but did not go with, and how to test the changes. References to relevant documentation are welcome as well. + +## Proof Of Work 📹 + +Show us the implementation: screenshots, GIFs, etc. From 190644d826eb1d8aee9d5edf848b3052d934e54a Mon Sep 17 00:00:00 2001 From: topnimble <90754900+topnimble@users.noreply.github.com> Date: Fri, 22 Jul 2022 16:37:00 +0700 Subject: [PATCH 38/61] Fix typo --- ...diness_request_test.exs.eex => readiness_request_test.exs.eex} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename priv/templates/nimble_template/test/otp_app_web/requests/_health/{rediness_request_test.exs.eex => readiness_request_test.exs.eex} (100%) diff --git a/priv/templates/nimble_template/test/otp_app_web/requests/_health/rediness_request_test.exs.eex b/priv/templates/nimble_template/test/otp_app_web/requests/_health/readiness_request_test.exs.eex similarity index 100% rename from priv/templates/nimble_template/test/otp_app_web/requests/_health/rediness_request_test.exs.eex rename to priv/templates/nimble_template/test/otp_app_web/requests/_health/readiness_request_test.exs.eex From 27847b525cf694294ae4ca89559918e578ce1f1e Mon Sep 17 00:00:00 2001 From: topnimble <90754900+topnimble@users.noreply.github.com> Date: Fri, 22 Jul 2022 16:44:49 +0700 Subject: [PATCH 39/61] Update file paths --- lib/nimble_template/addons/variants/phoenix/health_plug.ex | 4 ++-- test/nimble_template/addons/variants/health_plug_test.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nimble_template/addons/variants/phoenix/health_plug.ex b/lib/nimble_template/addons/variants/phoenix/health_plug.ex index 668dcabf..4898e0b8 100644 --- a/lib/nimble_template/addons/variants/phoenix/health_plug.ex +++ b/lib/nimble_template/addons/variants/phoenix/health_plug.ex @@ -31,8 +31,8 @@ defmodule NimbleTemplate.Addons.Phoenix.HealthPlug do "#{web_test_path}/plugs/health_plug_test.exs"}, {:eex, "test/otp_app_web/requests/_health/liveness_request_test.exs.eex", "#{web_test_path}/requests/_health/liveness_request_test.exs"}, - {:eex, "test/otp_app_web/requests/_health/rediness_request_test.exs.eex", - "#{web_test_path}/requests/_health/rediness_request_test.exs"} + {:eex, "test/otp_app_web/requests/_health/readiness_request_test.exs.eex", + "#{web_test_path}/requests/_health/readiness_request_test.exs"} ] Generator.copy_file(files, binding) diff --git a/test/nimble_template/addons/variants/health_plug_test.exs b/test/nimble_template/addons/variants/health_plug_test.exs index 97a219ef..9eb6b6eb 100644 --- a/test/nimble_template/addons/variants/health_plug_test.exs +++ b/test/nimble_template/addons/variants/health_plug_test.exs @@ -24,7 +24,7 @@ defmodule NimbleTemplate.Addons.Phoenix.HealthPlugTest do assert_file("test/nimble_template_web/plugs/health_plug_test.exs") assert_file("test/nimble_template_web/requests/_health/liveness_request_test.exs") - assert_file("test/nimble_template_web/requests/_health/rediness_request_test.exs") + assert_file("test/nimble_template_web/requests/_health/readiness_request_test.exs") end) end From e358932d6c89070cd37ae45fed465ea3b0e118c7 Mon Sep 17 00:00:00 2001 From: Micky Jittjana Date: Thu, 4 Aug 2022 14:11:56 +0700 Subject: [PATCH 40/61] Update command to verify localization file --- .../nimble_template/.github/workflows/test.yml.eex | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/priv/templates/nimble_template/.github/workflows/test.yml.eex b/priv/templates/nimble_template/.github/workflows/test.yml.eex index 89b0551e..26bd9a96 100644 --- a/priv/templates/nimble_template/.github/workflows/test.yml.eex +++ b/priv/templates/nimble_template/.github/workflows/test.yml.eex @@ -149,13 +149,7 @@ jobs: run: mix ecto.migrate - name: Ensure that localization files (POs, POTs) are up-to-date. - run: - mix gettext.extract-and-merge; - - if [ -n "$(git diff --exit-code priv/gettext/)" ]; then - echo "The localization files (POs, POTs) are NOT up-to-date, run \"mix gettext.extract-and-merge\" on your local and push again."; - exit 1; - fi + run: mix gettext.extract --check-up-to-date - name: Run codebase check run: mix codebase From 8dfb3e3aadfb1009420373f19f446a937f30de7a Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 12 Aug 2022 08:59:44 +0700 Subject: [PATCH 41/61] [gh-243] Publish to hex.pm on Release --- .github/workflows/publish_to_hex_pm.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish_to_hex_pm.yml b/.github/workflows/publish_to_hex_pm.yml index 8f9c8dba..aaf24156 100644 --- a/.github/workflows/publish_to_hex_pm.yml +++ b/.github/workflows/publish_to_hex_pm.yml @@ -1,13 +1,8 @@ name: Publish to Hex package manager on: - workflow_run: - workflows: - - Test template - branches: - - master - types: - - completed + release: + types: [published] workflow_dispatch: jobs: From f2e9efdf61cd608a7af7d61708fc0f23004aee71 Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 12 Aug 2022 09:01:04 +0700 Subject: [PATCH 42/61] [gh-243] Remove the workflow_dispatch --- .github/workflows/publish_to_hex_pm.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish_to_hex_pm.yml b/.github/workflows/publish_to_hex_pm.yml index aaf24156..93f98d57 100644 --- a/.github/workflows/publish_to_hex_pm.yml +++ b/.github/workflows/publish_to_hex_pm.yml @@ -3,7 +3,6 @@ name: Publish to Hex package manager on: release: types: [published] - workflow_dispatch: jobs: publish: From 6e385a550409b17c4e8de80e171109f44c093f06 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Fri, 12 Aug 2022 15:38:42 +0700 Subject: [PATCH 43/61] [241] Add test interactive addon --- lib/nimble_template/addons/test_interactive.ex | 14 ++++++++++++++ .../templates/variants/phoenix/template.ex | 1 + 2 files changed, 15 insertions(+) create mode 100644 lib/nimble_template/addons/test_interactive.ex diff --git a/lib/nimble_template/addons/test_interactive.ex b/lib/nimble_template/addons/test_interactive.ex new file mode 100644 index 00000000..a5d29fed --- /dev/null +++ b/lib/nimble_template/addons/test_interactive.ex @@ -0,0 +1,14 @@ +defmodule NimbleTemplate.Addons.TestInteractive do + @moduledoc false + + use NimbleTemplate.Addons.Addon + + @impl true + def do_apply(%Project{} = project, _opts) do + Generator.inject_mix_dependency( + {:mix_test_interactive, "~> 1.0", only: :dev, runtime: false} + ) + + project + end +end diff --git a/lib/nimble_template/templates/variants/phoenix/template.ex b/lib/nimble_template/templates/variants/phoenix/template.ex index 69fbf0f8..22df9a31 100644 --- a/lib/nimble_template/templates/variants/phoenix/template.ex +++ b/lib/nimble_template/templates/variants/phoenix/template.ex @@ -40,6 +40,7 @@ defmodule NimbleTemplate.Templates.Phoenix.Template do |> Addons.Mimic.apply() |> Addons.Faker.apply() |> Addons.Git.apply() + |> Addons.TestInteractive.apply() end defp apply_default_phoenix_addons(project) do From 2b20d099fecd60427b00dcbbdf09b85cdafe7f88 Mon Sep 17 00:00:00 2001 From: nvminhtue Date: Fri, 12 Aug 2022 15:50:22 +0700 Subject: [PATCH 44/61] [gh-240] Add html_filter_full_covered option to excoveralls --- lib/nimble_template/addons/ex_coveralls.ex | 3 ++- test/nimble_template/addons/ex_coveralls_test.exs | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/nimble_template/addons/ex_coveralls.ex b/lib/nimble_template/addons/ex_coveralls.ex index 3126c834..407888bf 100644 --- a/lib/nimble_template/addons/ex_coveralls.ex +++ b/lib/nimble_template/addons/ex_coveralls.ex @@ -13,7 +13,8 @@ defmodule NimbleTemplate.Addons.ExCoveralls do defp copy_files(%Project{otp_app: otp_app, mix_project?: mix_project?} = project) do binding = [ otp_app: otp_app, - minimum_coverage: 100 + minimum_coverage: 100, + html_filter_full_covered: true ] template_file_path = diff --git a/test/nimble_template/addons/ex_coveralls_test.exs b/test/nimble_template/addons/ex_coveralls_test.exs index 70a6596b..8ff842fb 100644 --- a/test/nimble_template/addons/ex_coveralls_test.exs +++ b/test/nimble_template/addons/ex_coveralls_test.exs @@ -11,7 +11,10 @@ defmodule NimbleTemplate.Addons.ExCoverallsTest do in_test_project(test_project_path, fn -> Addons.ExCoveralls.apply(project) - assert_file("coveralls.json") + assert_file("coveralls.json", fn file -> + assert file =~ "minimum_coverage: 100" + assert file =~ "html_filter_full_covered: true" + end) end) end From 96d6606f49cb09d1c41818174d3d5c44af92ca47 Mon Sep 17 00:00:00 2001 From: nvminhtue Date: Fri, 12 Aug 2022 16:37:17 +0700 Subject: [PATCH 45/61] [gh-240] Add html_filter_full_covered option to excoveralls --- priv/templates/nimble_template/coveralls.json.eex | 3 ++- priv/templates/nimble_template/coveralls.json.mix.eex | 3 ++- test/nimble_template/addons/ex_coveralls_test.exs | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/priv/templates/nimble_template/coveralls.json.eex b/priv/templates/nimble_template/coveralls.json.eex index 24e8e5be..f2919bd4 100644 --- a/priv/templates/nimble_template/coveralls.json.eex +++ b/priv/templates/nimble_template/coveralls.json.eex @@ -13,6 +13,7 @@ "test/support" ], "coverage_options": { - "minimum_coverage": <%= minimum_coverage %> + "minimum_coverage": <%= minimum_coverage %>, + "html_filter_full_covered": <%= html_filter_full_covered %> } } diff --git a/priv/templates/nimble_template/coveralls.json.mix.eex b/priv/templates/nimble_template/coveralls.json.mix.eex index ec9de978..5483be4d 100644 --- a/priv/templates/nimble_template/coveralls.json.mix.eex +++ b/priv/templates/nimble_template/coveralls.json.mix.eex @@ -4,6 +4,7 @@ "test/support" ], "coverage_options": { - "minimum_coverage": <%= minimum_coverage %> + "minimum_coverage": <%= minimum_coverage %>, + "html_filter_full_covered": <%= html_filter_full_covered %>, } } diff --git a/test/nimble_template/addons/ex_coveralls_test.exs b/test/nimble_template/addons/ex_coveralls_test.exs index 8ff842fb..92c5d9d2 100644 --- a/test/nimble_template/addons/ex_coveralls_test.exs +++ b/test/nimble_template/addons/ex_coveralls_test.exs @@ -12,8 +12,8 @@ defmodule NimbleTemplate.Addons.ExCoverallsTest do Addons.ExCoveralls.apply(project) assert_file("coveralls.json", fn file -> - assert file =~ "minimum_coverage: 100" - assert file =~ "html_filter_full_covered: true" + assert file =~ "minimum_coverage\": 100" + assert file =~ "html_filter_full_covered\": true" end) end) end From ff6e19893a95841a4f224ef17b0b9131924167d1 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Fri, 12 Aug 2022 16:23:16 +0700 Subject: [PATCH 46/61] [241] Add test --- .../addons/test_interactive.ex | 18 ++++++++- .../addons/test_interactive_test.exs | 38 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 test/nimble_template/addons/test_interactive_test.exs diff --git a/lib/nimble_template/addons/test_interactive.ex b/lib/nimble_template/addons/test_interactive.ex index a5d29fed..1780f327 100644 --- a/lib/nimble_template/addons/test_interactive.ex +++ b/lib/nimble_template/addons/test_interactive.ex @@ -5,8 +5,22 @@ defmodule NimbleTemplate.Addons.TestInteractive do @impl true def do_apply(%Project{} = project, _opts) do - Generator.inject_mix_dependency( - {:mix_test_interactive, "~> 1.0", only: :dev, runtime: false} + Generator.inject_mix_dependency({:mix_test_interactive, "~> 1.0", only: :dev, runtime: false}) + + add_dev_config(project) + end + + defp add_dev_config(project) do + Generator.inject_content( + "config/dev.exs", + """ + config :phoenix, :plug_init_mode, :runtime + """, + """ + + config :mix_test_interactive, + clear: true + """ ) project diff --git a/test/nimble_template/addons/test_interactive_test.exs b/test/nimble_template/addons/test_interactive_test.exs new file mode 100644 index 00000000..498bdc8d --- /dev/null +++ b/test/nimble_template/addons/test_interactive_test.exs @@ -0,0 +1,38 @@ +defmodule NimbleTemplate.Addons.TestInteractiveTest do + use NimbleTemplate.AddonCase, async: false + + describe "#apply/2" do + test "injects mix_test_interactive to mix dependencies list", %{ + project: project, + test_project_path: test_project_path + } do + in_test_project(test_project_path, fn -> + Addons.TestInteractive.apply(project) + + assert_file("mix.exs", fn file -> + assert file =~ """ + defp deps do + [ + {:mix_test_interactive, "~> 0.12.2", [only: :test]}, + """ + end) + end) + end + + test "injects mix_test_interactive config to the dev config", %{ + project: project, + test_project_path: test_project_path(ct_path) + } do + in_test_project(test_project_path, fn -> + Addons.TestInteractive.apply(project) + + assert_file("config/dev.exs", fn file -> + assert file =~ """ + config :mix_test_interactive, + clear: true + """ + end) + end) + end + end +end From 03edc8470dfdf515e79514a6755f5f758c0d2049 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Fri, 12 Aug 2022 17:14:53 +0700 Subject: [PATCH 47/61] [241] Update failed test --- lib/nimble_template/addons/test_interactive.ex | 2 +- test/nimble_template/addons/test_interactive_test.exs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/nimble_template/addons/test_interactive.ex b/lib/nimble_template/addons/test_interactive.ex index 1780f327..d7511016 100644 --- a/lib/nimble_template/addons/test_interactive.ex +++ b/lib/nimble_template/addons/test_interactive.ex @@ -5,7 +5,7 @@ defmodule NimbleTemplate.Addons.TestInteractive do @impl true def do_apply(%Project{} = project, _opts) do - Generator.inject_mix_dependency({:mix_test_interactive, "~> 1.0", only: :dev, runtime: false}) + Generator.inject_mix_dependency({:mix_test_interactive, "~> 1.2", only: :dev, runtime: false}) add_dev_config(project) end diff --git a/test/nimble_template/addons/test_interactive_test.exs b/test/nimble_template/addons/test_interactive_test.exs index 498bdc8d..9408cefb 100644 --- a/test/nimble_template/addons/test_interactive_test.exs +++ b/test/nimble_template/addons/test_interactive_test.exs @@ -13,7 +13,7 @@ defmodule NimbleTemplate.Addons.TestInteractiveTest do assert file =~ """ defp deps do [ - {:mix_test_interactive, "~> 0.12.2", [only: :test]}, + {:mix_test_interactive, "~> 1.2", [only: :dev, runtime: false]}, """ end) end) @@ -21,15 +21,15 @@ defmodule NimbleTemplate.Addons.TestInteractiveTest do test "injects mix_test_interactive config to the dev config", %{ project: project, - test_project_path: test_project_path(ct_path) + test_project_path: test_project_path } do in_test_project(test_project_path, fn -> Addons.TestInteractive.apply(project) assert_file("config/dev.exs", fn file -> assert file =~ """ - config :mix_test_interactive, - clear: true + config :mix_test_interactive, + clear: true """ end) end) From c3d01588ea4283f63f27ea3ea41ad33e267c88cd Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Sat, 13 Aug 2022 09:42:40 +0700 Subject: [PATCH 48/61] [241] Add docs --- .../.github/wiki/Getting-Started.md.eex | 12 +++++++++- .../.github/wiki/Getting-Started.md.mix.eex | 12 +++++++++- priv/templates/nimble_template/README.md.eex | 22 ++++++++++++++----- .../nimble_template/README.md.mix.eex | 18 +++++++++++---- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex index 8accb904..dd311f36 100644 --- a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex +++ b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex @@ -57,6 +57,16 @@ mix test ``` +- Run all tests with `watch` option: + + ```sh + mix test.interactive # Watch the whole test suite + + mix test.interactive test_file_path # Watch a specific test file + + mix test.interactive test_file_path:line_number # Watch a specific test line number + ``` + - Run all lint: ```sh @@ -66,7 +76,7 @@ - Fix all lint: ```sh - mix codebase.fix + mix codebase.fix ``` - Test coverage: diff --git a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex index c5700229..f3915a83 100644 --- a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex +++ b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex @@ -24,6 +24,16 @@ mix test ``` +- Run all tests with `watch` option: + + ```sh + mix test.interactive # Watch the whole test suite + + mix test.interactive test_file_path # Watch a specific test file + + mix test.interactive test_file_path:line_number # Watch a specific test line number + ``` + - Run all lint: ```sh @@ -33,7 +43,7 @@ - Fix all lint: ```sh - mix codebase.fix + mix codebase.fix ``` - Test coverage: diff --git a/priv/templates/nimble_template/README.md.eex b/priv/templates/nimble_template/README.md.eex index 94ebc750..a6184cd4 100644 --- a/priv/templates/nimble_template/README.md.eex +++ b/priv/templates/nimble_template/README.md.eex @@ -62,25 +62,35 @@ - Run all tests: ```sh - mix test + mix test + ``` + +- Run all tests with `watch` option: + + ```sh + mix test.interactive # Watch the whole test suite + + mix test.interactive test_file_path # Watch a specific test file + + mix test.interactive test_file_path:line_number # Watch a specific test line number ``` - Run all lint: ```sh - mix codebase + mix codebase ``` - + - Fix all lint: ```sh - mix codebase.fix + mix codebase.fix ``` - + - Test coverage: ```sh - mix coverage + mix coverage ``` ### Production diff --git a/priv/templates/nimble_template/README.md.mix.eex b/priv/templates/nimble_template/README.md.mix.eex index 4c55854b..76a52aaa 100644 --- a/priv/templates/nimble_template/README.md.mix.eex +++ b/priv/templates/nimble_template/README.md.mix.eex @@ -29,25 +29,35 @@ - Run all tests: ```sh - mix test + mix test + ``` + +- Run all tests with `watch` option: + + ```sh + mix test.interactive # Watch the whole test suite + + mix test.interactive test_file_path # Watch a specific test file + + mix test.interactive test_file_path:line_number # Watch a specific test line number ``` - Run all lint: ```sh - mix codebase + mix codebase ``` - Fix all lint: ```sh - mix codebase.fix + mix codebase.fix ``` - Test coverage: ```sh - mix coverage + mix coverage ``` ### CI/CD From aab2c0b32620848604f1811c5c54cab884eafd18 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Sat, 13 Aug 2022 10:47:07 +0700 Subject: [PATCH 49/61] [241] Add docs --- priv/templates/nimble_template/README.md.eex | 1 + priv/templates/nimble_template/README.md.mix.eex | 1 + 2 files changed, 2 insertions(+) diff --git a/priv/templates/nimble_template/README.md.eex b/priv/templates/nimble_template/README.md.eex index a6184cd4..65d7bbcf 100644 --- a/priv/templates/nimble_template/README.md.eex +++ b/priv/templates/nimble_template/README.md.eex @@ -102,5 +102,6 @@ ``` ### CI/CD + The project relies entirely on [Github Actions](https://github.com/features/actions) for CI/CD via multiple workflows located under the [`.github/workflows/`](.github/workflows) directory. Please check out the [`.github/workflows/README.md`](.github/workflows/README.md) file for further instructions. diff --git a/priv/templates/nimble_template/README.md.mix.eex b/priv/templates/nimble_template/README.md.mix.eex index 76a52aaa..36325731 100644 --- a/priv/templates/nimble_template/README.md.mix.eex +++ b/priv/templates/nimble_template/README.md.mix.eex @@ -61,5 +61,6 @@ ``` ### CI/CD + The project relies entirely on [Github Actions](https://github.com/features/actions) for CI/CD via multiple workflows located under the [`.github/workflows/`](.github/workflows) directory. Please check out the [`.github/workflows/README.md`](.github/workflows/README.md) file for further instructions. From 79979a200c83930f6917b1f1fa2e81369e072a60 Mon Sep 17 00:00:00 2001 From: An Duong Date: Sat, 13 Aug 2022 15:20:22 +0700 Subject: [PATCH 50/61] [gh-243] Update wiki --- .github/wiki/Release.md | 6 ++++-- README.md | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/wiki/Release.md b/.github/wiki/Release.md index 1d4e7a7d..840af6fc 100644 --- a/.github/wiki/Release.md +++ b/.github/wiki/Release.md @@ -10,6 +10,8 @@ 5. Merge the Bump version PR above into the `develop` branch. -6. Create the `release/` from the `develop` branch, pointing to the `master` branch. +6. Create the `release/` from the `develop` branch, pointing to the `main` branch. -7. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). +7. Create a Release from the `main` branch. + +8. Once the release is published, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). diff --git a/README.md b/README.md index 9473a4ae..2473cb42 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,11 @@ mix nimble_template.gen --mix # Apply the Mix template ## Running tests -The testing documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki) +The testing documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki/Testing) ### Release process -The release documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki) +The release documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki/Release) ## Contributing From 4c0825fec37a531a0918c84edffbe3732705d384 Mon Sep 17 00:00:00 2001 From: An Duong Date: Sun, 14 Aug 2022 14:31:21 +0700 Subject: [PATCH 51/61] Update CodeOwners --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cacd98c6..7ae020cd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,8 +1,8 @@ # Team Lead -* @andyduong1920 +* @byhbt # Team Members -* @bterone @byhbt @hanam1ni @junan @longnd @rosle @topnimble @Nihisil @nvminhtue @liamstevens111 +* @andyduong1920 @bterone @hanam1ni @junan @longnd @rosle @topnimble @Nihisil @nvminhtue @liamstevens111 # Engineering Leads CODEOWNERS @nimblehq/engineering-leads From 911faa558c4937349e2fbcb4982c09e3d5fb04c6 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Tue, 16 Aug 2022 17:57:05 +0700 Subject: [PATCH 52/61] [241] Supporting the mix project --- .../addons/test_interactive.ex | 12 +++++----- .../templates/variants/mix/template.ex | 1 + .../addons/test_interactive_test.exs | 23 +++++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/lib/nimble_template/addons/test_interactive.ex b/lib/nimble_template/addons/test_interactive.ex index d7511016..f423a5f6 100644 --- a/lib/nimble_template/addons/test_interactive.ex +++ b/lib/nimble_template/addons/test_interactive.ex @@ -5,19 +5,19 @@ defmodule NimbleTemplate.Addons.TestInteractive do @impl true def do_apply(%Project{} = project, _opts) do - Generator.inject_mix_dependency({:mix_test_interactive, "~> 1.2", only: :dev, runtime: false}) + latest_version = latest_package_version(:mix_test_interactive) + + Generator.inject_mix_dependency( + {:mix_test_interactive, latest_version, only: :dev, runtime: false} + ) add_dev_config(project) end defp add_dev_config(project) do - Generator.inject_content( + Generator.append_content( "config/dev.exs", """ - config :phoenix, :plug_init_mode, :runtime - """, - """ - config :mix_test_interactive, clear: true """ diff --git a/lib/nimble_template/templates/variants/mix/template.ex b/lib/nimble_template/templates/variants/mix/template.ex index a619330e..5c0d15ed 100644 --- a/lib/nimble_template/templates/variants/mix/template.ex +++ b/lib/nimble_template/templates/variants/mix/template.ex @@ -22,6 +22,7 @@ defmodule NimbleTemplate.Templates.Mix.Template do |> Addons.ExCoveralls.apply() |> Addons.Faker.apply() |> Addons.Git.apply() + |> Addons.TestInteractive.apply() end defp apply_optional_mix_addons(project) do diff --git a/test/nimble_template/addons/test_interactive_test.exs b/test/nimble_template/addons/test_interactive_test.exs index 9408cefb..b6652b48 100644 --- a/test/nimble_template/addons/test_interactive_test.exs +++ b/test/nimble_template/addons/test_interactive_test.exs @@ -2,6 +2,8 @@ defmodule NimbleTemplate.Addons.TestInteractiveTest do use NimbleTemplate.AddonCase, async: false describe "#apply/2" do + @describetag mock_latest_package_versions: [{:mix_test_interactive, "1.2"}] + test "injects mix_test_interactive to mix dependencies list", %{ project: project, test_project_path: test_project_path @@ -35,4 +37,25 @@ defmodule NimbleTemplate.Addons.TestInteractiveTest do end) end end + + describe "#apply/2 with mix_project" do + @describetag mix_project?: true + @describetag mock_latest_package_versions: [{:mix_test_interactive, "1.2"}] + + test "injects mix_test_interactive config to the dev config", %{ + project: project, + test_project_path: test_project_path + } do + in_test_project(test_project_path, fn -> + Addons.TestInteractive.apply(project) + + assert_file("config/dev.exs", fn file -> + assert file =~ """ + config :mix_test_interactive, + clear: true + """ + end) + end) + end + end end From 5dca0d2b4a4515f5bb38338b303ce2e3a488ad13 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Tue, 16 Aug 2022 17:59:28 +0700 Subject: [PATCH 53/61] [241] Update the README content --- .../nimble_template/.github/wiki/Getting-Started.md.eex | 2 +- .../nimble_template/.github/wiki/Getting-Started.md.mix.eex | 2 +- priv/templates/nimble_template/README.md.eex | 2 +- priv/templates/nimble_template/README.md.mix.eex | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex index dd311f36..aee1a523 100644 --- a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex +++ b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex @@ -57,7 +57,7 @@ mix test ``` -- Run all tests with `watch` option: +- Run tests with `watch` option: ```sh mix test.interactive # Watch the whole test suite diff --git a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex index f3915a83..8c6d30e1 100644 --- a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex +++ b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.mix.eex @@ -24,7 +24,7 @@ mix test ``` -- Run all tests with `watch` option: +- Run tests with `watch` option: ```sh mix test.interactive # Watch the whole test suite diff --git a/priv/templates/nimble_template/README.md.eex b/priv/templates/nimble_template/README.md.eex index 65d7bbcf..341f6b6e 100644 --- a/priv/templates/nimble_template/README.md.eex +++ b/priv/templates/nimble_template/README.md.eex @@ -65,7 +65,7 @@ mix test ``` -- Run all tests with `watch` option: +- Run tests with `watch` option: ```sh mix test.interactive # Watch the whole test suite diff --git a/priv/templates/nimble_template/README.md.mix.eex b/priv/templates/nimble_template/README.md.mix.eex index 36325731..d913dd56 100644 --- a/priv/templates/nimble_template/README.md.mix.eex +++ b/priv/templates/nimble_template/README.md.mix.eex @@ -32,7 +32,7 @@ mix test ``` -- Run all tests with `watch` option: +- Run tests with `watch` option: ```sh mix test.interactive # Watch the whole test suite From 5747dab5c1c294b35b68f91b68e17dc67b05a3a0 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Tue, 16 Aug 2022 18:50:38 +0700 Subject: [PATCH 54/61] [gh-241] Add guard for mix project to ignore append config file --- lib/nimble_template/addons/test_interactive.ex | 2 ++ test/nimble_template/addons/test_interactive_test.exs | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/nimble_template/addons/test_interactive.ex b/lib/nimble_template/addons/test_interactive.ex index f423a5f6..95212527 100644 --- a/lib/nimble_template/addons/test_interactive.ex +++ b/lib/nimble_template/addons/test_interactive.ex @@ -14,6 +14,8 @@ defmodule NimbleTemplate.Addons.TestInteractive do add_dev_config(project) end + defp add_dev_config(%Project{mix_project?: true} = project), do: project + defp add_dev_config(project) do Generator.append_content( "config/dev.exs", diff --git a/test/nimble_template/addons/test_interactive_test.exs b/test/nimble_template/addons/test_interactive_test.exs index b6652b48..e74f1c43 100644 --- a/test/nimble_template/addons/test_interactive_test.exs +++ b/test/nimble_template/addons/test_interactive_test.exs @@ -42,17 +42,18 @@ defmodule NimbleTemplate.Addons.TestInteractiveTest do @describetag mix_project?: true @describetag mock_latest_package_versions: [{:mix_test_interactive, "1.2"}] - test "injects mix_test_interactive config to the dev config", %{ + test "injects mix_test_interactive to mix dependencies list", %{ project: project, test_project_path: test_project_path } do in_test_project(test_project_path, fn -> Addons.TestInteractive.apply(project) - assert_file("config/dev.exs", fn file -> + assert_file("mix.exs", fn file -> assert file =~ """ - config :mix_test_interactive, - clear: true + defp deps do + [ + {:mix_test_interactive, "~> 1.2", [only: :dev, runtime: false]}, """ end) end) From 79a44d082fd51fd80d2b7790614f8debe7f0bc3c Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Sun, 28 Aug 2022 14:18:06 +0700 Subject: [PATCH 55/61] [gh-202] Add install chromedriver instruction to README of generated project --- README.md | 10 ++++--- .../.github/wiki/Getting-Started.md.eex | 16 +++++++++++- priv/templates/nimble_template/README.md.eex | 26 ++++++++++++++----- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2473cb42..6ec12748 100644 --- a/README.md +++ b/README.md @@ -91,13 +91,15 @@ mix archive.install hex phx_new #{specific-version} ### 2. Getting `Wallaby can't find chromedriver` error Your OS is missing/not installing `chromedriver`, you need to run: -Brew -``` bash +Homebrew + +```bash brew install --cask chromedriver ``` -Apt -``` bash +Debian/Ubuntu + +```bash apt install chromium-chromedriver ``` diff --git a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex index 8accb904..23371c30 100644 --- a/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex +++ b/priv/templates/nimble_template/.github/wiki/Getting-Started.md.eex @@ -38,6 +38,20 @@ ```sh npm install --prefix assets ``` + +- Install `chromedriver` for Wallaby browser tests + + Homebrew + + ```sh + brew install --cask chromedriver + ``` + + Debian/Ubuntu + + ```sh + brew install --cask chromedriver + ``` <% end %> - Setup the databases: @@ -66,7 +80,7 @@ - Fix all lint: ```sh - mix codebase.fix + mix codebase.fix ``` - Test coverage: diff --git a/priv/templates/nimble_template/README.md.eex b/priv/templates/nimble_template/README.md.eex index 94ebc750..43ddcfa2 100644 --- a/priv/templates/nimble_template/README.md.eex +++ b/priv/templates/nimble_template/README.md.eex @@ -46,6 +46,20 @@ ```sh npm install --prefix assets ``` + +- Install `chromedriver` for Wallaby browser tests + + Homebrew + + ```sh + brew install --cask chromedriver + ``` + + Debian/Ubuntu + + ```sh + brew install --cask chromedriver + ``` <% end %> - Setup the databases: @@ -62,25 +76,25 @@ - Run all tests: ```sh - mix test + mix test ``` - Run all lint: ```sh - mix codebase + mix codebase ``` - + - Fix all lint: ```sh - mix codebase.fix + mix codebase.fix ``` - + - Test coverage: ```sh - mix coverage + mix coverage ``` ### Production From 077620438f2ee20c4061fc238defa74a2d182406 Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 12 Aug 2022 08:59:44 +0700 Subject: [PATCH 56/61] [gh-243] Publish to hex.pm on Release --- .github/workflows/publish_to_hex_pm.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish_to_hex_pm.yml b/.github/workflows/publish_to_hex_pm.yml index 8f9c8dba..aaf24156 100644 --- a/.github/workflows/publish_to_hex_pm.yml +++ b/.github/workflows/publish_to_hex_pm.yml @@ -1,13 +1,8 @@ name: Publish to Hex package manager on: - workflow_run: - workflows: - - Test template - branches: - - master - types: - - completed + release: + types: [published] workflow_dispatch: jobs: From f2afb86534a04a91cd8e2a2731be6e78602d9701 Mon Sep 17 00:00:00 2001 From: An Duong Date: Fri, 12 Aug 2022 09:01:04 +0700 Subject: [PATCH 57/61] [gh-243] Remove the workflow_dispatch --- .github/workflows/publish_to_hex_pm.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish_to_hex_pm.yml b/.github/workflows/publish_to_hex_pm.yml index aaf24156..93f98d57 100644 --- a/.github/workflows/publish_to_hex_pm.yml +++ b/.github/workflows/publish_to_hex_pm.yml @@ -3,7 +3,6 @@ name: Publish to Hex package manager on: release: types: [published] - workflow_dispatch: jobs: publish: From 709fcb7cdb01d0d5ecfe4e5768b3b0e6160b50c9 Mon Sep 17 00:00:00 2001 From: An Duong Date: Sat, 13 Aug 2022 15:20:22 +0700 Subject: [PATCH 58/61] [gh-243] Update wiki --- .github/wiki/Release.md | 6 ++++-- README.md | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/wiki/Release.md b/.github/wiki/Release.md index 1d4e7a7d..840af6fc 100644 --- a/.github/wiki/Release.md +++ b/.github/wiki/Release.md @@ -10,6 +10,8 @@ 5. Merge the Bump version PR above into the `develop` branch. -6. Create the `release/` from the `develop` branch, pointing to the `master` branch. +6. Create the `release/` from the `develop` branch, pointing to the `main` branch. -7. Once the release branch is merged into the `master` branch, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). +7. Create a Release from the `main` branch. + +8. Once the release is published, Github Action automatically publishes the template to [https://hex.pm/packages/nimble_template](https://hex.pm/packages/nimble_template). diff --git a/README.md b/README.md index 9473a4ae..2473cb42 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,11 @@ mix nimble_template.gen --mix # Apply the Mix template ## Running tests -The testing documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki) +The testing documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki/Testing) ### Release process -The release documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki) +The release documentation is on [Wiki](https://github.com/nimblehq/elixir-templates/wiki/Release) ## Contributing From 06931c837282ed51cd69c6a5d7cd3125d644e57d Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Sun, 28 Aug 2022 12:53:42 +0700 Subject: [PATCH 59/61] [gh-198] Bump Phoenix version to 1.6.11 --- .github/workflows/bump_version.yml | 2 +- .../workflows/reusable_phoenix_project.yml | 2 +- .github/workflows/test_template.yml | 2 +- .github/workflows/upgrade_stack.yml | 2 +- .github/workflows/verify_release_version.yml | 2 +- README.md | 2 +- lib/nimble_template/addons/mimic.ex | 11 -------- lib/nimble_template/addons/test_env.ex | 5 +--- .../addons/variants/phoenix/ex_machina.ex | 11 -------- .../addons/variants/phoenix/ex_vcr.ex | 11 -------- .../addons/variants/phoenix/mix_release.ex | 27 ------------------- .../addons/variants/phoenix/web/es_lint.ex | 18 ++++++++++--- mix.exs | 2 +- test/nimble_template/addons/mimic_test.exs | 4 --- test/nimble_template/addons/test_env_test.exs | 2 +- .../addons/variants/ex_machina_test.exs | 4 --- .../addons/variants/ex_vcr_test.exs | 4 --- .../addons/variants/mix_release_test.exs | 21 --------------- 18 files changed, 23 insertions(+), 109 deletions(-) diff --git a/.github/workflows/bump_version.yml b/.github/workflows/bump_version.yml index f9e5c236..ad942231 100644 --- a/.github/workflows/bump_version.yml +++ b/.github/workflows/bump_version.yml @@ -9,7 +9,7 @@ on: type: string env: - PHOENIX_VERSION: 1.6.6 + PHOENIX_VERSION: 1.6.11 MIX_ENV: test jobs: diff --git a/.github/workflows/reusable_phoenix_project.yml b/.github/workflows/reusable_phoenix_project.yml index ffa5d00f..1ad18a8f 100644 --- a/.github/workflows/reusable_phoenix_project.yml +++ b/.github/workflows/reusable_phoenix_project.yml @@ -11,7 +11,7 @@ on: type: string env: - PHOENIX_VERSION: 1.6.6 + PHOENIX_VERSION: 1.6.11 BASE_PROJECT_DIRECTORY: sample_project DB_HOST: localhost diff --git a/.github/workflows/test_template.yml b/.github/workflows/test_template.yml index 14b155b9..8990f253 100644 --- a/.github/workflows/test_template.yml +++ b/.github/workflows/test_template.yml @@ -3,7 +3,7 @@ name: Test template on: push env: - PHOENIX_VERSION: 1.6.6 + PHOENIX_VERSION: 1.6.11 MIX_ENV: test jobs: diff --git a/.github/workflows/upgrade_stack.yml b/.github/workflows/upgrade_stack.yml index 4ec42dce..e3dbc14e 100644 --- a/.github/workflows/upgrade_stack.yml +++ b/.github/workflows/upgrade_stack.yml @@ -24,7 +24,7 @@ on: type: string env: - PHOENIX_VERSION: 1.6.6 + PHOENIX_VERSION: 1.6.11 MIX_ENV: test jobs: diff --git a/.github/workflows/verify_release_version.yml b/.github/workflows/verify_release_version.yml index 55e70103..67cee969 100644 --- a/.github/workflows/verify_release_version.yml +++ b/.github/workflows/verify_release_version.yml @@ -6,7 +6,7 @@ on: - 'release/**' env: - PHOENIX_VERSION: 1.6.6 + PHOENIX_VERSION: 1.6.11 MIX_ENV: test jobs: diff --git a/README.md b/README.md index 2473cb42..31fc254c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ NimbleTemplate has been developed and actively tested with the below environment - Mix 1.13.3 - Elixir 1.13.3 - Erlang/OTP 24.2.2 -- Phoenix 1.6.6 +- Phoenix 1.6.x - Node 16.15.0 ## Installation diff --git a/lib/nimble_template/addons/mimic.ex b/lib/nimble_template/addons/mimic.ex index f7e31b90..fbc7d865 100644 --- a/lib/nimble_template/addons/mimic.ex +++ b/lib/nimble_template/addons/mimic.ex @@ -40,17 +40,6 @@ defmodule NimbleTemplate.Addons.Mimic do end defp edit_case(%Project{mix_project?: false} = project) do - Generator.inject_content( - "test/support/channel_case.ex", - """ - quote do - """, - """ - use Mimic - - """ - ) - Generator.inject_content( "test/support/conn_case.ex", """ diff --git a/lib/nimble_template/addons/test_env.ex b/lib/nimble_template/addons/test_env.ex index 5a1aa464..41717747 100644 --- a/lib/nimble_template/addons/test_env.ex +++ b/lib/nimble_template/addons/test_env.ex @@ -133,10 +133,7 @@ defmodule NimbleTemplate.Addons.TestEnv do end defp edit_test_support_cases(project) do - project - |> edit_test_support_case("channel_case") - |> edit_test_support_case("conn_case") - |> edit_test_support_case("data_case") + edit_test_support_case(project, "data_case") end defp edit_test_support_case(project, support_case_name) do diff --git a/lib/nimble_template/addons/variants/phoenix/ex_machina.ex b/lib/nimble_template/addons/variants/phoenix/ex_machina.ex index 5582aad6..b4bdc72d 100644 --- a/lib/nimble_template/addons/variants/phoenix/ex_machina.ex +++ b/lib/nimble_template/addons/variants/phoenix/ex_machina.ex @@ -76,17 +76,6 @@ defmodule NimbleTemplate.Addons.Phoenix.ExMachina do """ ) - Generator.replace_content( - "test/support/channel_case.ex", - """ - import #{web_module}.ChannelCase - """, - """ - import #{web_module}.ChannelCase - import #{base_module}.Factory - """ - ) - Generator.replace_content( "test/support/conn_case.ex", """ diff --git a/lib/nimble_template/addons/variants/phoenix/ex_vcr.ex b/lib/nimble_template/addons/variants/phoenix/ex_vcr.ex index 11ac45a3..617cfd21 100644 --- a/lib/nimble_template/addons/variants/phoenix/ex_vcr.ex +++ b/lib/nimble_template/addons/variants/phoenix/ex_vcr.ex @@ -43,17 +43,6 @@ defmodule NimbleTemplate.Addons.Phoenix.ExVCR do end defp edit_case(project) do - Generator.inject_content( - "test/support/channel_case.ex", - """ - quote do - """, - """ - use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney - - """ - ) - Generator.inject_content( "test/support/conn_case.ex", """ diff --git a/lib/nimble_template/addons/variants/phoenix/mix_release.ex b/lib/nimble_template/addons/variants/phoenix/mix_release.ex index 63f37daf..9db9f9cd 100644 --- a/lib/nimble_template/addons/variants/phoenix/mix_release.ex +++ b/lib/nimble_template/addons/variants/phoenix/mix_release.ex @@ -27,33 +27,6 @@ defmodule NimbleTemplate.Addons.Phoenix.MixRelease do end defp edit_files(%{otp_app: otp_app, web_module: web_module} = project) do - Generator.delete_content( - "config/runtime.exs", - """ - # Start the phoenix server if environment is set and running in a release - if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do - config :#{otp_app}, #{web_module}.Endpoint, server: true - end - - """ - ) - - Generator.delete_content( - "config/runtime.exs", - """ - - # ## Using releases - # - # If you are doing OTP releases, you need to instruct Phoenix - # to start each relevant endpoint: - # - # config :#{otp_app}, #{web_module}.Endpoint, server: true - # - # Then you can assemble a release by calling `mix release`. - # See `mix help release` for more information. - """ - ) - Generator.replace_content( "config/runtime.exs", """ diff --git a/lib/nimble_template/addons/variants/phoenix/web/es_lint.ex b/lib/nimble_template/addons/variants/phoenix/web/es_lint.ex index 234fc5dc..9c7573f3 100644 --- a/lib/nimble_template/addons/variants/phoenix/web/es_lint.ex +++ b/lib/nimble_template/addons/variants/phoenix/web/es_lint.ex @@ -81,6 +81,20 @@ defmodule NimbleTemplate.Addons.Phoenix.Web.EsLint do end def edit_app_js(%Project{live_project?: true} = project) do + update_topbar_js_variables() + + project + end + + def edit_app_js(%Project{web_project?: true} = project) do + update_topbar_js_variables() + + project + end + + def edit_app_js(project), do: project + + defp update_topbar_js_variables do Generator.replace_content( "assets/js/app.js", "window.addEventListener(\"phx:page-loading-start\", info => topbar.show())", @@ -92,9 +106,5 @@ defmodule NimbleTemplate.Addons.Phoenix.Web.EsLint do "window.addEventListener(\"phx:page-loading-stop\", info => topbar.hide())", "window.addEventListener(\"phx:page-loading-stop\", _info => topbar.hide())" ) - - project end - - def edit_app_js(project), do: project end diff --git a/mix.exs b/mix.exs index 09a5b99f..aa166877 100644 --- a/mix.exs +++ b/mix.exs @@ -35,7 +35,7 @@ defmodule NimbleTemplate.MixProject do {:httpoison, "~> 1.7"}, {:jason, "~> 1.2"}, {:mimic, "~> 1.3", only: :test}, - {:phoenix, "~> 1.6.6"} + {:phoenix, "~> 1.6.11"} ] end diff --git a/test/nimble_template/addons/mimic_test.exs b/test/nimble_template/addons/mimic_test.exs index f9b3308b..857abad4 100644 --- a/test/nimble_template/addons/mimic_test.exs +++ b/test/nimble_template/addons/mimic_test.exs @@ -42,10 +42,6 @@ defmodule NimbleTemplate.Addons.MimicTest do in_test_project(test_project_path, fn -> Addons.Mimic.apply(project) - assert_file("test/support/channel_case.ex", fn file -> - assert file =~ "use Mimic" - end) - assert_file("test/support/data_case.ex", fn file -> assert file =~ "use Mimic" end) diff --git a/test/nimble_template/addons/test_env_test.exs b/test/nimble_template/addons/test_env_test.exs index df07a3ce..e41f2d99 100644 --- a/test/nimble_template/addons/test_env_test.exs +++ b/test/nimble_template/addons/test_env_test.exs @@ -82,7 +82,7 @@ defmodule NimbleTemplate.Addons.TestEnvTest do in_test_project(test_project_path, fn -> Addons.TestEnv.apply(project) - Enum.each(["channel_case", "conn_case", "data_case"], fn support_case_name -> + Enum.each(["conn_case", "data_case"], fn support_case_name -> assert_file("test/support/" <> support_case_name <> ".ex", fn file -> assert file =~ "alias Ecto.Adapters.SQL.Sandbox" assert file =~ "Sandbox.start_owner!" diff --git a/test/nimble_template/addons/variants/ex_machina_test.exs b/test/nimble_template/addons/variants/ex_machina_test.exs index fef60c92..9f655c7c 100644 --- a/test/nimble_template/addons/variants/ex_machina_test.exs +++ b/test/nimble_template/addons/variants/ex_machina_test.exs @@ -69,10 +69,6 @@ defmodule NimbleTemplate.Addons.Phoenix.ExMachinaTest do assert file =~ "import NimbleTemplate.Factory" end) - assert_file("test/support/channel_case.ex", fn file -> - assert file =~ "import NimbleTemplate.Factory" - end) - assert_file("test/support/conn_case.ex", fn file -> assert file =~ "import NimbleTemplate.Factory" end) diff --git a/test/nimble_template/addons/variants/ex_vcr_test.exs b/test/nimble_template/addons/variants/ex_vcr_test.exs index bbce6362..e887fae3 100644 --- a/test/nimble_template/addons/variants/ex_vcr_test.exs +++ b/test/nimble_template/addons/variants/ex_vcr_test.exs @@ -39,10 +39,6 @@ defmodule NimbleTemplate.Addons.Phoenix.ExVCRTest do in_test_project(test_project_path, fn -> PhoenixAddons.ExVCR.apply(project) - assert_file("test/support/channel_case.ex", fn file -> - assert file =~ "use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney" - end) - assert_file("test/support/data_case.ex", fn file -> assert file =~ "use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney" end) diff --git a/test/nimble_template/addons/variants/mix_release_test.exs b/test/nimble_template/addons/variants/mix_release_test.exs index 6e0e6722..70cb5219 100644 --- a/test/nimble_template/addons/variants/mix_release_test.exs +++ b/test/nimble_template/addons/variants/mix_release_test.exs @@ -54,27 +54,6 @@ defmodule NimbleTemplate.Addons.Phoenix.MixReleaseTest do Set the Heroku endpoint to this variable. \"\"\" """ - - refute file =~ """ - - # ## Using releases - # - # If you are doing OTP releases, you need to instruct Phoenix - # to start each relevant endpoint: - # - # config :nimble_template, NimbleTemplateWeb.Endpoint, server: true - # - # Then you can assemble a release by calling `mix release`. - # See `mix help release` for more information. - """ - - refute file =~ """ - # Start the phoenix server if environment is set and running in a release - if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do - config :nimble_template, NimbleTemplateWeb.Endpoint, server: true - end - - """ end) end) end From 84e86ce61423f3c3270be04be8e6fb73cbf4e5c6 Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Sun, 28 Aug 2022 13:12:15 +0700 Subject: [PATCH 60/61] [gh-198] Update README content --- README.md | 15 +++++++++------ test/nimble_template/addons/test_env_test.exs | 17 ----------------- .../variants/phoenix/web/esbuild_test.exs | 2 +- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 31fc254c..f376ae88 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ NimbleTemplate has been developed and actively tested with the below environment - Mix 1.13.3 - Elixir 1.13.3 - Erlang/OTP 24.2.2 -- Phoenix 1.6.x +- Phoenix 1.6.11 - Node 16.15.0 ## Installation @@ -78,7 +78,8 @@ Contributions, issues, and feature requests are welcome!
Feel free to check ### 1. Getting `(Mix) The task "phx.new" could not be found` error The Phoenix application generator is missing. By solving this problem, you need to run -``` bash + +```bash mix archive.install hex phx_new ``` @@ -89,20 +90,22 @@ mix archive.install hex phx_new #{specific-version} ``` ### 2. Getting `Wallaby can't find chromedriver` error + Your OS is missing/not installing `chromedriver`, you need to run: Brew -``` bash + +```bash brew install --cask chromedriver ``` Apt -``` bash + +```bash apt install chromium-chromedriver ``` -Or download the package on the official site: -https://chromedriver.chromium.org/downloads +Or download the package on the official site: https://chromedriver.chromium.org/downloads ## License diff --git a/test/nimble_template/addons/test_env_test.exs b/test/nimble_template/addons/test_env_test.exs index e41f2d99..301bf0d7 100644 --- a/test/nimble_template/addons/test_env_test.exs +++ b/test/nimble_template/addons/test_env_test.exs @@ -74,23 +74,6 @@ defmodule NimbleTemplate.Addons.TestEnvTest do end) end) end - - test "creates alias Ecto.Adapters.SQL.Sandbox in test support case", %{ - project: project, - test_project_path: test_project_path - } do - in_test_project(test_project_path, fn -> - Addons.TestEnv.apply(project) - - Enum.each(["conn_case", "data_case"], fn support_case_name -> - assert_file("test/support/" <> support_case_name <> ".ex", fn file -> - assert file =~ "alias Ecto.Adapters.SQL.Sandbox" - assert file =~ "Sandbox.start_owner!" - assert file =~ "Sandbox.stop_owner" - end) - end) - end) - end end describe "#apply/2 with mix_project" do diff --git a/test/nimble_template/addons/variants/phoenix/web/esbuild_test.exs b/test/nimble_template/addons/variants/phoenix/web/esbuild_test.exs index 90940b01..454a24bc 100644 --- a/test/nimble_template/addons/variants/phoenix/web/esbuild_test.exs +++ b/test/nimble_template/addons/variants/phoenix/web/esbuild_test.exs @@ -25,7 +25,7 @@ defmodule NimbleTemplate.Addons.Phoenix.Web.EsBuildTest do assert_file("config/config.exs", fn file -> assert file =~ """ config :esbuild, - version: "0.14.0", + version: "0.14.29", app: [ args: """ From ea1c5ea6fc4df5c9561fa9badba7bb4337f3881b Mon Sep 17 00:00:00 2001 From: Thanh Huynh Date: Mon, 29 Aug 2022 14:18:16 +0700 Subject: [PATCH 61/61] [gh-198] Revert the delete content in runtime.exs --- .../addons/variants/phoenix/mix_release.ex | 20 +++++++++++++++++++ .../addons/variants/mix_release_test.exs | 16 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lib/nimble_template/addons/variants/phoenix/mix_release.ex b/lib/nimble_template/addons/variants/phoenix/mix_release.ex index 9db9f9cd..0839935d 100644 --- a/lib/nimble_template/addons/variants/phoenix/mix_release.ex +++ b/lib/nimble_template/addons/variants/phoenix/mix_release.ex @@ -27,6 +27,26 @@ defmodule NimbleTemplate.Addons.Phoenix.MixRelease do end defp edit_files(%{otp_app: otp_app, web_module: web_module} = project) do + Generator.delete_content( + "config/runtime.exs", + """ + + # ## Using releases + # + # If you use `mix release`, you need to explicitly enable the server + # by passing the PHX_SERVER=true when you start it: + # + # PHX_SERVER=true bin/#{otp_app} start + # + # Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` + # script that automatically sets the env var above. + if System.get_env("PHX_SERVER") do + config :#{otp_app}, #{web_module}.Endpoint, server: true + end + + """ + ) + Generator.replace_content( "config/runtime.exs", """ diff --git a/test/nimble_template/addons/variants/mix_release_test.exs b/test/nimble_template/addons/variants/mix_release_test.exs index 70cb5219..edef8df6 100644 --- a/test/nimble_template/addons/variants/mix_release_test.exs +++ b/test/nimble_template/addons/variants/mix_release_test.exs @@ -54,6 +54,22 @@ defmodule NimbleTemplate.Addons.Phoenix.MixReleaseTest do Set the Heroku endpoint to this variable. \"\"\" """ + + refute file =~ """ + + # ## Using releases + # + # If you use `mix release`, you need to explicitly enable the server + # by passing the PHX_SERVER=true when you start it: + # + # PHX_SERVER=true bin/nimble_template start + # + # Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` + # script that automatically sets the env var above. + if System.get_env("PHX_SERVER") do + config :nimble_template, NimbleTemplateWeb.Endpoint, server: true + end + """ end) end) end