Current section
Files
Jump to
Current section
Files
lib/mix/tasks/github_workflows.generate.ex
defmodule Mix.Tasks.GithubWorkflows.Generate do
@moduledoc """
Generates GitHub Actions YAML workflow files.
$ mix github_workflows.generate [--dir .github/workflows] [--source .github/github_workflows.ex]
Workflows will be read from the `source` file and stored in the `dir` directory.
## Options
* `--dir` - directory path to store the generated workflows. Defaults to `.github/workflows`.
* `--source` - path to the source file containing the map of workflows. Defaults to `.github/github_workflows.ex`.
## Example
Given the following `.github/github_workflows.ex` file:
```elixir
defmodule GithubWorkflows do
def get do
%{
"main.yml" => main_workflow(),
"pr.yml" => pr_workflow()
}
end
defp main_workflow do
[
[
name: "Main",
on: [
push: [
branches: ["main"]
]
],
jobs: [
test: test_job(),
deploy: [
name: "Deploy",
needs: :test,
steps: [
checkout_step(),
[
name: "Deploy",
run: "make deploy"
]
]
]
]
]
]
end
defp pr_workflow do
[
[
name: "PR",
on: [
pull_request: [
branches: ["main"]
]
],
jobs: [
test: test_job()
]
]
]
end
defp test_job do
[
name: "Test",
steps: [
checkout_step(),
[
name: "Run tests",
run: "make test"
]
]
]
end
defp checkout_step do
[
name: "Checkout",
uses: "actions/checkout@v4"
]
end
end
```
running the `mix github_workflows.generate` task will output the following files:
`.github/workflows/main.yml`:
```yaml
name: Main
on:
push:
branches:
- main
jobs:
test:
name: Test
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run tests
run: make test
deploy:
name: Deploy
needs: test
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy
run: make deploy
```
`.github/workflows/pr.yml`:
```yaml
name: PR
on:
pull_request:
branches:
- main
jobs:
test:
name: Test
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run tests
run: make test
```
More complex workflows can be found here:
https://github.com/optimumBA/github_workflows_generator/blob/main/.github/github_workflows.ex
"""
use Mix.Task
@default_dir_path ".github/workflows"
@default_source_path ".github/github_workflows.ex"
@switches [dir: :string, source: :string]
@doc false
@spec run(OptionParser.argv()) :: no_return()
def run(argv) do
{opts, _} = OptionParser.parse!(argv, strict: @switches)
dir_path = Keyword.get(opts, :dir, @default_dir_path)
source_path = Keyword.get(opts, :source, @default_source_path)
with :ok <- check_file_exists(source_path),
:ok <- maybe_create_dir(dir_path),
:ok <- GithubWorkflowsGenerator.run(source_path, dir_path) do
Mix.shell().info("Done! You can check the generated workflows in #{dir_path} directory.")
else
{:error, reason} ->
Mix.raise(reason)
end
end
defp check_file_exists(path) do
if File.exists?(path) do
:ok
else
{:error, "File not found: #{path}"}
end
end
defp maybe_create_dir(path) do
case File.mkdir_p(path) do
:ok ->
:ok
{:error, reason} ->
{:error, "Failed to create directory #{path}: #{reason}"}
end
end
end