1- name : Release
1+ name : Release and Deploy
22permissions :
33 packages : write
44 contents : write
55on :
6- # Triggered on new GitHub Release
7- release :
8- types : [published]
9- # Triggered on every successful Build action
106 workflow_run :
117 workflows : ["Build"]
12- branches : [main,master]
138 types :
149 - completed
15- # Manual trigger for rollback to specific release or redeploy latest
1610 workflow_dispatch :
17- inputs :
18- version :
19- default : latest
20- description : Tag you want to release.
21- required : true
2211
12+ # Only update envs here if you need to change them for this workflow
13+ env :
14+ DOCKER_BUILDKIT : 1
15+ KAMAL_REGISTRY_PASSWORD : ${{ secrets.GITHUB_TOKEN }}
16+ KAMAL_REGISTRY_USERNAME : ${{ github.actor }}
17+
18+ # Standard steps for building and deploying a .NET app via Kamal
2319jobs :
24- push_to_registry :
25- runs-on : ubuntu-22.04
26- if : ${{ github.event.workflow_run.conclusion != 'failure' }}
20+ build-and-deploy :
21+ runs-on : ubuntu-latest
2722 steps :
28- # Checkout latest or specific tag
29- - name : checkout
30- if : ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
31- uses : actions/checkout@v3
32- - name : checkout tag
33- if : ${{ github.event.inputs.version != '' && github.event.inputs.version != 'latest' }}
23+ - name : Checkout code
3424 uses : actions/checkout@v3
35- with :
36- ref : refs/tags/${{ github.event.inputs.version }}
37-
38- # Assign environment variables used in subsequent steps
39- - name : Env variable assignment
40- run : echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
41- # TAG_NAME defaults to 'latest' if not a release or manual deployment
42- - name : Assign version
25+
26+ - name : Set up environment variables
4327 run : |
44- echo "TAG_NAME=latest" >> $GITHUB_ENV
45- if [ "${{ github.event.release.tag_name }}" != "" ]; then
46- echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
47- fi;
48- if [ "${{ github.event.inputs.version }}" != "" ]; then
49- echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
50- fi;
51-
28+ echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
29+ echo "repository_name=$(echo ${{ github.repository }} | cut -d '/' -f 2)" >> $GITHUB_ENV
30+ if find . -maxdepth 2 -type f -name "Configure.Db.Migrations.cs" | grep -q .; then
31+ echo "HAS_MIGRATIONS=true" >> $GITHUB_ENV
32+ else
33+ echo "HAS_MIGRATIONS=false" >> $GITHUB_ENV
34+ fi
35+ if [ -n "${{ secrets.APPSETTINGS_PATCH }}" ]; then
36+ echo "HAS_APPSETTINGS_PATCH=true" >> $GITHUB_ENV
37+ else
38+ echo "HAS_APPSETTINGS_PATCH=false" >> $GITHUB_ENV
39+ fi
40+
5241 - name : Login to GitHub Container Registry
53- uses : docker/login-action@v2
42+ uses : docker/login-action@v3
5443 with :
5544 registry : ghcr.io
56- username : ${{ github.actor }}
57- password : ${{ secrets.GITHUB_TOKEN }}
58-
59-
60- - name : Setup dotnet
45+ username : ${{ env.KAMAL_REGISTRY_USERNAME }}
46+ password : ${{ env.KAMAL_REGISTRY_PASSWORD }}
47+
48+ - name : Setup .NET
6149 uses : actions/setup-dotnet@v3
6250 with :
63- dotnet-version : ' 8.*'
64-
65- # Build and push new docker image, skip for manual redeploy other than 'latest'
66- - name : Build and push Docker image
67- run : |
68- dotnet publish --os linux --arch x64 -c Release -p:ContainerRepository=${{ env.image_repository_name }} -p:ContainerRegistry=ghcr.io -p:ContainerImageTags=${{ env.TAG_NAME }} -p:ContainerPort=80
51+ dotnet-version : ' 8.0'
6952
70- deploy_via_ssh :
71- needs : push_to_registry
72- runs-on : ubuntu-22.04
73- if : ${{ github.event.workflow_run.conclusion != 'failure' }}
74- steps :
75- # Checkout latest or specific tag
76- - name : checkout
77- if : ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
78- uses : actions/checkout@v3
79- - name : checkout tag
80- if : ${{ github.event.inputs.version != '' && github.event.inputs.version != 'latest' }}
81- uses : actions/checkout@v3
82- with :
83- ref : refs/tags/${{ github.event.inputs.version }}
53+ - name : Install x tool
54+ run : dotnet tool install -g x
8455
85- - name : repository name fix and env
56+ - name : Apply Production AppSettings
57+ if : env.HAS_APPSETTINGS_PATCH == 'true'
58+ working-directory : ./BlazorGalleryWasm
8659 run : |
87- echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
88- echo "TAG_NAME=latest" >> $GITHUB_ENV
89- if [ "${{ github.event.release.tag_name }}" != "" ]; then
90- echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
91- fi;
92- if [ "${{ github.event.inputs.version }}" != "" ]; then
93- echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
94- fi;
95-
96- - name : Create .env file
60+ cat <<EOF >> appsettings.json.patch
61+ ${{ secrets.APPSETTINGS_PATCH }}
62+ EOF
63+ x patch appsettings.json.patch
64+
65+ - name : Build and push Docker image
9766 run : |
98- echo "Generating .env file"
99-
100- echo "# Autogenerated .env file" > .deploy/.env
101- echo "HOST_DOMAIN=${{ secrets.DEPLOY_HOST }}" >> .deploy/.env
102- echo "LETSENCRYPT_EMAIL=${{ secrets.LETSENCRYPT_EMAIL }}" >> .deploy/.env
103- echo "APP_NAME=${{ github.event.repository.name }}" >> .deploy/.env
104- echo "IMAGE_REPO=${{ env.image_repository_name }}" >> .deploy/.env
105- echo "RELEASE_VERSION=${{ env.TAG_NAME }}" >> .deploy/.env
106-
107- # Copy only the docker-compose.yml to remote server home folder
108- - name : copy files to target server via scp
109- 67+ dotnet publish --os linux --arch x64 -c Release -p:ContainerRepository=${{ env.image_repository_name }} -p:ContainerRegistry=ghcr.io -p:ContainerImageTags=latest -p:ContainerPort=80
68+
69+ - name : Set up SSH key
70+ uses :
webfactory/[email protected] 11071 with :
111- host : ${{ secrets.DEPLOY_HOST }}
112- username : ${{ secrets.DEPLOY_USERNAME }}
113- port : 22
114- key : ${{ secrets.DEPLOY_KEY }}
115- strip_components : 2
116- source : " ./.deploy/docker-compose.yml,./.deploy/.env"
117- target : " ~/.deploy/${{ github.event.repository.name }}/"
118-
119- - name : Run remote db migrations
120- 121- env :
122- APPTOKEN : ${{ secrets.GITHUB_TOKEN }}
123- USERNAME : ${{ secrets.DEPLOY_USERNAME }}
72+ ssh-private-key : ${{ secrets.SSH_PRIVATE_KEY }}
73+
74+ - name : Setup Ruby
75+ uses : ruby/setup-ruby@v1
12476 with :
125- host : ${{ secrets.DEPLOY_HOST }}
126- username : ${{ secrets.DEPLOY_USERNAME }}
127- key : ${{ secrets.DEPLOY_KEY }}
128- port : 22
129- envs : APPTOKEN,USERNAME
130- script : |
131- set -e
132- echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin
133- cd ~/.deploy/${{ github.event.repository.name }}
134- docker compose pull
135- export APP_ID=$(docker compose run --entrypoint "id -u" --rm app)
136- docker compose run --entrypoint "chown $APP_ID:$APP_ID /app/App_Data" --user root --rm app
137- docker compose up app-migration --exit-code-from app-migration
138-
139- # Deploy Docker image with your application using `docker compose up` remotely
140- - name : remote docker-compose up via ssh
141- 142- env :
143- APPTOKEN : ${{ secrets.GITHUB_TOKEN }}
144- USERNAME : ${{ secrets.DEPLOY_USERNAME }}
77+ ruby-version : 3.3.0
78+ bundler-cache : true
79+
80+ - name : Install Kamal
81+ run : gem install kamal -v 2.2.2
82+
83+ - name : Set up Docker Buildx
84+ uses : docker/setup-buildx-action@v3
14585 with :
146- host : ${{ secrets.DEPLOY_HOST }}
147- username : ${{ secrets.DEPLOY_USERNAME }}
148- key : ${{ secrets.DEPLOY_KEY }}
149- port : 22
150- envs : APPTOKEN,USERNAME
151- script : |
152- echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin
153- cd ~/.deploy/${{ github.event.repository.name }}
154- docker compose pull
155- docker compose up app -d
86+ driver-opts : image=moby/buildkit:master
87+
88+ - name : Kamal bootstrap
89+ run : kamal server bootstrap
90+
91+ - name : Check if first run and execute kamal app boot if necessary
92+ run : |
93+ FIRST_RUN_FILE=".${{ env.repository_name }}"
94+ if ! kamal server exec --no-interactive -q "test -f $FIRST_RUN_FILE"; then
95+ kamal server exec --no-interactive -q "touch $FIRST_RUN_FILE" || true
96+ kamal deploy -q -P --version latest > /dev/null 2>&1 || true
97+ else
98+ echo "Not first run, skipping kamal app boot"
99+ fi
100+
101+ - name : Ensure file permissions
102+ run : kamal server exec --no-interactive "mkdir -p /opt/docker/${{ env.repository_name }}/App_Data && chown -R 1654:1654 /opt/docker/${{ env.repository_name }}"
103+
104+ - name : Migration
105+ if : env.HAS_MIGRATIONS == 'true'
106+ run : kamal app exec --no-reuse --no-interactive --version=latest "--AppTasks=migrate"
107+
108+ - name : Deploy with Kamal
109+ run : |
110+ kamal lock release -v
111+ kamal deploy -P --version latest
0 commit comments