diff --git a/.dialyzer_ignore.exs b/.dialyzer_ignore.exs new file mode 100644 index 0000000..05a9f48 --- /dev/null +++ b/.dialyzer_ignore.exs @@ -0,0 +1,9 @@ +# You can get the spec for these errors to ignore by running: +# $ mix dialyzer --format short +# ...and then taking that "short" output and either reproducing it whole here or by +# pulling out the file and error atom. +# +# More info in the Dialyxir README: +# https://github.com/jeremyjh/dialyxir#elixir-term-format +[ +] diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..051d09d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +eval "$(lorri direnv)" diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..b3d6784 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +[ + line_length: 140, + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fe012c8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: mix + directory: "/" + schedule: + interval: weekly + time: "12:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/elixir-build-and-test.yml b/.github/workflows/elixir-build-and-test.yml new file mode 100644 index 0000000..0007d8f --- /dev/null +++ b/.github/workflows/elixir-build-and-test.yml @@ -0,0 +1,67 @@ +name: ExUnit Tests + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +jobs: + test: + name: ExUnit Tests + runs-on: [ubuntu-20.04] + env: + MIX_ENV: test + + strategy: + matrix: + elixir: ['1.12.3', '1.13.1'] + otp: ['24.1'] + steps: + - uses: actions/checkout@v2 + - name: Setup elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{matrix.elixir}} + otp-version: ${{matrix.otp}} + - name: Cache Dependency Sources + uses: actions/cache@v2 + id: deps-cache + with: + path: deps + # If you ever need to clear the cache, increment the number after "v1" here + key: dependencies-v1-${{matrix.elixir}}-${{ hashFiles('**/mix.lock') }} + restore-keys: dependencies-${{ hashFiles('**/mix.lock') }} + - name: Cache Compiled Files + uses: actions/cache@v2 + with: + path: _build/test/ + key: compiled-test-${{matrix.elixir}}-${{ hashFiles('**/mix.lock') }} + restore-keys: compiled-test-${{matrix.elixir}} + # In my experience, I have issues with incremental builds maybe 1 in 100 + # times that are fixed by doing a full recompile. + # In order to not waste dev time on such trivial issues (while also reaping + # the time savings of incremental builds for *most* day-to-day development), + # I force a full recompile only on builds that we retry. + - name: Clean + if: github.run_attempt != '1' + run: | + mix deps.clean --all + mix clean + - name: Install Dependencies + run: mix deps.get + - name: Build + run: mix compile --all-warnings --warnings-as-errors + # If the compile fails, it's likely due to a warning. Go ahead and run the tests + # to give the devs feedback and save them some time. + - name: Run Tests + # You might consider adding the --stale flag here as well. + # Doing so will cause Mix to attempt to run only the tests that reference modules + # that have changed since the last CI run. + # https://hexdocs.pm/mix/1.12/Mix.Tasks.Test.html#module-the-stale-option + run: mix test + if: always() + + # TODO: Log test coverage diff --git a/.github/workflows/elixir-dialyzer.yml b/.github/workflows/elixir-dialyzer.yml new file mode 100644 index 0000000..dfacdbd --- /dev/null +++ b/.github/workflows/elixir-dialyzer.yml @@ -0,0 +1,46 @@ +name: Elixir Dialyzer + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +jobs: + dialyzer: + name: Run Dialyzer type checking + runs-on: [ubuntu-20.04] + + strategy: + matrix: + elixir: ['1.13.1'] + otp: ['24.1'] + steps: + - uses: actions/checkout@v2 + - name: Setup elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{matrix.elixir}} + otp-version: ${{matrix.otp}} + - name: Cache Dependency Sources + uses: actions/cache@v2 + id: deps-cache + with: + path: deps + # If you ever need to clear the cache, increment the number after "v1" here + key: dependencies-v1-${{matrix.elixir}}-${{ hashFiles('**/mix.lock') }} + restore-keys: dependencies-${{ hashFiles('**/mix.lock') }} + - name: Cache Compiled Files + uses: actions/cache@v2 + with: + path: _build/dev/ + key: compiled-dev-${{matrix.elixir}}-${{ hashFiles('**/mix.lock') }} + restore-keys: compiled-dev-${{matrix.elixir}} + - name: Install Dependencies + run: mix deps.get + - name: Generate PLT + run: mix dialyzer --plt + - name: Run Dialyzer + run: mix dialyzer diff --git a/.github/workflows/elixir-quality-checks.yml b/.github/workflows/elixir-quality-checks.yml new file mode 100644 index 0000000..860a2fa --- /dev/null +++ b/.github/workflows/elixir-quality-checks.yml @@ -0,0 +1,50 @@ +name: Elixir Quality Checks + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +jobs: + quality_checks: + runs-on: ubuntu-latest + env: + MIX_ENV: test + + strategy: + matrix: + elixir: ['1.13.1'] + otp: ['24.1'] + steps: + - uses: actions/checkout@v2 + - name: Setup elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{matrix.elixir}} + otp-version: ${{matrix.otp}} + - name: Cache Dependency Sources + uses: actions/cache@v2 + id: deps-cache + with: + path: deps + # If you ever need to clear the cache, increment the number after "v1" here + key: dependencies-v1-${{matrix.elixir}}-${{ hashFiles('**/mix.lock') }} + restore-keys: dependencies-${{ hashFiles('**/mix.lock') }} + - name: Cache Compiled Files + uses: actions/cache@v2 + with: + path: _build/test/ + key: compiled-test-${{matrix.elixir}}-${{ hashFiles('**/mix.lock') }} + restore-keys: compiled-test-${{matrix.elixir}} + - name: Install Dependencies + run: mix deps.get + - name: Run Credo + run: mix credo + # The format check gets run even if Credo fails so that + # we give the devs as much feedback as possible & save some time. + - name: Check Formatting + run: mix format --check-formatted + if: always() diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b263cd1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/_build +/cover +/deps +/doc +/.fetch +erl_crash.dump +*.ez +*.beam +/config/*.secret.exs +.elixir_ls/ diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..5032e78 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,7 @@ +# This lists the versions ASDF should use with this project. +# If you're using ASDF to manage your Elixir runtimes, you +# can do: +# $ asdf install +# to get going quickly. +elixir 1.12.3-otp-24 +erlang 24.1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6c955cf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Tyler A. Young + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3e1e15 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# ZipZip diff --git a/config/.credo.exs b/config/.credo.exs new file mode 100644 index 0000000..2b2bcf3 --- /dev/null +++ b/config/.credo.exs @@ -0,0 +1,163 @@ +# This file contains the configuration for Credo and you are probably reading +# this after creating it with `mix credo.gen.config`. +# +# If you find anything wrong or unclear in this file, please report an +# issue on GitHub: https://github.com/rrrene/credo/issues +# +%{ + # + # You can have as many configs as you like in the `configs:` field. + configs: [ + %{ + # + # Run any exec using `mix credo -C `. If no exec name is given + # "default" is used. + # + name: "default", + # + # These are the files included in the analysis: + files: %{ + # + # You can give explicit globs or simply directories. + # In the latter case `**/*.{ex,exs}` will be used. + # + included: ["lib/", "src/", "test/", "web/", "apps/"], + excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/", ~r"/data/"] + }, + # + # Load and configure plugins here: + # + plugins: [], + # + # If you create your own checks, you must specify the source files for + # them here, so they can be loaded by Credo before running the analysis. + # + requires: [ + "config/credo_checks/explicitly_ignore_return_values.ex" + ], + # + # If you want to enforce a style guide and need a more traditional linting + # experience, you can change `strict` to `true` below: + # + strict: true, + # + # If you want to use uncolored output by default, you can change `color` + # to `false` below: + # + color: true, + # + # You can customize the parameters of any check by adding a second element + # to the tuple. + # + # To disable a check put `false` as second element: + # + # {Credo.Check.Design.DuplicatedCode, false} + # + checks: [ + # + ## Consistency Checks + # + {Credo.Check.Consistency.ExceptionNames, []}, + {Credo.Check.Consistency.LineEndings, []}, + {Credo.Check.Consistency.ParameterPatternMatching, []}, + {Credo.Check.Consistency.SpaceAroundOperators, []}, + {Credo.Check.Consistency.SpaceInParentheses, []}, + {Credo.Check.Consistency.TabsOrSpaces, []}, + + # + ## Design Checks + # + # You can customize the priority of any check + # Priority values are: `low, normal, high, higher` + # + {Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, + # Don't cause to-do comments to fail + {Credo.Check.Design.TagTODO, [exit_status: 0]}, + {Credo.Check.Design.TagFIXME, []}, + + # + ## Readability Checks + # + {Credo.Check.Readability.AliasOrder, []}, + {Credo.Check.Readability.FunctionNames, []}, + {Credo.Check.Readability.LargeNumbers, []}, + {Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 140]}, + {Credo.Check.Readability.ModuleAttributeNames, []}, + {Credo.Check.Readability.ModuleDoc, []}, + {Credo.Check.Readability.ModuleNames, []}, + {Credo.Check.Readability.ParenthesesInCondition, []}, + {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, + {Credo.Check.Readability.PredicateFunctionNames, []}, + {Credo.Check.Readability.PreferImplicitTry, []}, + {Credo.Check.Readability.RedundantBlankLines, []}, + {Credo.Check.Readability.Semicolons, []}, + {Credo.Check.Readability.SpaceAfterCommas, []}, + {Credo.Check.Readability.StringSigils, []}, + {Credo.Check.Readability.TrailingBlankLine, []}, + {Credo.Check.Readability.TrailingWhiteSpace, []}, + {Credo.Check.Readability.UnnecessaryAliasExpansion, []}, + {Credo.Check.Readability.VariableNames, []}, + + # + ## Refactoring Opportunities + # + {Credo.Check.Refactor.CondStatements, []}, + {Credo.Check.Refactor.CyclomaticComplexity, []}, + {Credo.Check.Refactor.FunctionArity, []}, + {Credo.Check.Refactor.LongQuoteBlocks, []}, + {Credo.Check.Refactor.MatchInCondition, []}, + {Credo.Check.Refactor.NegatedConditionsInUnless, []}, + {Credo.Check.Refactor.NegatedConditionsWithElse, []}, + {Credo.Check.Refactor.Nesting, [max_nesting: 3]}, + {Credo.Check.Refactor.UnlessWithElse, []}, + {Credo.Check.Refactor.WithClauses, []}, + + # + ## Warnings + # + {Credo.Check.Warning.BoolOperationOnSameValues, []}, + {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, + {Credo.Check.Warning.IExPry, []}, + {Credo.Check.Warning.IoInspect, []}, + {Credo.Check.Warning.MixEnv, []}, + {Credo.Check.Warning.OperationOnSameValues, []}, + {Credo.Check.Warning.OperationWithConstantResult, []}, + {Credo.Check.Warning.RaiseInsideRescue, []}, + {Credo.Check.Warning.UnusedEnumOperation, []}, + {Credo.Check.Warning.UnusedFileOperation, []}, + {Credo.Check.Warning.UnusedKeywordOperation, []}, + {Credo.Check.Warning.UnusedListOperation, []}, + {Credo.Check.Warning.UnusedPathOperation, []}, + {Credo.Check.Warning.UnusedRegexOperation, []}, + {Credo.Check.Warning.UnusedStringOperation, []}, + {Credo.Check.Warning.UnusedTupleOperation, []}, + + # + # Controversial and experimental checks (opt-in, just replace `false` with `[]`) + # + {Credo.Check.Consistency.MultiAliasImportRequireUse, []}, + # Tyler says: I don't like this one... it just enforces that you always name your unused vars the *same* way + # either anonymously (like `_`) or with a real name (like `_client`) + {Credo.Check.Consistency.UnusedVariableNames, false}, + # Tyler says: I like this one + {Credo.Check.Design.DuplicatedCode, []}, + {Credo.Check.Readability.AliasAs, []}, + {Credo.Check.Readability.MultiAlias, []}, + {Credo.Check.Readability.Specs, false}, + {Credo.Check.Readability.SeparateAliasRequire, false}, + {Credo.Check.Readability.SinglePipe, []}, + {Credo.Check.Readability.WithCustomTaggedTuple, []}, + {Credo.Check.Refactor.ABCSize, false}, + {Credo.Check.Refactor.AppendSingleItem, []}, + {Credo.Check.Refactor.DoubleBooleanNegation, []}, + {Credo.Check.Refactor.ModuleDependencies, false}, + {Credo.Check.Refactor.PipeChainStart, false}, + # Tyler says: I like this one + {Credo.Check.Refactor.VariableRebinding, []}, + # Tyler says: I like this one + {Credo.Check.Warning.MapGetUnsafePass, []}, + {Credo.Check.Warning.UnsafeToAtom, []} + ] + } + ] +} diff --git a/elixir.nix b/elixir.nix new file mode 100644 index 0000000..4696014 --- /dev/null +++ b/elixir.nix @@ -0,0 +1,9 @@ +{ mkDerivation }: + +mkDerivation rec { + version = "1.13.0"; + + # nixnix-prefetch-url --unpack https://github.com/elixir-lang/elixir/archive/v1.13.0.tar.gz + sha256 = "1rkrx9kbs2nhkmzydm02r4wkb8wxwmg8iv0nqilpzj0skkxd6k8w"; + minimumOTPVersion = "24"; +} diff --git a/erlang.nix b/erlang.nix new file mode 100644 index 0000000..290ea78 --- /dev/null +++ b/erlang.nix @@ -0,0 +1,7 @@ +{ mkDerivation, fetchurl }: + +mkDerivation rec { + version = "24.1"; + # nix-prefetch-url --unpack https://github.com/erlang/otp/archive/OTP-24.0.5.tar.gz + sha256 = "1zxiqilnjrja2ihrsnpzlz2achkws1b7dnliw5qnzvz2sn9gf6fx"; +} diff --git a/lib/zipper.ex b/lib/zipper.ex new file mode 100644 index 0000000..80b698b --- /dev/null +++ b/lib/zipper.ex @@ -0,0 +1,3 @@ +defmodule Zipper do + @moduledoc false +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..c3d9cd5 --- /dev/null +++ b/mix.exs @@ -0,0 +1,43 @@ +defmodule ElixirStartingPoint.MixProject do + use Mix.Project + + def project do + [ + app: :zipzip, + version: "0.1.0", + build_path: "_build", + deps_path: "deps", + lockfile: "mix.lock", + elixir: "~> 1.12", + consolidate_protocols: Mix.env() != :test, + deps: deps(), + test_coverage: [tool: ExCoveralls], + preferred_cli_env: [ + coveralls: :test, + "coveralls.detail": :test, + "coveralls.html": :test + ], + dialyzer: [ + plt_add_apps: [:elixir, :mix], + flags: [ + :error_handling, + :race_conditions, + :underspecs + ], + ignore_warnings: ".dialyzer_ignore.exs" + ] + ] + end + + def application do + [] + end + + defp deps do + [ + {:credo, "~> 1.6.1", only: [:dev, :test], runtime: false}, + {:dialyxir, "~> 1.1", only: [:dev, :test], runtime: false}, + {:excoveralls, "~> 0.14", only: [:dev, :test], runtime: false} + ] + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..5e0cc11 --- /dev/null +++ b/mix.lock @@ -0,0 +1,17 @@ +%{ + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, + "certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"}, + "credo": {:hex, :credo, "1.6.2", "2f82b29a47c0bb7b72f023bf3a34d151624f1cbe1e6c4e52303b05a11166a701", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ae9dc112bc368e7b145c547bec2ed257ef88955851c15057c7835251a17211c6"}, + "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "excoveralls": {:hex, :excoveralls, "0.14.4", "295498f1ae47bdc6dce59af9a585c381e1aefc63298d48172efaaa90c3d251db", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e3ab02f2df4c1c7a519728a6f0a747e71d7d6e846020aae338173619217931c1"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, +} diff --git a/nixpkgs.nix b/nixpkgs.nix new file mode 100644 index 0000000..456b36d --- /dev/null +++ b/nixpkgs.nix @@ -0,0 +1,4 @@ +import (fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/86a3d865f4b05fb8c913980b6d470802e70fe577.tar.gz"; + sha256 ="1fj2xxhbrjgfwsr3v4mbci0i18qy0chrfcc7ijjyk418nqxaac36"; +}) diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..bd6b22f --- /dev/null +++ b/shell.nix @@ -0,0 +1,35 @@ +{ pkgs ? import ./nixpkgs.nix {} }: + +with pkgs; +let + inherit (lib) optional optionals; + + erlang = pkgs.beam.lib.callErlang ./erlang.nix {}; + + elixir = pkgs.beam.lib.callElixir ./elixir.nix { + inherit erlang; + debugInfo = true; + }; + + elixir-erlang-src = runCommand "elixir-erlang-src" {} '' + mkdir $out + ln -s ${elixir.src} $out/elixir + ln -s ${erlang.src} $out/otp + '';#used for vim configs +in + +mkShell { + buildInputs = [ erlang elixir ] + ++ optional stdenv.isLinux inotify-tools + ++ optionals stdenv.isDarwin (with darwin.apple_sdk.frameworks; [ + # For file_system on macOS. + CoreFoundation + CoreServices + ]); + + shellHook = '' + export LOCALE_ARCHIVE=/usr/lib/locale/locale-archive + ''; + +} + diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..426a91f --- /dev/null +++ b/test.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# Runs the same steps locally that will be run in CI. +# If this passes, the CI build should as well. + +mix credo --strict +CREDO_RES=$? +if [ $CREDO_RES -ne 0 ]; then + echo "" + echo "☆ ==================================== ☆" + echo "☆ Credo found problems with your code. ☆" >&2 + echo "☆ Please fix the issues above before ☆" >&2 + echo "☆ committing. ☆" >&2 + echo "☆ ==================================== ☆" + echo "" + exit $CREDO_RES +else + echo "" + echo "★ ============================== ★" + echo "★ Credo linter passed. ★" + echo "★ ============================== ★" + echo "" +fi + +mix format --check-formatted +FORMAT_RES=$? +if [ $FORMAT_RES -ne 0 ] +then + echo "" + echo "☆ ==================================== ☆" + echo "☆ Format check failed. ☆" >&2 + echo "☆ Please run $ mix format ☆" >&2 + echo "☆ before committing. ☆" >&2 + echo "☆ ==================================== ☆" + echo "" + exit $FORMAT_RES +else + echo "" + echo "★ ============================== ★" + echo "★ Formatting looks good! ★" + echo "★ ============================== ★" + echo "" +fi + +# You might consider adding the --stale flag here as well. +# Doing so will cause Mix to attempt to run only the tests that reference modules +# that have changed since the last CI run. +# https://hexdocs.pm/mix/1.12/Mix.Tasks.Test.html#module-the-stale-optionmix test +mix test +TEST_RES=$? +if [ $TEST_RES -ne 0 ] +then + echo "" + echo "☆ ==================================== ☆" + echo "☆ One or more tests failed. ☆" >&2 + echo "☆ Please fix them before committing. ☆" >&2 + echo "☆ ==================================== ☆" + echo "" + exit $TEST_RES +else + echo "" + echo "★ ============================== ★" + echo "★ Tests passed. ★" + echo "★ ============================== ★" + echo "" +fi + +mix dialyzer --plt +mix dialyzer +DIALYZER_RES=$? + +if [ $DIALYZER_RES -ne 0 ] +then + echo "" + echo "☆ ========================================= ☆" + echo "☆ Dialyzer checks failed. ☆" >&2 + echo "☆ Please fix typespecs before committing. ☆" >&2 + echo "☆ ======================================== ☆" + echo "" + exit $DIALYZER_RES +else + echo "" + echo "★ ============================== ★" + echo "★ Dialyzer passed. ★" + echo "★ ============================== ★" + echo "" +fi + +exit 0 \ No newline at end of file diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/test/zipper_test.exs b/test/zipper_test.exs new file mode 100644 index 0000000..6a07f4d --- /dev/null +++ b/test/zipper_test.exs @@ -0,0 +1,5 @@ +defmodule ZipperTest do + use ExUnit.Case, async: true + + alias Zipper +end