diff --git a/.github/wiki/Addon:-Github-AWS-ECS.md b/.github/wiki/Addon:-Github-AWS-ECS.md new file mode 100644 index 00000000..bd14683a --- /dev/null +++ b/.github/wiki/Addon:-Github-AWS-ECS.md @@ -0,0 +1,12 @@ +## Environment Variables + +To use this workflow, you need to config these variables in the [GitHub Actions secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) of the repository: + +- `AWS_REGION` +- `AWS_ACCESS_KEY_ID` +- `AWS_SECRET_ACCESS_KEY` +- `ECS_CLUSTER` +- `ECS_SERVICE` +- `ECS_TASK_DEFINITION` +- `ECS_CONTAINER_NAME` +- `ECR_REPOSITORY` diff --git a/.github/wiki/Addon:-Github-Wiki.md b/.github/wiki/Addon:-Github-Wiki.md new file mode 100644 index 00000000..c1a13dfb --- /dev/null +++ b/.github/wiki/Addon:-Github-Wiki.md @@ -0,0 +1,5 @@ +## Environment Variables + +To use this workflow, you need to config these variables in the [GitHub Actions secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) of the repository: + +- `WIKI_ACTION_TOKEN`: Generate [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to allow action push the markdown content files in `.github/wiki` to Github Wiki section. diff --git a/.github/wiki/_Sidebar.md b/.github/wiki/_Sidebar.md index 95317319..9cc5df86 100644 --- a/.github/wiki/_Sidebar.md +++ b/.github/wiki/_Sidebar.md @@ -9,6 +9,12 @@ - [[Docker]] - [[Testing]] +## Add-ons + +- Github + - [[Addon:-Github-AWS-ECS]] + - [[Addon:-Github-Wiki]] + ## Release - [[Release]] diff --git a/Makefile b/Makefile index ff39d38d..1a25be4b 100644 --- a/Makefile +++ b/Makefile @@ -13,12 +13,13 @@ create_mix_project: # Y - in response to Will you host this project on Github? # Y - in response to Do you want to generate the .github/ISSUE_TEMPLATE and .github/PULL_REQUEST_TEMPLATE? # Y - in response to Do you want to generate the Github Action workflows: Test? -# Y - in response to Do you want to generate the Github Action workflows: Deploy to Heroku? # Y - in response to Do you want to generate the .github/.workflow/README file? # Y - in response to Do you want to publish a Github Wiki for this project? You'd need to manually create the first Github Wiki Page and set the GH_TOKEN and GH_EMAIL secret for this to properly function. +# Y - in response to Do you want to generate the Github Action workflows: Deploy to Heroku? +# Y - in response to Do you want to generate the Github Action workflows: Deploy to AWS ECS? # Y - in response to Would you like to add the Oban addon? # Y - in response to Would you like to add the ExVCR addon? -common_addon_prompts = Y\nY\nY\nY\nY\nY\nY\nY\n +common_addon_prompts = Y\nY\nY\nY\nY\nY\nY\nY\nY\n # Y - in response to Would you like to add the SVG Sprite addon? # Y - in response to Would you like to add the Dart Sass addon? @@ -36,8 +37,9 @@ live_addon_prompts = # Y - in response to Do you want to generate the Github Action workflow: Test? # Y - in response to Do you want to generate the .github/.workflow/README file? # Y - in response to Do you want to publish a Github Wiki for this project? You'd need to manually create the first Github Wiki Page and set the GH_TOKEN and GH_EMAIL secret for this to properly function. +# Y - in response to Do you want to generate the Github Action to deploy to AWS ECS? # Y - in response to Would you like to add the Mimic addon? -mix_addon_prompts = Y\nY\nY\nY\nY\nY\n +mix_addon_prompts = Y\nY\nY\nY\nY\nY\nY\n post_setup_addon_prompts = diff --git a/lib/nimble_template/addons/github.ex b/lib/nimble_template/addons/github.ex index c99ed955..fcf60b2f 100644 --- a/lib/nimble_template/addons/github.ex +++ b/lib/nimble_template/addons/github.ex @@ -57,7 +57,8 @@ defmodule NimbleTemplate.Addons.Github do %{ github_workflows_readme: true, with_test_workflow?: with_test_workflow?, - with_deploy_to_heroku_workflow?: with_deploy_to_heroku_workflow? + with_deploy_to_heroku_workflow?: with_deploy_to_heroku_workflow?, + with_deploy_to_aws_ecs_workflow?: with_deploy_to_aws_ecs_workflow? } ) do Generator.copy_file( @@ -65,7 +66,8 @@ defmodule NimbleTemplate.Addons.Github do {:eex, ".github/workflows/README.md.eex", ".github/workflows/README.md"} ], with_test_workflow?: with_test_workflow?, - with_deploy_to_heroku_workflow?: with_deploy_to_heroku_workflow? + with_deploy_to_heroku_workflow?: with_deploy_to_heroku_workflow?, + with_deploy_to_aws_ecs_workflow?: with_deploy_to_aws_ecs_workflow? ) project @@ -98,6 +100,16 @@ defmodule NimbleTemplate.Addons.Github do project end + @impl true + def do_apply(%Project{mix_project?: false} = project, %{github_action_deploy_aws_ecs: true}) do + Generator.copy_file([ + {:eex, ".github/workflows/deploy_to_aws_ecs.yml.eex", + ".github/workflows/deploy_to_aws_ecs.yml"} + ]) + + project + end + @impl true def do_apply(%Project{} = project, %{github_wiki: true}) do project diff --git a/lib/nimble_template/helpers/github.ex b/lib/nimble_template/helpers/github.ex index d5e3835a..ab9f8e38 100644 --- a/lib/nimble_template/helpers/github.ex +++ b/lib/nimble_template/helpers/github.ex @@ -25,5 +25,8 @@ defmodule NimbleTemplate.GithubHelper do def generate_github_action_deploy_heroku?(), do: Mix.shell().yes?("\nDo you want to generate the Github Action workflows: Deploy to Heroku?") + def generate_github_action_deploy_aws_ecs?(), + do: Mix.shell().yes?("\nDo you want to generate the Github Action workflows: Deploy to AWS ECS?") + def has_github_wiki_directory?(), do: File.dir?(".github/wiki/") end diff --git a/lib/nimble_template/templates/variants/phoenix/template.ex b/lib/nimble_template/templates/variants/phoenix/template.ex index 69fbf0f8..9a2005b3 100644 --- a/lib/nimble_template/templates/variants/phoenix/template.ex +++ b/lib/nimble_template/templates/variants/phoenix/template.ex @@ -87,16 +87,24 @@ defmodule NimbleTemplate.Templates.Phoenix.Template do if generate_github_action_deploy_heroku?, do: Addons.Github.apply(project, %{github_action_deploy_heroku: true}) + generate_github_action_deploy_aws_ecs? = generate_github_action_deploy_aws_ecs?() + + if generate_github_action_deploy_aws_ecs?, + do: Addons.Github.apply(project, %{github_action_deploy_aws_ecs: true}) + if generate_github_workflows_readme?(), do: Addons.Github.apply(project, %{ github_workflows_readme: true, with_test_workflow?: generate_github_action_test?, - with_deploy_to_heroku_workflow?: generate_github_action_deploy_heroku? - }) + with_deploy_to_heroku_workflow?: generate_github_action_deploy_heroku?, + with_deploy_to_aws_ecs_workflow?: generate_github_action_deploy_aws_ecs? + }) if generate_github_wiki?(), do: Addons.Github.apply(project, %{github_wiki: true}) + + project end defp apply_phoenix_variant_setup(%Project{api_project?: true} = project), diff --git a/priv/templates/nimble_template/.github/workflows/README.md.eex b/priv/templates/nimble_template/.github/workflows/README.md.eex index c259f396..df2ec76a 100644 --- a/priv/templates/nimble_template/.github/workflows/README.md.eex +++ b/priv/templates/nimble_template/.github/workflows/README.md.eex @@ -14,7 +14,7 @@ The following workflows are supported. - A pre-generated [Heroku App](https://devcenter.heroku.com/articles/creating-apps) - A Heroku API key. It can be generated under your [Account Settings](https://dashboard.heroku.com/account#api-key) -- Three Heroku config vars: +- Three Heroku config vars: - **DATABASE_URL**: It will be created automatically when the [PostgreSQL add-on](https://elements.heroku.com/addons/heroku-postgresql) is added. - **PHX_HOST**: if your app name is `acme`, the value of this var is: `acme.herokuapp.com` - **HEALTH_PATH**: Health path (eg: "/_health") @@ -31,8 +31,19 @@ The following workflows are supported. socket "/socket", HelloWeb.UserSocket, websocket: [timeout: 45_000], longpoll: false - ... + ... ``` otherwise, leaving it set to `false` as default. <% end %> + + +<%= if with_deploy_to_aws_ecs_workflow? do %> +- [Deploy to AWS ECS](#deploy-to-aws-ecs-workflow-usage-instruction) +<% end %> + +<%= if with_deploy_to_aws_ecs_workflow? do %> +## Deploy to AWS ECS usage instruction + +### Requirements +<% end %> diff --git a/priv/templates/nimble_template/.github/workflows/deploy_to_aws_ecs.yml.eex b/priv/templates/nimble_template/.github/workflows/deploy_to_aws_ecs.yml.eex new file mode 100644 index 00000000..ce750982 --- /dev/null +++ b/priv/templates/nimble_template/.github/workflows/deploy_to_aws_ecs.yml.eex @@ -0,0 +1,74 @@ +name: Deploy to Amazon ECS + +on: + push: + branches: + - main + - develop + +env: + ECS_CLUSTER: ${{ secrets.ECS_CLUSTER }} + ECS_SERVICE: ${{ secrets.ECS_SERVICE }} + ECS_TASK_DEFINITION: ${{ secrets.ECS_TASK_DEFINITION }} + ECS_CONTAINER_NAME: ${{ secrets.ECS_CONTAINER_NAME }} + ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }} + +jobs: + deploy: + name: Deploy to ECS + runs-on: ubuntu-latest + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.6.0 + with: + access_token: ${{ github.token }} + + - name: Checkout + uses: actions/checkout@v2.3.4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build, tag, and push image to Amazon ECR + id: build-image + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + ECR_REPOSITORY: ${{ env.ECR_REPOSITORY }} + IMAGE_TAG: ${{ github.sha }} + run: | + docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" + + - name: Log out of Amazon ECR + if: always() + run: docker logout ${{ steps.login-ecr.outputs.registry }} + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition ${{ env.ECS_TASK_DEFINITION }} \ + --query taskDefinition > task-definition.json + + - name: Fill in the new image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@97587c9d45a4930bf0e3da8dd2feb2a463cf4a3a + with: + task-definition: task-definition.json + container-name: ${{ env.ECS_CONTAINER_NAME }} + image: ${{ steps.build-image.outputs.image }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@100cd113ebe287f1550436363834e6f2b2b4c16f + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + service: ${{ env.ECS_SERVICE }} + cluster: ${{ env.ECS_CLUSTER }} + wait-for-service-stability: true diff --git a/priv/templates/nimble_template/.github/workflows/publish_wiki.yml b/priv/templates/nimble_template/.github/workflows/publish_wiki.yml index 59f4b29c..cd320b58 100644 --- a/priv/templates/nimble_template/.github/workflows/publish_wiki.yml +++ b/priv/templates/nimble_template/.github/workflows/publish_wiki.yml @@ -15,4 +15,4 @@ jobs: USER_NAME: github-wiki-workflow USER_EMAIL: ${{ secrets.GH_EMAIL }} secrets: - USER_TOKEN: ${{ secrets.GH_TOKEN }} + USER_TOKEN: ${{ secrets.WIKI_ACTION_TOKEN }} diff --git a/test/nimble_template/addons/github_test.exs b/test/nimble_template/addons/github_test.exs index 36fc6d9e..a36a9c75 100644 --- a/test/nimble_template/addons/github_test.exs +++ b/test/nimble_template/addons/github_test.exs @@ -547,4 +547,19 @@ defmodule NimbleTemplate.Addons.GithubTest do end) end end + + describe "#apply/2 with web_project and github_action_deploy_to_aws_ecs option" do + test "copies the .github/workflows/deploy_to_aws_ecs.yml file", %{ + project: project, + test_project_path: test_project_path + } do + project = %{project | api_project?: false, web_project?: true} + + in_test_project(test_project_path, fn -> + Addons.Github.apply(project, %{github_action_deploy_aws_ecs: true}) + + assert_file(".github/workflows/deploy_to_aws_ecs.yml") + end) + end + end end