Improve SEO basics: metadata, Open Graph, sitemap, structured data (#34) #16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to Production | |
| on: | |
| push: | |
| branches: [master] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Image tag to deploy (leave empty for latest)' | |
| required: false | |
| type: string | |
| default: '' | |
| permissions: | |
| contents: read | |
| packages: write | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: vreshch/diffractwd.com | |
| jobs: | |
| build-and-push: | |
| name: π³ Build & Push Docker Image | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| outputs: | |
| image-tag: ${{ steps.set-tag.outputs.tag }} | |
| steps: | |
| - name: π₯ Checkout code | |
| uses: actions/checkout@v4 | |
| - name: π·οΈ Determine image tag | |
| id: set-tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.tag }}" ]; then | |
| echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT | |
| echo "π Using custom tag: ${{ inputs.tag }}" | |
| else | |
| echo "tag=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| echo "π Using commit SHA: ${{ github.sha }}" | |
| fi | |
| - name: π Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: π³ Build and push Docker image | |
| run: | | |
| IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| TAG="${{ steps.set-tag.outputs.tag }}" | |
| echo "ποΈ Building image..." | |
| docker build -t ${IMAGE}:${TAG} -t ${IMAGE}:latest . | |
| echo "π€ Pushing image..." | |
| docker push ${IMAGE}:${TAG} | |
| docker push ${IMAGE}:latest | |
| echo "β Image pushed successfully!" | |
| echo "π¦ Image: ${IMAGE}:${TAG}" | |
| echo "π¦ Image: ${IMAGE}:latest" | |
| deploy: | |
| name: π Deploy to Server | |
| needs: build-and-push | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: production | |
| steps: | |
| - name: π₯ Checkout code | |
| uses: actions/checkout@v4 | |
| - name: π§ Setup SSH | |
| run: | | |
| mkdir -p ~/.ssh | |
| echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key | |
| chmod 600 ~/.ssh/deploy_key | |
| ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts | |
| # Test SSH connection | |
| echo "Testing SSH connection..." | |
| ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no root@${{ secrets.SERVER_HOST }} "echo 'SSH connection successful'" | |
| - name: π€ Copy deployment files to server | |
| run: | | |
| echo "π¦ Ensuring remote directory exists..." | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} "mkdir -p /opt/diffractwd-com && chown root:root /opt/diffractwd-com && chmod 755 /opt/diffractwd-com" | |
| echo "π¦ Copying docker-compose.yml..." | |
| scp -i ~/.ssh/deploy_key docker-compose.yml root@${{ secrets.SERVER_HOST }}:/opt/diffractwd-com/ | |
| echo "π¦ Copying deployment script..." | |
| scp -i ~/.ssh/deploy_key scripts/deploy.sh root@${{ secrets.SERVER_HOST }}:/opt/diffractwd-com/ | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} "chmod +x /opt/diffractwd-com/deploy.sh" | |
| - name: π Deploy application | |
| id: deploy | |
| run: | | |
| IMAGE_TAG="${{ needs.build-and-push.outputs.image-tag }}" | |
| echo "π Deploying to production..." | |
| echo "π¦ Image tag: ${IMAGE_TAG}" | |
| ssh -i ~/.ssh/deploy_key root@${{ secrets.SERVER_HOST }} << EOF | |
| set -e | |
| cd /opt/diffractwd-com | |
| # Update image tag in docker-compose | |
| sed -i "s|image:.*|image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${IMAGE_TAG}|g" docker-compose.yml | |
| # Deploy to Docker Swarm | |
| echo "π³ Deploying stack..." | |
| docker stack deploy -c docker-compose.yml diffractwd --with-registry-auth | |
| # Wait for deployment | |
| echo "β³ Waiting for service to be ready..." | |
| sleep 15 | |
| # Check service status | |
| echo "β Service status:" | |
| docker service ps diffractwd_web --no-trunc --format "table {{.Name}}\t{{.CurrentState}}\t{{.Error}}" | |
| # Save deployed version | |
| echo "${IMAGE_TAG}" > .deployed-version | |
| echo "β Deployment complete!" | |
| EOF | |
| - name: β Verify deployment | |
| run: | | |
| echo "π Verifying deployment..." | |
| # Wait a bit more for service to be fully ready | |
| sleep 10 | |
| # Check if website is accessible | |
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -L https://diffractwd.com || echo "000") | |
| if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "301" ] || [ "$HTTP_CODE" = "302" ]; then | |
| echo "β Website is accessible (HTTP $HTTP_CODE)" | |
| echo "deployment-status=success" >> $GITHUB_OUTPUT | |
| else | |
| echo "β οΈ Website returned HTTP $HTTP_CODE" | |
| echo "deployment-status=warning" >> $GITHUB_OUTPUT | |
| fi | |
| echo "π Production URL: https://diffractwd.com" | |
| - name: π§Ή Cleanup | |
| if: always() | |
| run: | | |
| rm -f ~/.ssh/deploy_key | |
| echo "π§Ή Cleanup complete" | |
| deployment-summary: | |
| name: π Deployment Summary | |
| needs: [build-and-push, deploy] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: π Generate summary | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const buildResult = '${{ needs.build-and-push.result }}'; | |
| const deployResult = '${{ needs.deploy.result }}'; | |
| const imageTag = '${{ needs.build-and-push.outputs.image-tag }}'; | |
| const commitSha = '${{ github.sha }}'; | |
| const commitMessage = `${{ github.event.head_commit.message }}` || 'Manual deployment'; | |
| const eventName = '${{ github.event_name }}'; | |
| const triggerType = eventName === 'workflow_dispatch' ? 'Manual' : 'Automatic (push)'; | |
| let status = 'β SUCCESS'; | |
| let emoji = 'π'; | |
| if (buildResult === 'failure') { | |
| status = 'β FAILED - Build'; | |
| emoji = 'π¨'; | |
| } else if (deployResult === 'failure') { | |
| status = 'β FAILED - Deployment'; | |
| emoji = 'π¨'; | |
| } | |
| const summary = `${emoji} **Deployment ${status}** | |
| **Commit:** \`${commitSha.substring(0, 8)}\` | |
| **Message:** ${commitMessage} | |
| **Branch:** master | |
| **Trigger:** ${triggerType} | |
| **Pipeline Results:** | |
| - π³ Build & Push: ${buildResult === 'success' ? 'β ' : 'β'} ${buildResult} | |
| - π Deployment: ${deployResult === 'success' ? 'β ' : 'β'} ${deployResult} | |
| **Details:** | |
| - **Image Tag:** \`${imageTag}\` | |
| - **Registry:** ghcr.io/vreshch/diffractwd.com | |
| - **Server:** diffractwd.com | |
| - **Deployment URL:** https://diffractwd.com | |
| **Quick Actions:** | |
| - π [Workflow Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| - π [Visit Website](https://diffractwd.com) | |
| - π¦ [Registry](https://github.com/${{ github.repository }}/pkgs/container/diffractwd.com) | |
| --- | |
| β° Generated at: \`${new Date().toISOString()}\``; | |
| console.log(summary); | |
| // Create commit status | |
| try { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: commitSha, | |
| state: deployResult === 'success' ? 'success' : 'failure', | |
| target_url: `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`, | |
| description: `Deployment ${status}`, | |
| context: 'deployment/production' | |
| }); | |
| } catch (error) { | |
| console.log('Could not create commit status:', error.message); | |
| } |