Skip to content

Commit

Permalink
refactor: ci and basic guides practice
Browse files Browse the repository at this point in the history
  • Loading branch information
cao7113 committed Jul 10, 2024
1 parent e53e666 commit f339ce3
Show file tree
Hide file tree
Showing 165 changed files with 8,596 additions and 59 deletions.
49 changes: 49 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This file excludes paths from the Docker build context.
#
# By default, Docker's build context includes all files (and folders) in the
# current directory. Even if a file isn't copied into the container it is still sent to
# the Docker daemon.
#
# There are multiple reasons to exclude files from the build context:
#
# 1. Prevent nested folders from being copied into the container (ex: exclude
# /assets/node_modules when copying /assets)
# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc)
# 3. Avoid sending files containing sensitive information
#
# More information on using .dockerignore is available here:
# https://docs.docker.com/engine/reference/builder/#dockerignore-file

.dockerignore

# Ignore git, but keep git HEAD and refs to access current commit hash if needed:
#
# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat
# d0b8727759e1e0e7aa3d41707d12376e373d5ecc
.git
!.git/HEAD
!.git/refs

# Common development/test artifacts
/cover/
/doc/
/test/
/tmp/
.elixir_ls

# Mix artifacts
/_build/
/deps/
*.ez

# Generated on crash by the VM
erl_crash.dump

# Static artifacts - These should be fetched and built inside the Docker image
/assets/node_modules/
/priv/static/assets/
/priv/static/cache_manifest.json

.vscode
/local/
.env*
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Elixir CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

workflow_call:

permissions:
contents: read

jobs:
build:
name: Build and test
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Elixir
# https://github.com/erlef/setup-beam
uses: erlef/setup-beam@v1
with:
version-file: .tool-versions
version-type: strict

- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Install dependencies
run: mix deps.get --only test

- name: Run tests
run: mix test
44 changes: 44 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Docker Try
on:
push:
branches:
- docker
workflow_dispatch:
workflow_call:

permissions:
contents: read

jobs:
test-docker:
runs-on: ubuntu-latest
services:
api-server:
image: cao7113/hello-phx
ports:
- 4000:4000

# https://github.com/cao7113/hello-phx/pkgs/container/hello-phx
api-server2:
image: ghcr.io/cao7113/hello-phx
ports:
- 4002:4000

steps:
# - name: Checkout code
# uses: actions/checkout@v4

- name: Ping api-server
run: |
sleep 1
echo Ping api-server
curl -sSL http://localhost:4000/api/ping
echo Ping api-server2
curl -sSL http://localhost:4002/api/ping
- name: Api build info
run: |
echo api-server build info:
curl -sSL http://localhost:4000/api | jq
echo api-server2 build info:
curl -sSL http://localhost:4002/api | jq
193 changes: 193 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
name: Release Deployment
on:
push:
tags:
- "v*"

permissions:
contents: write

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
check-ci:
name: Check CI
uses: ./.github/workflows/ci.yml

# direct use ghcr or docker-hub image?
fly-deploy:
name: Deploy fly app
runs-on: ubuntu-latest
needs: check-ci
concurrency: deploy-group
steps:
- name: Checkout code
uses: actions/checkout@v4

# https://github.com/superfly/flyctl-actions
# https://github.com/marketplace/actions/github-action-for-flyctl
- name: Setup flyctl
uses: superfly/flyctl-actions/setup-flyctl@master

- name: Deploy app
run: flyctl deploy --remote-only --build-arg GIT_COMMIT_ID=$(git log -1 --format="%H") --build-arg GIT_COMMIT_TIME=$(git log -1 --format="%ct")
env:
# https://github.com/superfly/flyctl-actions?tab=readme-ov-file#secrets
# https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/#speed-run-your-way-to-continuous-deployment
# gen cmd: fly tokens create deploy -x 999999h
# set in Github Settings -> Secrets -> Actions -> Repository secrets
# https://github.com/cao7113/hello-phx/settings/secrets/actions
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

push-images:
name: Push Docker image to Docker Hub and Github Packages
runs-on: ubuntu-latest
needs: check-ci
permissions:
packages: write
contents: read
attestations: write
id-token: write
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Set Commit Env from git command
run: |
echo GIT_COMMIT_TIME=$(git log -1 --format="%ct") >> $GITHUB_ENV
echo GIT_COMMIT_ID=$(git log -1 --format="%H") >> $GITHUB_ENV
- name: Inspect Commit Env
run: |
echo GIT_COMMIT_ID=$GIT_COMMIT_ID vs ${{ env.GIT_COMMIT_ID }} in env context
echo GIT_COMMIT_TIME=$GIT_COMMIT_TIME vs ${{ env.GIT_COMMIT_TIME }} in env context
# https://github.com/docker/login-action
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# https://github.com/docker/metadata-action
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: |
cao7113/hello-phx
ghcr.io/${{ github.repository }}
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# https://github.com/docker/build-push-action?tab=readme-ov-file#customizing
# GIT_COMMIT_TIME=$(git log -1 --format="%ct")
build-args: |
GIT_COMMIT_ID=${{ github.sha }}
GIT_COMMIT_TIME=${{ env.GIT_COMMIT_TIME }}
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-docker-hub
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true

test-docker-images:
name: Test latest docker images
needs: push-images
uses: ./.github/workflows/docker.yml

release-tar:
# strategy:
# matrix:
# # erlef/setup-beam only supports Ubuntu and Windows at this time
# os: [ubuntu-latest]
# otp: [27.x]
# elixir: [1.17.x]
name: Publish mix release tar
runs-on: ubuntu-latest
needs: check-ci
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
version-file: .tool-versions
version-type: strict

- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Install dependencies
run: mix deps.get --only prod

- name: Make mix release
run: |
export GIT_COMMIT_ID=${{ github.sha }}
export GIT_COMMIT_TIME=$(git log -1 --format="%ct")
MIX_ENV=prod RELEASE_TAR=1 mix release
# https://github.com/softprops/action-gh-release
- name: Make Github release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
# todo: add runner.os & runner.arch info in final tar filename
with:
files: _build/prod/*.tar.gz

# ssh-deploy:
# name: Deoloy to remote server by ssh
# runs-on: ubuntu-latest
# needs: release-tar
# steps:
# # https://github.com/appleboy/ssh-action
# # https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
# - name: executing remote ssh commands
# uses: appleboy/[email protected]
# with:
# host: ${{ secrets.REMOTE_HOST }}
# username: ${{ secrets.REMOTE_USERNAME }}
# key: ${{ secrets.REMOTE_PRIVKEY }}
# port: 22
# script: |
# vsn=${{ github.ref_name }}
# git_repo=${{ github.repository }}

# app_root=~/hello-phx
# script_path=${app_root}/deploy.sh

# mkdir -p $app_root
# script_url="https://raw.githubusercontent.com/${git_repo}/main/run/deploy.sh"
# if [ ! -e $script_path ]; then
# wget -q -O $script_path $script_url
# chmod +x $script_path
# echo "Setup deploy-script into ${script_path} from ${script_url}"
# else
# echo "Use existed deploy-script: ${script_path}, manually delete it when need update"
# fi

# $script_path $vsn bin/hello_api ${git_repo} 3
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@ hello_phx-*.tar
npm-debug.log
/assets/node_modules/

.vscode
.elixir_ls

.env
.env*
/priv/static/favicon-*
/priv/static/images/logo-*
/priv/static/robots-*
/priv/static/*.gz
21 changes: 21 additions & 0 deletions .iex.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# IO.puts("project .iex.exs loaded")

# helper aliases
alias HelloPhx, as: H
alias HelloPhx.Repo
alias HelloPhx.Data, as: D
alias HelloPhxWeb, as: Hw

alias HelloPhx.Catalog
alias HelloPhx.Catalog.Product
alias HelloPhx.ShoppingCart.Cart
alias HelloPhx.Orders
alias HelloPhx.Orders.Order

alias HelloPhx.Urls.Url

alias HelloPhx.Accounts
alias HelloPhx.Accounts.User

# handy functions
import Ecto.Query
2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
elixir 1.17.1-otp-27
erlang 27.0
Loading

0 comments on commit f339ce3

Please sign in to comment.