|
name: Master |
|
on: |
|
push: |
|
branches: |
|
- master |
|
- main |
|
workflow_dispatch: |
|
|
|
jobs: |
|
ci: |
|
name: CI |
|
runs-on: "ubuntu-latest" # Or probably if you have your runner as a self-hosted instance, ["self-hosted", "Linux"] |
|
container: mcr.microsoft.com/dotnet/sdk:8.0 # Run the job inside a Docker container, if you're a C# developer, you must know what that is |
|
timeout-minutes: 60 |
|
services: |
|
database: |
|
image: postgres:16 |
|
env: |
|
POSTGRES_PASSWORD: password |
|
POSTGRES_USER: postgres |
|
POSTGRES_DB: database |
|
options: >- |
|
--hostname database.internal |
|
--health-cmd "pg_isready" |
|
--health-interval 15s |
|
--health-timeout 10s |
|
--health-retries 5 |
|
--health-start-period 30s |
|
steps: |
|
- name: Checkout code |
|
uses: actions/checkout@v4 |
|
|
|
- name: Setup PostgreSQL Client |
|
run: | |
|
apt-get update |
|
apt-get install -y postgresql-client |
|
env: |
|
DEBIAN_FRONTEND: noninteractive |
|
|
|
- name: Migrate PostgreSQL tables |
|
run: | |
|
for entry in "YourProject.Migrations/Tables"/* |
|
do |
|
psql -h database.internal -U postgres -d database --no-password -a -f "$entry" |
|
done |
|
env: |
|
PGPASSWORD: password |
|
PGSSLMODE: disable |
|
|
|
- name: Fill PostgreSQL with data |
|
run: | |
|
for entry in "YourProject.Migrations/Data"/* |
|
do |
|
psql -h database.internal -U postgres -d database --no-password -a -f "$entry" |
|
done |
|
env: |
|
PGPASSWORD: password |
|
PGSSLMODE: disable |
|
|
|
- name: Build Backend |
|
run: dotnet build |
|
|
|
cd: |
|
name: CD |
|
runs-on: "ubuntu-latest" # Or, again, if you're on self-hosted, you'd probably use: ["self-hosted", "Linux"] |
|
container: mcr.microsoft.com/dotnet/sdk:8.0 |
|
timeout-minutes: 60 |
|
needs: |
|
- ci # The `ci` job above needs to successfully complete first |
|
steps: |
|
# If you're using Zerotier or Tailscale or equivalent to connect to your server, you can use their GitHub Actions script now. |
|
# (THIS IS THE RECOMMENDED WAY TO CONNECT TO YOUR SERVER, IF YOU DON'T HAVE DIRECT PRIVATE NETWORK ACCESS) |
|
# |
|
# For Zerotier: (see https://github.com/zerotier/github-action) |
|
# - name: ZeroTier |
|
# uses: zerotier/[email protected] |
|
# with: |
|
# network_id: ${{ secrets.ZEROTIER_NETWORK_ID }} |
|
# auth_token: ${{ secrets.ZEROTIER_CENTRAL_TOKEN }} |
|
# |
|
# For Tailscale: (see https://github.com/tailscale/github-action) |
|
# - name: Tailscale |
|
# uses: tailscale/github-action@v3 |
|
# with: |
|
# oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} |
|
# oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} |
|
# tags: tag:ci |
|
|
|
- name: Checkout code |
|
uses: actions/checkout@v4 |
|
|
|
- name: Install required packages |
|
run: > |
|
apt-get update && |
|
apt-get upgrade -y && |
|
apt-get install -y tar gzip curl ssh openssh-client |
|
|
|
- name: Register SSH key |
|
uses: shimataro/ssh-key-action@v2 |
|
with: |
|
key: ${{ secrets.SSH_KEY }} # Your SSH private key |
|
name: ${{ secrets.SSH_KEY_TYPE }} # This should be something like "id_ed25519" or "id_rsa" |
|
known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }} # Execute locally with `ssh-keyscan -H YOUR.IP.ADDRESS` (example: `ssh-keyscan -H 10.100.12.30`) |
|
if_key_exists: replace |
|
|
|
# Or for native scripting using bash: |
|
# mkdir -p /$(whoami)/.ssh |
|
# echo ${{ secrets.SSH_KEY }} >> /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} |
|
# echo ${{ secrets.SSH_KNOWN_HOSTS }} >> /$(whoami)/.ssh/known_hosts |
|
# chmod 700 /$(whoami)/.ssh |
|
# chmod 400 /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} |
|
|
|
- name: Build Backend |
|
run: dotnet publish -c Release |
|
|
|
- name: Copy to server |
|
run: | |
|
tar cfz YourProject.tar.gz -C ./YourProject/bin/Release/net8.0/ . |
|
scp -rp -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} YourProject.tar.gz ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }}:YourProject.tar.gz |
|
|
|
- name: Stop existing service |
|
run: | |
|
echo ${{ secrets.SSH_SUDO_PASSWORD }} | ssh -tt -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }} "sudo systemctl stop your-project" |
|
|
|
- name: Execute prepare script on remote machine |
|
run: | |
|
scp -rp -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} setup-project-service.sh ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }}:setup-project-service.sh |
|
scp -rp -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} your-project.service ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }}:your-project.service |
|
echo ${{ secrets.APPLICATION_SECRETS }} > appsettings.Production.json |
|
scp -rp -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} appsettings.Production.json ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }}:appsettings.Production.json |
|
echo ${{ secrets.SSH_SUDO_PASSWORD }} | ssh -tt -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }} "sudo bash ./setup-project-service.sh production ${{ secrets.SSH_USER }}" |
|
ssh -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }} 'rm setup-project-service.sh' |
|
|
|
- name: Start service |
|
run: | |
|
echo ${{ secrets.SSH_SUDO_PASSWORD }} | ssh -tt -i /$(whoami)/.ssh/${{ secrets.SSH_KEY_TYPE }} ${{ secrets.SSH_USER }}@${{ secrets.SSH_IP }} "sudo systemctl start your-project" |