up
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build Test Deploy / build-test (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / authority-container (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / docs (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / deploy (push) Has been cancelled
				
			
		
			
				
	
				Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build Test Deploy / build-test (push) Has been cancelled
				
			Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			This commit is contained in:
		| @@ -1,206 +1,206 @@ | ||||
| # .gitea/workflows/promote.yml | ||||
| # Manual promotion workflow to copy staged artefacts to production | ||||
|  | ||||
| name: Promote Feedser (Manual) | ||||
|  | ||||
| on: | ||||
|   workflow_dispatch: | ||||
|     inputs: | ||||
|       include_docs: | ||||
|         description: 'Also promote the generated documentation bundle' | ||||
|         required: false | ||||
|         default: 'true' | ||||
|         type: boolean | ||||
|       tag: | ||||
|         description: 'Optional build identifier to record in the summary' | ||||
|         required: false | ||||
|         default: 'latest' | ||||
|         type: string | ||||
|  | ||||
| jobs: | ||||
|   promote: | ||||
|     runs-on: ubuntu-22.04 | ||||
|     environment: production | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Resolve staging credentials | ||||
|         id: staging | ||||
|         run: | | ||||
|           missing=() | ||||
|  | ||||
|           host="${{ secrets.STAGING_DEPLOYMENT_HOST }}" | ||||
|           if [ -z "$host" ]; then host="${{ vars.STAGING_DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then missing+=("STAGING_DEPLOYMENT_HOST"); fi | ||||
|  | ||||
|           user="${{ secrets.STAGING_DEPLOYMENT_USERNAME }}" | ||||
|           if [ -z "$user" ]; then user="${{ vars.STAGING_DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then missing+=("STAGING_DEPLOYMENT_USERNAME"); fi | ||||
|  | ||||
|           path="${{ secrets.STAGING_DEPLOYMENT_PATH }}" | ||||
|           if [ -z "$path" ]; then path="${{ vars.STAGING_DEPLOYMENT_PATH }}"; fi | ||||
|           if [ -z "$path" ]; then missing+=("STAGING_DEPLOYMENT_PATH") | ||||
|           fi | ||||
|  | ||||
|           docs_path="${{ secrets.STAGING_DOCS_PATH }}" | ||||
|           if [ -z "$docs_path" ]; then docs_path="${{ vars.STAGING_DOCS_PATH }}"; fi | ||||
|  | ||||
|           key="${{ secrets.STAGING_DEPLOYMENT_KEY }}" | ||||
|           if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.STAGING_DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then missing+=("STAGING_DEPLOYMENT_KEY"); fi | ||||
|  | ||||
|           if [ ${#missing[@]} -gt 0 ]; then | ||||
|             echo "❌ Missing staging configuration: ${missing[*]}" | ||||
|             exit 1 | ||||
|           fi | ||||
|  | ||||
|           key_file="$RUNNER_TEMP/staging_key" | ||||
|           printf '%s\n' "$key" > "$key_file" | ||||
|           chmod 600 "$key_file" | ||||
|  | ||||
|           echo "host=$host" >> $GITHUB_OUTPUT | ||||
|           echo "user=$user" >> $GITHUB_OUTPUT | ||||
|           echo "path=$path" >> $GITHUB_OUTPUT | ||||
|           echo "docs-path=$docs_path" >> $GITHUB_OUTPUT | ||||
|           echo "key-file=$key_file" >> $GITHUB_OUTPUT | ||||
|  | ||||
|       - name: Resolve production credentials | ||||
|         id: production | ||||
|         run: | | ||||
|           missing=() | ||||
|  | ||||
|           host="${{ secrets.PRODUCTION_DEPLOYMENT_HOST }}" | ||||
|           if [ -z "$host" ]; then host="${{ vars.PRODUCTION_DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then missing+=("PRODUCTION_DEPLOYMENT_HOST"); fi | ||||
|  | ||||
|           user="${{ secrets.PRODUCTION_DEPLOYMENT_USERNAME }}" | ||||
|           if [ -z "$user" ]; then user="${{ vars.PRODUCTION_DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then missing+=("PRODUCTION_DEPLOYMENT_USERNAME"); fi | ||||
|  | ||||
|           path="${{ secrets.PRODUCTION_DEPLOYMENT_PATH }}" | ||||
|           if [ -z "$path" ]; then path="${{ vars.PRODUCTION_DEPLOYMENT_PATH }}"; fi | ||||
|           if [ -z "$path" ]; then missing+=("PRODUCTION_DEPLOYMENT_PATH") | ||||
|           fi | ||||
|  | ||||
|           docs_path="${{ secrets.PRODUCTION_DOCS_PATH }}" | ||||
|           if [ -z "$docs_path" ]; then docs_path="${{ vars.PRODUCTION_DOCS_PATH }}"; fi | ||||
|  | ||||
|           key="${{ secrets.PRODUCTION_DEPLOYMENT_KEY }}" | ||||
|           if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.PRODUCTION_DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then missing+=("PRODUCTION_DEPLOYMENT_KEY"); fi | ||||
|  | ||||
|           if [ ${#missing[@]} -gt 0 ]; then | ||||
|             echo "❌ Missing production configuration: ${missing[*]}" | ||||
|             exit 1 | ||||
|           fi | ||||
|  | ||||
|           key_file="$RUNNER_TEMP/production_key" | ||||
|           printf '%s\n' "$key" > "$key_file" | ||||
|           chmod 600 "$key_file" | ||||
|  | ||||
|           echo "host=$host" >> $GITHUB_OUTPUT | ||||
|           echo "user=$user" >> $GITHUB_OUTPUT | ||||
|           echo "path=$path" >> $GITHUB_OUTPUT | ||||
|           echo "docs-path=$docs_path" >> $GITHUB_OUTPUT | ||||
|           echo "key-file=$key_file" >> $GITHUB_OUTPUT | ||||
|  | ||||
|       - name: Install rsync | ||||
|         run: | | ||||
|           if command -v rsync >/dev/null 2>&1; then | ||||
|             exit 0 | ||||
|           fi | ||||
|           CACHE_DIR="${CI_CACHE_ROOT:-/tmp}/apt" | ||||
|           mkdir -p "$CACHE_DIR" | ||||
|           KEY="rsync-$(lsb_release -rs 2>/dev/null || echo unknown)" | ||||
|           DEB_DIR="$CACHE_DIR/$KEY" | ||||
|           mkdir -p "$DEB_DIR" | ||||
|           if ls "$DEB_DIR"/rsync*.deb >/dev/null 2>&1; then | ||||
|             apt-get update | ||||
|             apt-get install -y --no-install-recommends "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb | ||||
|           else | ||||
|             apt-get update | ||||
|             apt-get download rsync libpopt0 | ||||
|             mv rsync*.deb libpopt0*.deb "$DEB_DIR"/ | ||||
|             dpkg -i "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb || apt-get install -f -y | ||||
|           fi | ||||
|  | ||||
|       - name: Fetch staging artefacts | ||||
|         id: fetch | ||||
|         run: | | ||||
|           staging_root="${{ runner.temp }}/staging" | ||||
|           mkdir -p "$staging_root/service" "$staging_root/docs" | ||||
|  | ||||
|           echo "📥 Copying service bundle from staging" | ||||
|           rsync -az --delete \ | ||||
|             -e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|             "${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs.path }}/" \ | ||||
|             "$staging_root/service/" | ||||
|  | ||||
|           if [ "${{ github.event.inputs.include_docs }}" = "true" ] && [ -n "${{ steps.staging.outputs['docs-path'] }}" ]; then | ||||
|             echo "📥 Copying documentation bundle from staging" | ||||
|             rsync -az --delete \ | ||||
|               -e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|               "${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs['docs-path'] }}/" \ | ||||
|               "$staging_root/docs/" | ||||
|           else | ||||
|             echo "ℹ️ Documentation promotion skipped" | ||||
|           fi | ||||
|  | ||||
|           echo "service-dir=$staging_root/service" >> $GITHUB_OUTPUT | ||||
|           echo "docs-dir=$staging_root/docs" >> $GITHUB_OUTPUT | ||||
|  | ||||
|       - name: Backup production service content | ||||
|         run: | | ||||
|           ssh -o StrictHostKeyChecking=no -i "${{ steps.production.outputs['key-file'] }}" \ | ||||
|             "${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}" \ | ||||
|             "set -e; TARGET='${{ steps.production.outputs.path }}'; \ | ||||
|              if [ -d \"$TARGET\" ]; then \ | ||||
|                parent=\$(dirname \"$TARGET\"); \ | ||||
|                base=\$(basename \"$TARGET\"); \ | ||||
|                backup=\"\$parent/\${base}.backup.\$(date +%Y%m%d_%H%M%S)\"; \ | ||||
|                mkdir -p \"\$backup\"; \ | ||||
|                rsync -a --delete \"$TARGET/\" \"\$backup/\"; \ | ||||
|                ls -dt \"\$parent/\${base}.backup.*\" 2>/dev/null | tail -n +6 | xargs rm -rf || true; \ | ||||
|                echo 'Backup created at ' \"\$backup\"; \ | ||||
|              else \ | ||||
|                echo 'Production service path missing; skipping backup'; \ | ||||
|              fi" | ||||
|  | ||||
|       - name: Publish service to production | ||||
|         run: | | ||||
|           rsync -az --delete \ | ||||
|             -e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|             "${{ steps.fetch.outputs['service-dir'] }}/" \ | ||||
|             "${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs.path }}/" | ||||
|  | ||||
|       - name: Promote documentation bundle | ||||
|         if: github.event.inputs.include_docs == 'true' && steps.production.outputs['docs-path'] != '' | ||||
|         run: | | ||||
|           rsync -az --delete \ | ||||
|             -e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|             "${{ steps.fetch.outputs['docs-dir'] }}/" \ | ||||
|             "${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs['docs-path'] }}/" | ||||
|  | ||||
|       - name: Promotion summary | ||||
|         run: | | ||||
|           echo "✅ Promotion completed" | ||||
|           echo "   Tag: ${{ github.event.inputs.tag }}" | ||||
|           echo "   Service: ${{ steps.staging.outputs.host }} → ${{ steps.production.outputs.host }}" | ||||
|           if [ "${{ github.event.inputs.include_docs }}" = "true" ]; then | ||||
|             echo "   Docs: included" | ||||
|           else | ||||
|             echo "   Docs: skipped" | ||||
|           fi | ||||
| # .gitea/workflows/promote.yml | ||||
| # Manual promotion workflow to copy staged artefacts to production | ||||
|  | ||||
| name: Promote Feedser (Manual) | ||||
|  | ||||
| on: | ||||
|   workflow_dispatch: | ||||
|     inputs: | ||||
|       include_docs: | ||||
|         description: 'Also promote the generated documentation bundle' | ||||
|         required: false | ||||
|         default: 'true' | ||||
|         type: boolean | ||||
|       tag: | ||||
|         description: 'Optional build identifier to record in the summary' | ||||
|         required: false | ||||
|         default: 'latest' | ||||
|         type: string | ||||
|  | ||||
| jobs: | ||||
|   promote: | ||||
|     runs-on: ubuntu-22.04 | ||||
|     environment: production | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Resolve staging credentials | ||||
|         id: staging | ||||
|         run: | | ||||
|           missing=() | ||||
|  | ||||
|           host="${{ secrets.STAGING_DEPLOYMENT_HOST }}" | ||||
|           if [ -z "$host" ]; then host="${{ vars.STAGING_DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then missing+=("STAGING_DEPLOYMENT_HOST"); fi | ||||
|  | ||||
|           user="${{ secrets.STAGING_DEPLOYMENT_USERNAME }}" | ||||
|           if [ -z "$user" ]; then user="${{ vars.STAGING_DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then missing+=("STAGING_DEPLOYMENT_USERNAME"); fi | ||||
|  | ||||
|           path="${{ secrets.STAGING_DEPLOYMENT_PATH }}" | ||||
|           if [ -z "$path" ]; then path="${{ vars.STAGING_DEPLOYMENT_PATH }}"; fi | ||||
|           if [ -z "$path" ]; then missing+=("STAGING_DEPLOYMENT_PATH") | ||||
|           fi | ||||
|  | ||||
|           docs_path="${{ secrets.STAGING_DOCS_PATH }}" | ||||
|           if [ -z "$docs_path" ]; then docs_path="${{ vars.STAGING_DOCS_PATH }}"; fi | ||||
|  | ||||
|           key="${{ secrets.STAGING_DEPLOYMENT_KEY }}" | ||||
|           if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.STAGING_DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then missing+=("STAGING_DEPLOYMENT_KEY"); fi | ||||
|  | ||||
|           if [ ${#missing[@]} -gt 0 ]; then | ||||
|             echo "❌ Missing staging configuration: ${missing[*]}" | ||||
|             exit 1 | ||||
|           fi | ||||
|  | ||||
|           key_file="$RUNNER_TEMP/staging_key" | ||||
|           printf '%s\n' "$key" > "$key_file" | ||||
|           chmod 600 "$key_file" | ||||
|  | ||||
|           echo "host=$host" >> $GITHUB_OUTPUT | ||||
|           echo "user=$user" >> $GITHUB_OUTPUT | ||||
|           echo "path=$path" >> $GITHUB_OUTPUT | ||||
|           echo "docs-path=$docs_path" >> $GITHUB_OUTPUT | ||||
|           echo "key-file=$key_file" >> $GITHUB_OUTPUT | ||||
|  | ||||
|       - name: Resolve production credentials | ||||
|         id: production | ||||
|         run: | | ||||
|           missing=() | ||||
|  | ||||
|           host="${{ secrets.PRODUCTION_DEPLOYMENT_HOST }}" | ||||
|           if [ -z "$host" ]; then host="${{ vars.PRODUCTION_DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ secrets.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then host="${{ vars.DEPLOYMENT_HOST }}"; fi | ||||
|           if [ -z "$host" ]; then missing+=("PRODUCTION_DEPLOYMENT_HOST"); fi | ||||
|  | ||||
|           user="${{ secrets.PRODUCTION_DEPLOYMENT_USERNAME }}" | ||||
|           if [ -z "$user" ]; then user="${{ vars.PRODUCTION_DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ secrets.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then user="${{ vars.DEPLOYMENT_USERNAME }}"; fi | ||||
|           if [ -z "$user" ]; then missing+=("PRODUCTION_DEPLOYMENT_USERNAME"); fi | ||||
|  | ||||
|           path="${{ secrets.PRODUCTION_DEPLOYMENT_PATH }}" | ||||
|           if [ -z "$path" ]; then path="${{ vars.PRODUCTION_DEPLOYMENT_PATH }}"; fi | ||||
|           if [ -z "$path" ]; then missing+=("PRODUCTION_DEPLOYMENT_PATH") | ||||
|           fi | ||||
|  | ||||
|           docs_path="${{ secrets.PRODUCTION_DOCS_PATH }}" | ||||
|           if [ -z "$docs_path" ]; then docs_path="${{ vars.PRODUCTION_DOCS_PATH }}"; fi | ||||
|  | ||||
|           key="${{ secrets.PRODUCTION_DEPLOYMENT_KEY }}" | ||||
|           if [ -z "$key" ]; then key="${{ secrets.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.PRODUCTION_DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then key="${{ vars.DEPLOYMENT_KEY }}"; fi | ||||
|           if [ -z "$key" ]; then missing+=("PRODUCTION_DEPLOYMENT_KEY"); fi | ||||
|  | ||||
|           if [ ${#missing[@]} -gt 0 ]; then | ||||
|             echo "❌ Missing production configuration: ${missing[*]}" | ||||
|             exit 1 | ||||
|           fi | ||||
|  | ||||
|           key_file="$RUNNER_TEMP/production_key" | ||||
|           printf '%s\n' "$key" > "$key_file" | ||||
|           chmod 600 "$key_file" | ||||
|  | ||||
|           echo "host=$host" >> $GITHUB_OUTPUT | ||||
|           echo "user=$user" >> $GITHUB_OUTPUT | ||||
|           echo "path=$path" >> $GITHUB_OUTPUT | ||||
|           echo "docs-path=$docs_path" >> $GITHUB_OUTPUT | ||||
|           echo "key-file=$key_file" >> $GITHUB_OUTPUT | ||||
|  | ||||
|       - name: Install rsync | ||||
|         run: | | ||||
|           if command -v rsync >/dev/null 2>&1; then | ||||
|             exit 0 | ||||
|           fi | ||||
|           CACHE_DIR="${CI_CACHE_ROOT:-/tmp}/apt" | ||||
|           mkdir -p "$CACHE_DIR" | ||||
|           KEY="rsync-$(lsb_release -rs 2>/dev/null || echo unknown)" | ||||
|           DEB_DIR="$CACHE_DIR/$KEY" | ||||
|           mkdir -p "$DEB_DIR" | ||||
|           if ls "$DEB_DIR"/rsync*.deb >/dev/null 2>&1; then | ||||
|             apt-get update | ||||
|             apt-get install -y --no-install-recommends "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb | ||||
|           else | ||||
|             apt-get update | ||||
|             apt-get download rsync libpopt0 | ||||
|             mv rsync*.deb libpopt0*.deb "$DEB_DIR"/ | ||||
|             dpkg -i "$DEB_DIR"/libpopt0*.deb "$DEB_DIR"/rsync*.deb || apt-get install -f -y | ||||
|           fi | ||||
|  | ||||
|       - name: Fetch staging artefacts | ||||
|         id: fetch | ||||
|         run: | | ||||
|           staging_root="${{ runner.temp }}/staging" | ||||
|           mkdir -p "$staging_root/service" "$staging_root/docs" | ||||
|  | ||||
|           echo "📥 Copying service bundle from staging" | ||||
|           rsync -az --delete \ | ||||
|             -e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|             "${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs.path }}/" \ | ||||
|             "$staging_root/service/" | ||||
|  | ||||
|           if [ "${{ github.event.inputs.include_docs }}" = "true" ] && [ -n "${{ steps.staging.outputs['docs-path'] }}" ]; then | ||||
|             echo "📥 Copying documentation bundle from staging" | ||||
|             rsync -az --delete \ | ||||
|               -e "ssh -i ${{ steps.staging.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|               "${{ steps.staging.outputs.user }}@${{ steps.staging.outputs.host }}:${{ steps.staging.outputs['docs-path'] }}/" \ | ||||
|               "$staging_root/docs/" | ||||
|           else | ||||
|             echo "ℹ️ Documentation promotion skipped" | ||||
|           fi | ||||
|  | ||||
|           echo "service-dir=$staging_root/service" >> $GITHUB_OUTPUT | ||||
|           echo "docs-dir=$staging_root/docs" >> $GITHUB_OUTPUT | ||||
|  | ||||
|       - name: Backup production service content | ||||
|         run: | | ||||
|           ssh -o StrictHostKeyChecking=no -i "${{ steps.production.outputs['key-file'] }}" \ | ||||
|             "${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}" \ | ||||
|             "set -e; TARGET='${{ steps.production.outputs.path }}'; \ | ||||
|              if [ -d \"$TARGET\" ]; then \ | ||||
|                parent=\$(dirname \"$TARGET\"); \ | ||||
|                base=\$(basename \"$TARGET\"); \ | ||||
|                backup=\"\$parent/\${base}.backup.\$(date +%Y%m%d_%H%M%S)\"; \ | ||||
|                mkdir -p \"\$backup\"; \ | ||||
|                rsync -a --delete \"$TARGET/\" \"\$backup/\"; \ | ||||
|                ls -dt \"\$parent/\${base}.backup.*\" 2>/dev/null | tail -n +6 | xargs rm -rf || true; \ | ||||
|                echo 'Backup created at ' \"\$backup\"; \ | ||||
|              else \ | ||||
|                echo 'Production service path missing; skipping backup'; \ | ||||
|              fi" | ||||
|  | ||||
|       - name: Publish service to production | ||||
|         run: | | ||||
|           rsync -az --delete \ | ||||
|             -e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|             "${{ steps.fetch.outputs['service-dir'] }}/" \ | ||||
|             "${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs.path }}/" | ||||
|  | ||||
|       - name: Promote documentation bundle | ||||
|         if: github.event.inputs.include_docs == 'true' && steps.production.outputs['docs-path'] != '' | ||||
|         run: | | ||||
|           rsync -az --delete \ | ||||
|             -e "ssh -i ${{ steps.production.outputs['key-file'] }} -o StrictHostKeyChecking=no" \ | ||||
|             "${{ steps.fetch.outputs['docs-dir'] }}/" \ | ||||
|             "${{ steps.production.outputs.user }}@${{ steps.production.outputs.host }}:${{ steps.production.outputs['docs-path'] }}/" | ||||
|  | ||||
|       - name: Promotion summary | ||||
|         run: | | ||||
|           echo "✅ Promotion completed" | ||||
|           echo "   Tag: ${{ github.event.inputs.tag }}" | ||||
|           echo "   Service: ${{ steps.staging.outputs.host }} → ${{ steps.production.outputs.host }}" | ||||
|           if [ "${{ github.event.inputs.include_docs }}" = "true" ]; then | ||||
|             echo "   Docs: included" | ||||
|           else | ||||
|             echo "   Docs: skipped" | ||||
|           fi | ||||
|   | ||||
		Reference in New Issue
	
	Block a user