diff --git a/.gitea/actions/buildDockerImage.yml b/.gitea/actions/buildDockerImage.yml new file mode 100644 index 0000000..f7d2b64 --- /dev/null +++ b/.gitea/actions/buildDockerImage.yml @@ -0,0 +1,35 @@ +name: Build docker image +inputs: + tag: + description: 'Docker image tag' + required: true + +outputs: + image_url: + description: 'Full image URL that was built' + value: ${{ steps.build.outputs.image_url }} + +jobs: + build_docker: + runs-on: ubuntu-latest + steps: + - name: Set up Docker Build + uses: docker/setup-buildx-action@v3 + + - name: Log in to registry + uses: docker/login-action@v3 + with: + registry: ${{ vars.INSTANCE_URL }} + username: ${{ github.actor }} + password: ${{ secrets.REGISTRY_ACCESS_TOKEN }} + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + push: true + tags: ${{ vars.INSTANCE_URL }}/tech-reborn/phoenix:${{ inputs.tag }} + + - name: Set output + shell: bash + run: | + echo "image_url=${{ vars.INSTANCE_URL }}/tech-reborn/phoenix:${{ inputs.tag }}" >> $GITHUB_OUTPUT diff --git a/.gitea/actions/deploy.yml b/.gitea/actions/deploy.yml new file mode 100644 index 0000000..dc040dc --- /dev/null +++ b/.gitea/actions/deploy.yml @@ -0,0 +1,93 @@ +name: 'Docker Compose Deploy' +description: 'Deploy application using Docker Compose' + +inputs: + compose_file: + description: 'Path to docker-compose file' + required: false + default: 'docker-compose.yml' + project_name: + description: 'Docker Compose project name' + required: true + url: + description: 'Url of the deployed application' + required: true + environment_file: + description: 'Path to environment file' + required: false + default: '.env' + image_url: + description: 'Docker image tag to deploy' + required: false + default: 'latest' + registry: + description: 'Docker registry' + required: false + default: 'git.klemp.dev' + +runs: + using: 'composite' + steps: + - uses: webfactory/ssh-agent@v0.9.1 + with: + ssh-private-key: ${{ secrets.SSH_DEPLOYMENT_KEY }} + + - name: Create environment file + shell: bash + run: | + cat > ${{ inputs.environment_file }} << EOF + IMAGE_URL=${{ inputs.image_url }} + URL=${{ inputs.url }} + REGISTRY=${{ inputs.registry }} + PROJECT_NAME=${{ inputs.project_name }} + COMPOSE_PROJECT_NAME=${{ inputs.project_name }} + EOF + + - name: Create Docker context + shell: bash + run: | + # Remove existing context if it exists + docker context rm deploy_target 2>/dev/null || true + + # Create new Docker context + docker context create deploy_target \ + --docker "host=ssh://${{ vars.ssh_user }}@${{ vars.ssh_host }}:${{ vars.ssh_port }}" + + # Verify context works + docker --context deploy_target info + + - name: Stop existing deployment + shell: bash + run: | + docker-compose --context deploy_target -f ${{ inputs.compose_file }} -p ${{ inputs.project_name }} down --remove-orphans || true + + - name: Pull latest images + shell: bash + run: | + docker-compose --context deploy_target -f ${{ inputs.compose_file }} -p ${{ inputs.project_name }} pull + + - name: Deploy with Docker Compose + id: deploy + shell: bash + run: | + # Start services + docker-compose --context deploy_target -f ${{ inputs.compose_file }} -p ${{ inputs.project_name }} up -d + + # Wait for services to be healthy + echo "Waiting for services to start..." + sleep 10 + + # Get container names + CONTAINERS=$(docker-compose --context deploy_target -f ${{ inputs.compose_file }} -p ${{ inputs.project_name }} ps --services | tr '\n' ',' | sed 's/,$//') + echo "containers=$CONTAINERS" >> $GITHUB_OUTPUT + + echo "✅ Deployment completed successfully!" + echo "🌐 URL: ${{ inputs.url }}" + echo "📦 Containers: $CONTAINERS" + + - name: Show deployment status + shell: bash + run: | + echo "=== Deployment Status ===" + docker-compose --context deploy_target -f ${{ inputs.compose_file }} -p ${{ inputs.project_name }} ps + echo "=========================" diff --git a/.gitea/actions/getTagSafeRef.yml b/.gitea/actions/getTagSafeRef.yml new file mode 100644 index 0000000..5b77397 --- /dev/null +++ b/.gitea/actions/getTagSafeRef.yml @@ -0,0 +1,20 @@ +name: Build docker image + +outputs: + branch_name: + description: 'Branch name that can be used as docker image tag' + value: ${{ steps.build.outputs.branch_name }} + +jobs: + build_docker: + runs-on: ubuntu-latest + steps: + - name: Create tag name + run: | + BRANCH_NAME="${{ github.ref }}" + CLEAN_BRANCH=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9._-]/-/g' | tr '[:upper:]' '[:lower:]') + + - name: Set output + shell: bash + run: | + echo "branch_name=$CLEAN_BRANCH" >> $GITHUB_OUTPUT diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 7a43621..b8f565f 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -38,27 +38,24 @@ jobs: - name: Check formatting run: bun --bun run format:check - build-docker-image: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 + # build-docker-image: + # runs-on: ubuntu-latest + # steps: + # - name: Set up Docker Build + # uses: docker/setup-buildx-action@v3 - - name: Set up Docker Build - uses: docker/setup-buildx-action@v3 + # - name: Log in to registry + # uses: docker/login-action@v3 + # with: + # registry: ${{ vars.INSTANCE_URL }} + # username: ${{ github.actor }} + # password: ${{ secrets.REGISTRY_ACCESS_TOKEN }} - - name: Log in to registry - uses: docker/login-action@v3 - with: - registry: ${{ vars.INSTANCE_URL }} - username: ${{ github.actor }} - password: ${{ secrets.REGISTRY_ACCESS_TOKEN }} - - - name: Build and push image - uses: docker/build-push-action@v6 - with: - push: true - tags: ${{ vars.INSTANCE_URL }}/tech-reborn/phoenix:${{ github.sha }} + # - name: Build and push image + # uses: docker/build-push-action@v6 + # with: + # push: true + # tags: ${{ vars.INSTANCE_URL }}/tech-reborn/phoenix:${{ github.sha }} # type-check: # runs-on: ubuntu-latest diff --git a/.gitea/workflows/commentDeploy.yml b/.gitea/workflows/commentDeploy.yml new file mode 100644 index 0000000..3f0784e --- /dev/null +++ b/.gitea/workflows/commentDeploy.yml @@ -0,0 +1,30 @@ +name: ChatOps Deploy +on: + issue_comment: + types: [created] + +jobs: + deploy: + if: | + github.event.issue.pull_request && + startsWith(github.event.comment.body, '/deploy') && + (github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'MEMBER') + runs-on: ubuntu-latest + steps: + - name: Get tag safe branch name + id: branch_name + uses: ./.github/actions/getTagSafeRef + + - name: Build and push image + id: docker_build + uses: ./.github/actions/buildDockerImage + with: + tag: ${{ steps.branch_name.outputs.branch_name }} + + - name: Deploy application + uses: ./.github/actions/deploy + with: + project_name: ${{ steps.branch_name.outputs.branch_name }} + url: '${{ steps.branch_name.outputs.branch_name }}.phoenix.klemp.local' + image_url: ${{ steps.docker_build.outputs.image_url }} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cba3f43 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: '3.8' +networks: + default: + external: + name: traefik-proxy + +services: + app: + image: ${IMAGE_URL} + container_name: ${PROJECT_NAME}-app + restart: unless-stopped + networks: + - traefik + - internal + labels: + - traefik.enable=true + - traefik.docker.network=traefik-proxy + - traefik.http.routers.${PROJECT_NAME}.rule=Host(`${URL}`) + - traefik.http.routers.${PROJECT_NAME}.tls.certresolver=letsencrypt + - traefik.http.services.${PROJECT_NAME}.loadbalancer.server.port=3000