diff --git a/.formatter.exs b/.formatter.exs index 4d5fa61..734ad7f 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,4 +1,8 @@ # Used by "mix format" [ - inputs: ["{mix,.credo,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] + inputs: [ + "{mix,.credo,.formatter}.exs", + ".github/github_workflows.ex", + "{config,lib,test}/**/*.{ex,exs}" + ] ] diff --git a/.github/github_workflows.ex b/.github/github_workflows.ex new file mode 100644 index 0000000..4caaed8 --- /dev/null +++ b/.github/github_workflows.ex @@ -0,0 +1,260 @@ +defmodule GithubWorkflows do + @moduledoc false + + def get do + %{ + "ci.yml" => ci_workflow() + } + end + + defp ci_workflow do + [ + [ + name: "CI", + on: [ + pull_request: [], + push: [ + branches: ["main"] + ] + ], + jobs: [ + compile: compile_job(), + credo: credo_job(), + deps_audit: deps_audit_job(), + dialyzer: dialyzer_job(), + format: format_job(), + hex_audit: hex_audit_job(), + prettier: prettier_job(), + test: test_job(), + unused_deps: unused_deps_job() + ] + ] + ] + end + + defp compile_job do + elixir_job("Install deps and compile", + steps: [ + [ + name: "Install Elixir dependencies", + env: [MIX_ENV: "test"], + run: "mix deps.get" + ], + [ + name: "Compile", + env: [MIX_ENV: "test"], + run: "mix compile" + ] + ] + ) + end + + defp credo_job do + elixir_job("Credo", + needs: :compile, + steps: [ + [ + name: "Check code style", + env: [MIX_ENV: "test"], + run: "mix credo --strict" + ] + ] + ) + end + + defp deps_audit_job do + elixir_job("Deps audit", + needs: :compile, + steps: [ + [ + name: "Check for vulnerable Mix dependencies", + env: [MIX_ENV: "test"], + run: "mix deps.audit" + ] + ] + ) + end + + defp dialyzer_job do + elixir_job("Dialyzer", + needs: :compile, + steps: [ + [ + name: "Restore PLT cache", + uses: "actions/cache@v3", + with: + [ + path: "priv/plts" + ] ++ cache_opts(prefix: "plt-${{ matrix.versions.runner-image }}") + ], + [ + name: "Create PLTs", + env: [MIX_ENV: "test"], + run: "mix dialyzer --plt" + ], + [ + name: "Run dialyzer", + env: [MIX_ENV: "test"], + run: "mix dialyzer --format short 2>&1" + ] + ] + ) + end + + defp elixir_job(name, opts) do + needs = Keyword.get(opts, :needs) + steps = Keyword.get(opts, :steps, []) + + job = [ + name: name, + "runs-on": "${{ matrix.versions.runner-image }}", + strategy: [ + "fail-fast": false, + matrix: [ + versions: [ + %{ + elixir: "1.11", + otp: "21.3", + "runner-image": "ubuntu-20.04" + }, + %{ + elixir: "1.16", + otp: "26.2", + "runner-image": "ubuntu-latest" + } + ] + ] + ], + steps: + [ + checkout_step(), + [ + name: "Set up Elixir", + uses: "erlef/setup-beam@v1", + with: [ + "elixir-version": "${{ matrix.versions.elixir }}", + "otp-version": "${{ matrix.versions.otp }}" + ] + ], + [ + uses: "actions/cache@v3", + with: + [ + path: ~S""" + _build + deps + """ + ] ++ cache_opts(prefix: "mix-${{ matrix.versions.runner-image }}") + ] + ] ++ steps + ] + + if needs do + Keyword.put(job, :needs, needs) + else + job + end + end + + defp format_job do + elixir_job("Format", + needs: :compile, + steps: [ + [ + name: "Check Elixir formatting", + env: [MIX_ENV: "test"], + run: "mix format --check-formatted" + ] + ] + ) + end + + defp hex_audit_job do + elixir_job("Hex audit", + needs: :compile, + steps: [ + [ + name: "Check for retired Hex packages", + env: [MIX_ENV: "test"], + run: "mix hex.audit" + ] + ] + ) + end + + defp prettier_job do + [ + name: "Check formatting using Prettier", + "runs-on": "ubuntu-latest", + steps: [ + checkout_step(), + [ + name: "Restore npm cache", + uses: "actions/cache@v3", + id: "npm-cache", + with: [ + path: "~/.npm", + key: "npm-ubuntu-latest" + ] + ], + [ + name: "Install Prettier", + if: "steps.npm-cache.outputs.cache-hit != 'true'", + run: "npm i -g prettier" + ], + [ + name: "Run Prettier", + run: "npx prettier -c ." + ] + ] + ] + end + + defp test_job do + elixir_job("Test", + needs: :compile, + steps: [ + [ + name: "Run tests", + env: [ + MIX_ENV: "test", + MUX_CREDENTIALS_EMAIL: "${{ secrets.MUX_CREDENTIALS_EMAIL }}", + MUX_CREDENTIALS_PASSWORD: "${{ secrets.MUX_CREDENTIALS_PASSWORD }}" + ], + run: "mix test --cover" + ] + ] + ) + end + + defp unused_deps_job do + elixir_job("Check unused deps", + needs: :compile, + steps: [ + [ + name: "Check for unused Mix dependencies", + env: [MIX_ENV: "test"], + run: "mix deps.unlock --check-unused" + ] + ] + ) + end + + defp checkout_step do + [ + name: "Checkout", + uses: "actions/checkout@v4" + ] + end + + defp cache_opts(opts) do + prefix = Keyword.get(opts, :prefix) + + [ + key: "#{prefix}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }}", + "restore-keys": ~s""" + #{prefix}- + """ + ] + end +end diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a7fa00f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,287 @@ +name: CI +on: + pull_request: [] + push: + branches: + - main +jobs: + compile: + name: Install deps and compile + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Install Elixir dependencies + env: + MIX_ENV: test + run: mix deps.get + - name: Compile + env: + MIX_ENV: test + run: mix compile + credo: + needs: compile + name: Credo + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Check code style + env: + MIX_ENV: test + run: mix credo --strict + deps_audit: + needs: compile + name: Deps audit + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Check for vulnerable Mix dependencies + env: + MIX_ENV: test + run: mix deps.audit + dialyzer: + needs: compile + name: Dialyzer + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Restore PLT cache + uses: actions/cache@v3 + with: + path: priv/plts + key: plt-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: plt-${{ matrix.versions.runner-image }}- + - name: Create PLTs + env: + MIX_ENV: test + run: mix dialyzer --plt + - name: Run dialyzer + env: + MIX_ENV: test + run: mix dialyzer --format short 2>&1 + format: + needs: compile + name: Format + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Check Elixir formatting + env: + MIX_ENV: test + run: mix format --check-formatted + hex_audit: + needs: compile + name: Hex audit + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Check for retired Hex packages + env: + MIX_ENV: test + run: mix hex.audit + prettier: + name: Check formatting using Prettier + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Restore npm cache + uses: actions/cache@v3 + id: npm-cache + with: + path: ~/.npm + key: npm-ubuntu-latest + - name: Install Prettier + if: steps.npm-cache.outputs.cache-hit != 'true' + run: npm i -g prettier + - name: Run Prettier + run: npx prettier -c . + test: + needs: compile + name: Test + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Run tests + env: + MIX_ENV: test + MUX_CREDENTIALS_EMAIL: ${{ secrets.MUX_CREDENTIALS_EMAIL }} + MUX_CREDENTIALS_PASSWORD: ${{ secrets.MUX_CREDENTIALS_PASSWORD }} + run: mix test --cover + unused_deps: + needs: compile + name: Check unused deps + runs-on: ${{ matrix.versions.runner-image }} + strategy: + fail-fast: false + matrix: + versions: + - otp: 21.3 + elixir: 1.11 + runner-image: ubuntu-20.04 + - otp: 26.2 + elixir: 1.16 + runner-image: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.versions.elixir }} + otp-version: ${{ matrix.versions.otp }} + - uses: actions/cache@v3 + with: + path: "_build\ndeps" + key: mix-${{ matrix.versions.runner-image }}-${{ matrix.versions.otp }}-${{ matrix.versions.elixir }}-${{ github.sha }} + restore-keys: mix-${{ matrix.versions.runner-image }}- + - name: Check for unused Mix dependencies + env: + MIX_ENV: test + run: mix deps.unlock --check-unused diff --git a/lib/mix/tasks/github_workflows.generate.ex b/lib/mix/tasks/github_workflows.generate.ex index 33e3cb7..e16518e 100644 --- a/lib/mix/tasks/github_workflows.generate.ex +++ b/lib/mix/tasks/github_workflows.generate.ex @@ -136,7 +136,7 @@ defmodule Mix.Tasks.GithubWorkflows.Generate do ``` More complex workflows can be found here: - https://github.com/optimumBA/phx.tools/blob/main/.github/github_workflows.ex + https://github.com/optimumBA/github_workflows_generator/blob/main/.github/github_workflows.ex """ diff --git a/mix.exs b/mix.exs index 98c1e64..196c8dc 100644 --- a/mix.exs +++ b/mix.exs @@ -59,7 +59,6 @@ defmodule GithubWorkflowsGenerator.MixProject do "hex.audit", "format --check-formatted", "cmd npx prettier -c .", - "compile --force --warnings-as-errors", "credo --strict", "dialyzer", "coveralls" diff --git a/test/test_helper.exs b/test/test_helper.exs index 869559e..79f403a 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1 +1,4 @@ +# TODO: Remove when Elixir v1.11 gets deprecated +Code.put_compiler_option(:warnings_as_errors, true) + ExUnit.start()