This repository provides a collection of reusable GitHub Actions workflows designed to automate CI/CD tasks for a variety of tech stacks and deployment scenarios.
| Workflow File | Description |
|---|---|
deploy-to-vps.yml |
Deploys application artifacts or containers to a self-hosted VPS. Requires at least one Git tag in the calling repository. |
sync-compose-to-vps.yml |
Uploads docker-compose assets to a VPS before running a deployment. |
java-ci.yml |
Java CI workflow: builds, tests, and verifies Java applications using Maven or Gradle. |
node-ci.yml |
Node.js CI workflow: installs dependencies, runs tests, and builds the app. |
push-to-ghcr.yml |
Pushes container images to GitHub Container Registry (GHCR). |
react-ci.yml |
Builds and tests React applications with optional deployment step. |
sonarcloud.yml |
Integrates SonarCloud for static code analysis and quality gate checks. |
springboot-push-to-ghcr.yml |
Builds Spring Boot app and pushes the OCI image to GHCR. |
java-scan.yml |
Scan Source code for vulnerabilities. |
Each workflow is designed to be reusable via workflow_call.
To use one in your project, reference it in your workflow like so:
name: Java CI
on:
push:
branches: [ main ]
jobs:
call-java-ci:
uses: your-org/your-repo/.github/workflows/java-ci.yml@main
with:
java-version: '21'name: Node CI
on:
push:
branches: [ main ]
jobs:
call-node-ci:
uses: your-org/your-repo/.github/workflows/node-ci.yml@main
with:
node-version: '20'Required secrets
SSH_PRIVATE_KEYVPS_HOSTVPS_USER
Inputs
compose-path: Path (file or directory) in your repository that should be uploaded.remote-path: Destination path on the VPS for thedocker-compose.ymlfile.
Outputs
remote-compose-path: The compose file path on the VPS (useful for deployment jobs).remote-directory: The directory containing the synced files.
name: Sync Compose Assets
on:
push:
branches: [ main ]
jobs:
sync-compose:
uses: your-org/your-repo/.github/workflows/sync-compose-to-vps.yml@main
with:
compose-path: infra/docker
remote-path: /opt/my-app/docker-compose.yml
secrets:
SSH_PRIVATE_KEY: ${{ secrets.VPS_SSH_KEY }}
VPS_HOST: ${{ secrets.VPS_HOST }}
VPS_USER: ${{ secrets.VPS_USER }}name: Sync and Deploy
on:
workflow_dispatch:
jobs:
sync-compose:
uses: your-org/your-repo/.github/workflows/sync-compose-to-vps.yml@main
with:
compose-path: infra/docker
remote-path: /opt/my-app/docker-compose.yml
secrets:
SSH_PRIVATE_KEY: ${{ secrets.VPS_SSH_KEY }}
VPS_HOST: ${{ secrets.VPS_HOST }}
VPS_USER: ${{ secrets.VPS_USER }}
deploy:
needs: sync-compose
uses: your-org/your-repo/.github/workflows/deploy-to-vps.yml@main
with:
IMAGE_NAME: my-app
COMPOSE_PATH: ${{ needs.sync-compose.outputs.remote-compose-path }}
RUN_COMPOSE_PULL: true # optional but keeps services current
secrets:
SSH_PRIVATE_KEY: ${{ secrets.VPS_SSH_KEY }}
VPS_HOST: ${{ secrets.VPS_HOST }}
VPS_USER: ${{ secrets.VPS_USER }}
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
GHCR_ORG: ${{ secrets.GHCR_ORG }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}Prerequisite: The calling repository must have at least one Git tag before this workflow runs. Create one with
git tag v1.0.0followed bygit push --tags.
name: Deploy to VPS
on:
workflow_run:
workflows: ["Build and Push"]
types:
- completed
jobs:
deploy:
uses: your-org/your-repo/.github/workflows/deploy-to-vps.yml@main
with:
IMAGE_NAME: my-app
COMPOSE_PATH: /opt/my-app/docker-compose.yml
RUN_COMPOSE_PULL: true # optional, defaults to false
secrets:
SSH_PRIVATE_KEY: \${{ secrets.VPS_SSH_KEY }}
VPS_HOST: \${{ secrets.VPS_HOST }}
VPS_USER: \${{ secrets.VPS_USER }}
GHCR_TOKEN: \${{ secrets.GHCR_TOKEN }}
GHCR_USERNAME: \${{ secrets.GHCR_USERNAME }}
GHCR_ORG: \${{ secrets.GHCR_ORG }}
DISCORD_WEBHOOK: \${{ secrets.DISCORD_WEBHOOK }}name: Release Deployment
on:
push:
tags:
- 'v*'
jobs:
deploy:
uses: your-org/your-repo/.github/workflows/deploy-to-vps.yml@main
with:
IMAGE_NAME: my-app
COMPOSE_PATH: /opt/my-app/docker-compose.yml
secrets:
SSH_PRIVATE_KEY: \${{ secrets.VPS_SSH_KEY }}
VPS_HOST: \${{ secrets.VPS_HOST }}
VPS_USER: \${{ secrets.VPS_USER }}
GHCR_TOKEN: \${{ secrets.GHCR_TOKEN }}
GHCR_USERNAME: \${{ secrets.GHCR_USERNAME }}
GHCR_ORG: \${{ secrets.GHCR_ORG }}
DISCORD_WEBHOOK: \${{ secrets.DISCORD_WEBHOOK }}name: Push Docker Image to GHCR
on:
push:
branches: [ main ]
jobs:
push-image:
uses: your-org/your-repo/.github/workflows/push-to-ghcr.yml@main
with:
image-name: my-app
secrets:
ghcr_token: \${{ secrets.GHCR_TOKEN }}name: React CI
on:
push:
branches: [ main ]
jobs:
react-build:
uses: your-org/your-repo/.github/workflows/react-ci.yml@mainname: SonarCloud Analysis
on:
push:
branches: [ main ]
jobs:
sonar:
uses: your-org/your-repo/.github/workflows/sonarcloud.yml@main
secrets:
sonar_token: \${{ secrets.SONAR_TOKEN }}name: Spring Boot Build & Push
on:
push:
branches: [ main ]
jobs:
spring-ghcr:
uses: your-org/your-repo/.github/workflows/springboot-push-to-ghcr.yml@main
with:
image-name: spring-app
secrets:
ghcr_token: \${{ secrets.GHCR_TOKEN }}- Modular and maintainable
- Designed for reuse across multiple projects
- Built-in support for container builds, SonarCloud scanning, and deployments
- GitHub Actions enabled
- Optional: Secrets like
GHCR_TOKEN,SONAR_TOKEN, orVPS_SSH_KEYdepending on workflow