Packages
git_hub_actions
0.2.15
0.4.2
0.4.1
0.4.0
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A little tool to write GitHub actions in Elixir
Current section
Files
Jump to
Current section
Files
lib/git_hub_actions/workflow.ex
defmodule GitHubActions.Workflow do
@moduledoc """
The `GitHubActions.Workflow` is used to create a GitHub actions workflow.
```elixir
defmodule Minimal do
use GitHubActions.Workflow
def workflow do
[
name: "CI"
]
end
end
```
The workflow module must define the `workflow/0` function. This function
returns a nested data structure that will be translated in a yml-file.
The line `use GitHubActions.Workflow` imports `GitHubActions.Workflow`,
`GitHubActions.Mix` and `GitHubActions.Sigils` and adds the aliases
`GitHubActions.Config`, `GitHubActions.Project` and `GitHubActions.Versions`.
List entries with the value `:skip` are not taken over.
Key-value pairs with a value of `:skip` are also not part of the resulting
data structure.
With :skip, you can handle optional parts in a workflow script.
```elixir
defmodule Simple do
use GitHubActions.Workflow
def workflow do
[
name: "CI",
jobs: [
linux: linux(),
os2: os2()
]
]
end
defp linux do
job(:linux,
name: "Test on \#{Config.fetch!([:linux, :name])}",
runs_on: Config.fetch!([:linux, :runs_on])
)
end
defp os2 do
job(:linux,
name: "Test on \#{Config.fetch!([:os2, :name])}",
runs_on: Config.fetch!([:os2, :runs_on])
)
end
defp job(os, cofig) do
case :jobs |> Config.get([]) |> Enum.member?(os) do
true -> config
false -> :skip
end
end
end
```
It is also possible to add steps when a dependency is available in the current
project.
```elixir
defmodule Simple do
use GitHubActions.Workflow
def workflow do
[
name: "CI",
jobs: [linux: linux()]
]
end
defp linux do
name: "Test on \#{Config.fetch!([:linux, :name])}",
runs_on: Config.fetch!([:linux, :runs_on])
steps: [
checkout(),
check_code_format(),
lint_code()
]
end
defp checkout do
[
name: "Checkout",
uses: "actions/checkout@v3"
]
end
defp lint_code do
case Project.has_dep?(:credo) do
false ->
:skip
true ->
[
name: "Lint code",
run: mix(:credo, strict: true, env: :test)
]
end
end
defp check_code_format do
case Config.get(:check_code_format, true) do
false ->
:skip
true ->
[
name: "Check code format",
run: mix(:format, check_formatted: true, env: :test)
]
end
end
end
```
"""
alias GitHubActions.ConvCase
defmacro __using__(_opts) do
quote do
import GitHubActions.Workflow
import GitHubActions.Mix
import GitHubActions.Sigils
alias GitHubActions.Config
alias GitHubActions.Project
alias GitHubActions.Versions
end
end
@doc """
Evaluates a workflow script and returns the workflow data structure.
"""
@spec eval(Path.t()) :: {:ok, term()} | :error
def eval(file) do
with {:ok, module} <- compile(file),
{:ok, workflow} <- workflow(module) do
{:ok, map(workflow)}
end
end
defp workflow(module) do
case function_exported?(module, :workflow, 0) do
true -> {:ok, module.workflow()}
false -> {:error, :workflow}
end
end
defp compile(file) do
case file |> File.read!() |> Code.eval_string([], file: file) do
{{:module, module, _bin, _meta}, _bind} -> {:ok, module}
_else -> :error
end
end
defp map({_key, :skip}), do: :skip
defp map({key, value}) do
{ConvCase.to_kebab(key), map(value)}
end
defp map(workflow) when is_list(workflow) do
workflow
|> Enum.reduce([], fn item, acc ->
case map(item) do
:skip -> acc
value -> [value | acc]
end
end)
|> Enum.reverse()
end
defp map(:skip), do: :skip
defp map(value), do: to_string(value)
end