diff --git a/.github/actions/elixir_setup/action.yaml b/.github/actions/elixir_setup/action.yaml new file mode 100644 index 0000000..c4d0156 --- /dev/null +++ b/.github/actions/elixir_setup/action.yaml @@ -0,0 +1,30 @@ +# Install Elixir +# +# I install the Elixir and OTP versions specified in the inputs. +# +# I take two parameters: +# - elixir-version: The version of Elixir to install. +# - otp-version: The version of OTP to install. + +name: Install Elixir +description: Install Elixir +inputs: + elixir-version: + description: "elixir version" + required: true + otp-version: + description: "otp version" + required: true +runs: + using: "composite" + steps: + # setup the beam + - name: configure beam + uses: erlef/setup-beam@v1 + with: + otp-version: ${{ inputs.otp-version }} + elixir-version: ${{ inputs.elixir-version }} + # install protobuf package + - name: Install Protobuf Elixir dependencies + shell: bash + run: mix escript.install hex protobuf --force diff --git a/.github/actions/os_setup/action.yaml b/.github/actions/os_setup/action.yaml new file mode 100644 index 0000000..61520b1 --- /dev/null +++ b/.github/actions/os_setup/action.yaml @@ -0,0 +1,18 @@ +# OS Setup +# +# I install the necessary packages at the OS level. +name: OS Setup +description: OS Setup +runs: + using: "composite" + steps: + - name: install apt packages + shell: bash + run: sudo apt-get install -y libsodium-dev protobuf-compiler + + - name: install new protobuf + shell: bash + run: | + curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v29.0/protoc-29.0-linux-x86_64.zip && \ + unzip protoc-29.0-linux-x86_64.zip -d $HOME/.local + echo "$HOME/.local" >> $GITHUB_PATH diff --git a/.github/workflows/build_release.yaml b/.github/workflows/build_release.yaml new file mode 100644 index 0000000..8dd0a9b --- /dev/null +++ b/.github/workflows/build_release.yaml @@ -0,0 +1,68 @@ +# Build Release +# +# I build a release of the project on GitHub. +# +# I take three parameters: +# - mix-env: The environment to build the release for. +# - elixir-version: The version of Elixir to use. +# - otp-version: The version of OTP to use. +name: Build Release +on: + workflow_call: + inputs: + mix-env: + required: true + type: string + elixir-version: + required: true + type: string + otp-version: + required: true + type: string + release_name: + required: true + type: string +jobs: + build_release: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + - name: setup deps and _build cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/deps + ${{ github.workspace }}/_build + key: ${{ runner.os }}-build-${{ inputs.mix-env }}-${{ hashFiles('mix.lock') }} + + - name: setup elixir + uses: ./.github/actions/elixir_setup + with: + elixir-version: ${{ inputs.elixir-version }} + otp-version: ${{ inputs.otp-version }} + + - name: install apt packages + uses: ./.github/actions/os_setup + + #--------------------------------------------------------------------------- + # Create binaries + # + # This part of the action generates all the binaries that are necessary + # for a release. + # If these need to be compiled for different elixir versions, the matrix + # should be put in the on_release.yml file. + + # - name: create the client binary + # continue-on-error: false + # shell: bash + # run: | + # MIX_ENV=prod mix do --app anoma_client escript.build + # mv "apps/anoma_client/anoma_client" "apps/anoma_client/anoma_client-elixir-${{ inputs.elixir-version }}-otp-${{ inputs.otp-version }}" + + # - name: create artifact of the client binary + # uses: actions/upload-artifact@v4 + # with: + # name: anoma_client-elixir-${{ inputs.elixir-version }}-otp-${{ inputs.otp-version }} + # path: "apps/anoma_client/anoma_client-elixir-${{ inputs.elixir-version }}-otp-${{ inputs.otp-version }}" diff --git a/.github/workflows/compile.yaml b/.github/workflows/compile.yaml new file mode 100644 index 0000000..7d0300a --- /dev/null +++ b/.github/workflows/compile.yaml @@ -0,0 +1,54 @@ +# Compile +# +# I compile the Elixir project. +# +# I take three parameters: +# - mix-env: The environment to compile the project for. +# - elixir-version: The version of Elixir to use. +# - otp-version: The version of OTP to use. +name: Compile +on: + workflow_call: + inputs: + mix-env: + required: true + type: string + elixir-version: + required: true + type: string + otp-version: + required: true + type: string +jobs: + compile: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + - name: setup deps and _build cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/deps + ${{ github.workspace }}/_build + key: ${{ runner.os }}-build-${{ inputs.mix-env }}-${{ hashFiles('mix.lock') }} + + - name: setup elixir + uses: ./.github/actions/elixir_setup + with: + elixir-version: ${{ inputs.elixir-version }} + otp-version: ${{ inputs.otp-version }} + + - name: install apt packages + uses: ./.github/actions/os_setup + + - name: fetch elixir dependencies + run: MIX_ENV=${{ inputs.mix-env }} mix deps.get + + - name: print protobuf information + shell: bash + run: protoc --version + + - name: compile elixir project + run: MIX_ENV=${{ inputs.mix-env }} mix compile diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 0000000..e69abda --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,92 @@ +# Generate Docs +# +# I generate the documentation for the project. +# I compile the documentation and publish it on GitHub pages. +# +# I take three parameters: +# - mix-env: The environment to build the release for. +# - elixir-version: The version of Elixir to use. +# - otp-version: The version of OTP to use. +name: Generate Docs +on: + workflow_call: + inputs: + mix-env: + required: true + type: string + elixir-version: + required: true + type: string + otp-version: + required: true + type: string +jobs: + compile-docs: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + - name: setup deps and _build cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/deps + ${{ github.workspace }}/_build + key: ${{ runner.os }}-build-${{ inputs.mix-env }}-${{ hashFiles('mix.lock') }} + + - name: setup elixir + uses: ./.github/actions/elixir_setup + with: + elixir-version: ${{ inputs.elixir-version }} + otp-version: ${{ inputs.otp-version }} + + - name: install apt packages + uses: ./.github/actions/os_setup + + # - name: compile docs + # shell: bash + # run: make docs-release + - name: generate docs + run: MIX_ENV=${{ inputs.mix-env }} mix docs + + publish-docs: + environment: + name: github-pages + needs: compile-docs + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + - name: setup deps and _build cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/deps + ${{ github.workspace }}/_build + key: ${{ runner.os }}-build-${{ inputs.mix-env }}-${{ hashFiles('mix.lock') }} + + - name: setup elixir + uses: ./.github/actions/elixir_setup + with: + elixir-version: ${{ inputs.elixir-version }} + otp-version: ${{ inputs.otp-version }} + + - name: install apt packages + uses: ./.github/actions/os_setup + + - name: generate docs + run: MIX_ENV=${{ inputs.mix-env }} mix docs + + - name: setup github pages + uses: actions/configure-pages@v5 + + - name: upload docs to github pages + uses: actions/upload-pages-artifact@v3 + with: + path: "./doc" + + - name: deploy github pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..633253a --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,80 @@ +# Lint +# +# I lint the codebase. +# +# I take three parameters: +# - mix-env: The environment to build the release for. +# - elixir-version: The version of Elixir to use. +# - otp-version: The version of OTP to use. +# +# Linting means the following. +# - Check if the code if formatted +# - Check if the code has trailing whitespaces +# - Check if the code has any issues reported by credo +# - Check if the code has any issues reported by dialyzer +name: Lint +on: + workflow_call: + inputs: + mix-env: + required: true + type: string + elixir-version: + required: true + type: string + otp-version: + required: true + type: string +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + - name: setup deps and _build cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/deps + ${{ github.workspace }}/_build + key: ${{ runner.os }}-build-${{ inputs.mix-env }}-${{ hashFiles('mix.lock') }} + + - name: setup plt cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/plts + key: ${{ runner.os }}-plt-${{ inputs.mix-env }}-${{ hashFiles('**/*.ex') }} + + - name: setup elixir + uses: ./.github/actions/elixir_setup + with: + elixir-version: ${{ inputs.elixir-version }} + otp-version: ${{ inputs.otp-version }} + + - name: install apt packages + uses: ./.github/actions/os_setup + + # strict credo may fail + - name: mix credo + shell: bash + continue-on-error: true + run: MIX_ENV=${{inputs.mix-env}} mix credo --strict + + # non strict credo should be blocking + - name: mix credo + shell: bash + continue-on-error: false + run: MIX_ENV=${{inputs.mix-env}} mix credo + + - name: mix format + shell: bash + run: MIX_ENV=${{inputs.mix-env}} mix format --check-formatted + + - name: mix dialyzer + shell: bash + run: MIX_ENV=${{inputs.mix-env}} mix dialyzer --format github + + - name: trailing whitespaces + shell: bash + run: git diff-tree --check 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD diff --git a/.github/workflows/on_main_or_next_or_base.yaml b/.github/workflows/on_main_or_next_or_base.yaml new file mode 100644 index 0000000..bfd650e --- /dev/null +++ b/.github/workflows/on_main_or_next_or_base.yaml @@ -0,0 +1,42 @@ +# Push On Main/Next/Base +# +# This is the pipeline that will run for every push on main or next or base. +# +# The pipeline does the following. +# 1. Compile the source code for all environments (dev, test, prod) +# 2. Run the linter on the source code. +# 3. Run the entire test suite + +name: Push On Main/Next/Base +run-name: Push on `${{ github.ref_name }}` + +on: + push: + branches: ["main", "next", "base"] + +jobs: + compile: + strategy: + matrix: + target: [dev, test, prod] + uses: ./.github/workflows/compile.yaml + with: + mix-env: ${{ matrix.target }} + elixir-version: "1.17" + otp-version: "27.1" + + lint: + needs: compile + uses: ./.github/workflows/lint.yaml + with: + mix-env: "dev" + elixir-version: "1.17" + otp-version: "27.1" + + test: + needs: compile + uses: ./.github/workflows/test.yaml + with: + mix-env: "test" + elixir-version: "1.17" + otp-version: "27.1" diff --git a/.github/workflows/on_pull_request.yaml b/.github/workflows/on_pull_request.yaml new file mode 100644 index 0000000..26dbbac --- /dev/null +++ b/.github/workflows/on_pull_request.yaml @@ -0,0 +1,47 @@ +# Pull Request +# +# This is the pipeline that will run for every pull request that is created against the base branch. +# +# The pipeline does the following. +# 0. Try to merge this release with next. +# 1. Compile the source code for all environments (dev, test, prod) +# 2. Run the linter on the source code. +# 3. Run the entire test suite + +name: Pull Request +run-name: Pull request `${{ github.head_ref }}` into `${{ github.base_ref }}` +on: + pull_request: + branches: ["base"] + +jobs: + try_merge: + uses: ./.github/workflows/try_merge.yaml + with: + merge_with: "main" + + compile: + strategy: + matrix: + target: [dev, test, prod] + uses: ./.github/workflows/compile.yaml + with: + mix-env: ${{ matrix.target }} + elixir-version: "1.17" + otp-version: "27.1" + + lint: + needs: compile + uses: ./.github/workflows/lint.yaml + with: + mix-env: "dev" + elixir-version: "1.17" + otp-version: "27.1" + + test: + needs: compile + uses: ./.github/workflows/test.yaml + with: + mix-env: "test" + elixir-version: "1.17" + otp-version: "27.1" diff --git a/.github/workflows/on_push.yml b/.github/workflows/on_push.yml new file mode 100644 index 0000000..35a3326 --- /dev/null +++ b/.github/workflows/on_push.yml @@ -0,0 +1,35 @@ +# Push +# +# This is the pipeline that will run for every pushed commit, except for main and next. +# +# The pipeline does the following. +# 1. Compile the source code for all environments (dev, test, prod) +# 2. Run the linter on the source code. + +name: Push +run-name: Push on `${{ github.ref_name }}` +on: + push: + branches-ignore: + - 'main' + - 'next' + - 'base' + +jobs: + compile: + strategy: + matrix: + target: [dev, test, prod] + uses: ./.github/workflows/compile.yaml + with: + mix-env: ${{ matrix.target }} + elixir-version: "1.17" + otp-version: "27.1" + + lint: + needs: compile + uses: ./.github/workflows/lint.yaml + with: + mix-env: "dev" + elixir-version: "1.17" + otp-version: "27.1" diff --git a/.github/workflows/on_release.yaml b/.github/workflows/on_release.yaml new file mode 100644 index 0000000..7e76bba --- /dev/null +++ b/.github/workflows/on_release.yaml @@ -0,0 +1,88 @@ +# Release +# +# This is the pipeline that will run for every release. +# A release is a tag that starts with a "v" followed by a version number. +# In brief, pushing a tag will run this pipeline. +# +# The pipeline does the following. +# 0. Try to merge this release with next. +# 1. Compile the source code for all environments (dev, test, prod) +# 2. Run the linter on the source code. +# 3. Run the entire test suite +# 4. Compile the documentation +# 5. Make a release on GitHub + +name: Release +run-name: Release `${{ github.ref_name }}` + +on: + push: + tags: + - v* + +jobs: + compile: + strategy: + matrix: + mix_env: [dev, test, prod] + uses: ./.github/workflows/compile.yaml + with: + mix-env: ${{ matrix.mix_env }} + elixir-version: "1.17" + otp-version: "27.1" + + lint: + needs: compile + uses: ./.github/workflows/lint.yaml + with: + mix-env: "dev" + elixir-version: "1.17" + otp-version: "27.1" + + test: + needs: compile + uses: ./.github/workflows/test.yaml + with: + mix-env: "test" + elixir-version: "1.17" + otp-version: "27.1" + + docs: + needs: compile + permissions: + contents: write + id-token: write + pages: write + uses: ./.github/workflows/docs.yaml + with: + mix-env: "dev" + elixir-version: "1.17" + otp-version: "27.1" + + make_release: + needs: [compile, lint, test, docs] + strategy: + matrix: + beam_versions: + - otp: "27.1" + elixir: "1.17" + # - otp: "26.2.5.5" + # elixir: "1.17" + permissions: + contents: write + id-token: write + pages: write + uses: ./.github/workflows/build_release.yaml + with: + mix-env: "prod" + elixir-version: "${{ matrix.beam_versions.elixir }}" + otp-version: "${{ matrix.beam_versions.otp }}" + release_name: ${{ github.ref_name }} + + publish_release: + needs: [make_release] + permissions: + contents: write + id-token: write + pages: write + uses: ./.github/workflows/publish_release.yaml diff --git a/.github/workflows/publish_release.yaml b/.github/workflows/publish_release.yaml new file mode 100644 index 0000000..1436445 --- /dev/null +++ b/.github/workflows/publish_release.yaml @@ -0,0 +1,57 @@ +# Build Release +# +# I publish a release on GitHub +name: Publish Release +on: + workflow_call: + +jobs: + build_release: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + #--------------------------------------------------------------------------- + # Create a GitHub release + + - name: ensure that the release does not exist yet + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + export RELEASE=$(gh release list --json name | jq '.[] | select(.name == "${{ github.ref_name }}") | .name') ; \ + test -z "${RELEASE}" || echo "release ${RELEASE} already exists" + + - name: create the release on github + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + gh release create ${{ github.ref_name }} \ + --title ${{ github.ref_name }} \ + --repo ${{ github.repository }} + + #--------------------------------------------------------------------------- + # Add the client binary to the release + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + - name: Display structure of downloaded files + run: ls -la artifacts + + #--------------------------------------------------------------------------- + # Push artifacts for this release + + - name: publish all release binaries + shell: bash + env: + GH_TOKEN: ${{ secrets.github_token }} + run: | + for f in artifacts/*; do + gh release upload ${{ github.ref_name }} --clobber $f + done \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..ca440df --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,49 @@ +# Test +# +# I run the testsuite on the code base. +# If any tests fail, I fail. +# +# I take three parameters: +# - mix-env: The environment to build the release for. +# - elixir-version: The version of Elixir to use. +# - otp-version: The version of OTP to use. +name: Test +on: + workflow_call: + inputs: + mix-env: + required: true + type: string + elixir-version: + required: true + type: string + otp-version: + required: true + type: string +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + + - name: setup deps and _build cache + uses: actions/cache@v4 + with: + path: | + ${{ github.workspace }}/deps + ${{ github.workspace }}/_build + key: ${{ runner.os }}-build-${{ inputs.mix-env }}-${{ hashFiles('mix.lock') }} + + - name: setup elixir + uses: ./.github/actions/elixir_setup + with: + elixir-version: ${{ inputs.elixir-version }} + otp-version: ${{ inputs.otp-version }} + + - name: install apt packages + uses: ./.github/actions/os_setup + + - name: mix test + shell: bash + run: MIX_ENV=${{inputs.mix-env}} mix test diff --git a/.github/workflows/try_merge.yaml b/.github/workflows/try_merge.yaml new file mode 100644 index 0000000..15255e7 --- /dev/null +++ b/.github/workflows/try_merge.yaml @@ -0,0 +1,39 @@ +# Try Merge +# +# I will try to merge the current branch onto the target branch. +# If the merge fails, I error. +# +# I take one parameter: +# - merge_with: The branch to merge the current branch with. + +name: Try Merge +on: + workflow_call: + inputs: + merge_with: + required: true + type: string +jobs: + try-merge: + runs-on: ubuntu-latest + steps: + - name: checkout the repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # fetch all branches + + # get the current commit hash and store in the environment under `$SHA` + - name: get the current commit hash + id: commit_hash + shell: bash + run: echo "SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV + + # checkout the target branch + - name: checkout the target branch + shell: bash + run: git checkout ${{ inputs.merge_with }} + + # try and merge the commit into the target branch + - name: merge the commit into the checked out branch + shell: bash + run: git -c user.name="Dummy User" -c user.email="example@example.com" merge $SHA diff --git a/lib/examples/stack_examples.ex b/lib/examples/stack_examples.ex index 0f86229..31e0ed6 100644 --- a/lib/examples/stack_examples.ex +++ b/lib/examples/stack_examples.ex @@ -15,7 +15,6 @@ defmodule Examples.Stack do example empty_stack_should_be_empty do stack = new_stack() - assert Stack.empty?(stack) end