Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

the-mikedavis/duckduck

DuckDuck Coverage Status Build Status Hex Version

DuckDuck is a mix task that uploads Distillery releases to GitHub. This is useful for CI/CD pipelines that pull directly from GitHub releases. You can get travis or circle-ci to do it for you, but in some projects (like if you use Elm or have large brunch builds,) the VMs from travis or circle are too small.

Think of Duckduck as a better version of alternative to edeliver.

To see a project that actually uses duckduck, check out doc_gen. DocGen uses elm in the front end, and I can't get that to build on travis.

Setup

Couple prerequisites for using duckduck:

Create a GitHub API Token

Click on your icon in the top right and go to Settings. Go into Developer Settings. You're a real hacker now. Click Personal Access Tokens > Generate new token. Sign in.

Write something memorable in the token description, like fossilized geese. Check the box named repo, giving access to all the children repo:status, repo_deployment, public_repo, and repo:invite. Don't check those individually and leave repo unchecked though. You'll need full repo access to upload artifacts.

Setup your Config Files for DuckDuck
DuckDuck needs to know some things about your GitHub. Setup a block like this in `config/config.exs`. Or if you're fancy, you can setup different configs for uploading releases in each environment (e.g. `config/dev.exs`).
config :duckduck,
  owner: "the-mikedavis",
  repo: "duckduck",
  token_file: "~/.goose_api_token" # this is the default value if omitted

Here owner is the repo owner and repo is the repo name as GitHub knows it. I.e. if your repo url is https://github.com/<owner>/<repo>, use those.

Instead of using a token_file, you can use the api_token: "MY_KEY" key. Please don't put your GitHub API Token in plaintext in a public repo. If you're gonna use api_token, please use an environment variable at least:

config :duckduck,
  owner: "the-mikedavis",
  repo: "duckduck",
  api_token: System.get_env("GOOSE_API_TOKEN")

Usage

First, you have to make a tag for the release and upload that to GitHub.

$ git tag -a v25 -m "Wow already v25!"
$ git push v25

(If you have a phoenix project, do the assets thing

$ cd assets; ./node_modules/.bin/webpack -p; cd .. # OR
$ cd assets; ./node_modules/.bin/brunch b -p; cd ..
$ MIX_ENV=prod mix phx.digest

)

Then make a distillery release with your new code.

$ MIX_ENV=prod mix release --env=prod

Then use duckduck to upload the release artifact that you just generated.

$ MIX_ENV=prod mix goose

N.B.

  • the MIX_ENV has to be the same as the distillery release
    • this allows you to upload dev releases, if that's your kinda thing
  • you must configure releases to be named similarly to the git tag
    • example distillery config
    • the matching is done with globbing _build/#{Mix.env()}/rel/#{app_name}/releases/#{tag}*/#{app_name}.tar.gz

Flags

  • --tag <tag> or -t <tag>: specify the tag you want to upload
  • --file <path> or -f <path>: specify the file you want to upload
  • --yes or -y: don't ask for confirmation; useful for running non-interactively

A Useful Alias

Making aliases is pretty cool. Here's an alias that does it all:

# mix.exs
defmodule MyApp.Mixfile do
  use Mix.Project

  def project do
    [
      ...
      aliases: aliases(),
      preferred_cli_env: [
        build_and_upload: :prod,
        goose: :prod
      ],
      ...
    ]
  end

  ...

  defp aliases do
    [
      build_and_upload: [&build_assets/1, "phx.digest", "release", "goose"]
    ]
  end

  # If you use brunch
  defp build_assets(_) do
    assets_path = Path.join(System.cwd!(), "assets")

    assets_path
    |> Path.join("node_modules/.bin/brunch")
    |> System.cmd(["build", "--production"], cd: assets_path)
  end

  # If you use webpack
  defp build_assets(_) do
    assets_path = Path.join(System.cwd!(), "assets")

    assets_path
    |> Path.join("node_modules/.bin/webpack")
    |> System.cmd(["--production"], cd: assets_path)
  end
end

Now you can write $ mix build_and_upload (without MIX_ENV=prod wow!) and it'll build you assets in production, digest them, build a release with distillery, and upload the tarball to GitHub.

Installation

def deps do
  [
    {:duckduck, "~> 1.1"}
  ]
end

Inspiration

I liked and used ghr for a while, but wanted a native Elixir solution. Installing go is still kinda painful.

Contributing

Having troubles using duckduck or have ideas? Send me an issue or a PR!

About

A Mix Task for uploading release artifacts to GitHub

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages