286 lines
9.7 KiB
Bash
Executable File
286 lines
9.7 KiB
Bash
Executable File
#!/bin/bash
|
||
# scripts/ci/publish.sh - Публикация Docker образов в registry
|
||
|
||
set -e
|
||
|
||
echo "📤 Publishing Docker images to registry..."
|
||
|
||
# Переменные
|
||
REGISTRY=${DOCKER_REGISTRY:-"registry.hub.docker.com"}
|
||
PROJECT_NAME="catlink"
|
||
VERSION=${DRONE_TAG:-${DRONE_COMMIT_SHA:0:8}}
|
||
DOCKER_USERNAME=${DOCKER_USERNAME}
|
||
DOCKER_PASSWORD=${DOCKER_PASSWORD}
|
||
|
||
echo "📋 Publish information:"
|
||
echo " • Registry: $REGISTRY"
|
||
echo " • Project: $PROJECT_NAME"
|
||
echo " • Version: $VERSION"
|
||
echo " • Username: ${DOCKER_USERNAME:0:3}***"
|
||
|
||
# Проверка учетных данных
|
||
if [ -z "$DOCKER_USERNAME" ] || [ -z "$DOCKER_PASSWORD" ]; then
|
||
echo "❌ Docker registry credentials not found!"
|
||
echo "Please set DOCKER_USERNAME and DOCKER_PASSWORD environment variables"
|
||
exit 1
|
||
fi
|
||
|
||
# Вход в Docker registry
|
||
echo "🔐 Authenticating with Docker registry..."
|
||
echo "$DOCKER_PASSWORD" | docker login "$REGISTRY" -u "$DOCKER_USERNAME" --password-stdin
|
||
|
||
if [ $? -ne 0 ]; then
|
||
echo "❌ Failed to authenticate with Docker registry"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ Successfully authenticated with registry"
|
||
|
||
# Список образов для публикации
|
||
IMAGES=(
|
||
"$REGISTRY/$PROJECT_NAME-backend:$VERSION"
|
||
"$REGISTRY/$PROJECT_NAME-backend:latest"
|
||
"$REGISTRY/$PROJECT_NAME-frontend:$VERSION"
|
||
"$REGISTRY/$PROJECT_NAME-frontend:latest"
|
||
)
|
||
|
||
# Проверка существования образов локально
|
||
echo "🔍 Checking local images..."
|
||
for image in "${IMAGES[@]}"; do
|
||
if docker images --format "table {{.Repository}}:{{.Tag}}" | grep -q "${image#*/}"; then
|
||
echo " ✅ Found: $image"
|
||
else
|
||
echo " ❌ Missing: $image"
|
||
echo "Error: Local image $image not found. Please run build first."
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
# Публикация образов
|
||
echo "🚀 Publishing images..."
|
||
for image in "${IMAGES[@]}"; do
|
||
echo " • Publishing $image..."
|
||
|
||
# Проверка размера образа
|
||
size=$(docker images --format "table {{.Size}}" "$image" | tail -n +2)
|
||
echo " Size: $size"
|
||
|
||
# Публикация с повторными попытками
|
||
for attempt in 1 2 3; do
|
||
echo " Attempt $attempt/3..."
|
||
|
||
if docker push "$image"; then
|
||
echo " ✅ Successfully pushed $image"
|
||
break
|
||
else
|
||
echo " ❌ Failed to push $image (attempt $attempt/3)"
|
||
if [ $attempt -eq 3 ]; then
|
||
echo "Error: Failed to push $image after 3 attempts"
|
||
exit 1
|
||
fi
|
||
sleep 5
|
||
fi
|
||
done
|
||
done
|
||
|
||
# Проверка опубликованных образов
|
||
echo "🔍 Verifying published images..."
|
||
for image in "${IMAGES[@]}"; do
|
||
echo " • Verifying $image..."
|
||
|
||
# Попытка скачать manifest
|
||
if docker manifest inspect "$image" > /dev/null 2>&1; then
|
||
echo " ✅ Manifest verified for $image"
|
||
else
|
||
echo " ❌ Failed to verify manifest for $image"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
# Создание release notes
|
||
echo "📝 Creating release notes..."
|
||
cat > /tmp/release-notes.md << EOF
|
||
# Release $VERSION
|
||
|
||
## 🚀 What's New
|
||
|
||
### Features
|
||
- Updated to version $VERSION
|
||
- Production-ready Docker images
|
||
- Enhanced security configurations
|
||
- Performance optimizations
|
||
|
||
### Technical Details
|
||
- **Backend Image**: \`$REGISTRY/$PROJECT_NAME-backend:$VERSION\`
|
||
- **Frontend Image**: \`$REGISTRY/$PROJECT_NAME-frontend:$VERSION\`
|
||
- **Build Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||
- **Git Commit**: ${DRONE_COMMIT_SHA:-$(git rev-parse HEAD)}
|
||
|
||
### Docker Images
|
||
\`\`\`bash
|
||
# Pull latest images
|
||
docker pull $REGISTRY/$PROJECT_NAME-backend:$VERSION
|
||
docker pull $REGISTRY/$PROJECT_NAME-frontend:$VERSION
|
||
|
||
# Or use latest tags
|
||
docker pull $REGISTRY/$PROJECT_NAME-backend:latest
|
||
docker pull $REGISTRY/$PROJECT_NAME-frontend:latest
|
||
\`\`\`
|
||
|
||
### Quick Start
|
||
\`\`\`bash
|
||
# Download and run with docker-compose
|
||
curl -sSL https://raw.githubusercontent.com/smartsoltech/links/main/docker-compose.production.yml -o docker-compose.yml
|
||
docker-compose up -d
|
||
\`\`\`
|
||
|
||
### Migration Notes
|
||
- No breaking changes in this release
|
||
- Database migrations included
|
||
- Backward compatible
|
||
|
||
## 📊 Image Information
|
||
|
||
| Component | Image | Size | Layers |
|
||
|-----------|-------|------|--------|
|
||
| Backend | \`$PROJECT_NAME-backend:$VERSION\` | $(docker images --format "{{.Size}}" "$REGISTRY/$PROJECT_NAME-backend:$VERSION" 2>/dev/null || echo "N/A") | $(docker history "$REGISTRY/$PROJECT_NAME-backend:$VERSION" 2>/dev/null | wc -l || echo "N/A") |
|
||
| Frontend | \`$PROJECT_NAME-frontend:$VERSION\` | $(docker images --format "{{.Size}}" "$REGISTRY/$PROJECT_NAME-frontend:$VERSION" 2>/dev/null || echo "N/A") | $(docker history "$REGISTRY/$PROJECT_NAME-frontend:$VERSION" 2>/dev/null | wc -l || echo "N/A") |
|
||
|
||
## 🔐 Security
|
||
|
||
All images are scanned for vulnerabilities and follow security best practices:
|
||
- Non-root user execution
|
||
- Minimal base images
|
||
- Regular security updates
|
||
- Dependency vulnerability scanning
|
||
|
||
## 📖 Documentation
|
||
|
||
- [Installation Guide](./docs/INSTALLATION.md)
|
||
- [Configuration Guide](./docs/CONFIGURATION.md)
|
||
- [API Documentation](./docs/API.md)
|
||
- [Makefile Commands](./docs/MAKEFILE.md)
|
||
|
||
---
|
||
|
||
**Full Changelog**: https://github.com/smartsoltech/links/compare/previous...${DRONE_TAG:-$VERSION}
|
||
EOF
|
||
|
||
# Уведомления о публикации
|
||
echo "📢 Sending publication notifications..."
|
||
|
||
# Slack уведомление (если настроено)
|
||
if [ -n "$SLACK_WEBHOOK_URL" ]; then
|
||
curl -X POST -H 'Content-type: application/json' \
|
||
--data "{
|
||
\"text\": \"🚀 *CatLink $VERSION* published successfully!\",
|
||
\"attachments\": [
|
||
{
|
||
\"color\": \"good\",
|
||
\"fields\": [
|
||
{
|
||
\"title\": \"Backend Image\",
|
||
\"value\": \"\`$REGISTRY/$PROJECT_NAME-backend:$VERSION\`\",
|
||
\"short\": true
|
||
},
|
||
{
|
||
\"title\": \"Frontend Image\",
|
||
\"value\": \"\`$REGISTRY/$PROJECT_NAME-frontend:$VERSION\`\",
|
||
\"short\": true
|
||
},
|
||
{
|
||
\"title\": \"Registry\",
|
||
\"value\": \"\`$REGISTRY\`\",
|
||
\"short\": true
|
||
},
|
||
{
|
||
\"title\": \"Build\",
|
||
\"value\": \"#${DRONE_BUILD_NUMBER:-$(date +%s)}\",
|
||
\"short\": true
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}" \
|
||
"$SLACK_WEBHOOK_URL" || echo "Failed to send Slack notification"
|
||
fi
|
||
|
||
# Discord уведомление (если настроено)
|
||
if [ -n "$DISCORD_WEBHOOK_URL" ]; then
|
||
curl -H "Content-Type: application/json" \
|
||
-d "{
|
||
\"embeds\": [
|
||
{
|
||
\"title\": \"🚀 CatLink $VERSION Published\",
|
||
\"color\": 65280,
|
||
\"fields\": [
|
||
{
|
||
\"name\": \"Backend Image\",
|
||
\"value\": \"\`$REGISTRY/$PROJECT_NAME-backend:$VERSION\`\",
|
||
\"inline\": true
|
||
},
|
||
{
|
||
\"name\": \"Frontend Image\",
|
||
\"value\": \"\`$REGISTRY/$PROJECT_NAME-frontend:$VERSION\`\",
|
||
\"inline\": true
|
||
},
|
||
{
|
||
\"name\": \"Registry\",
|
||
\"value\": \"\`$REGISTRY\`\",
|
||
\"inline\": true
|
||
}
|
||
],
|
||
\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
|
||
}
|
||
]
|
||
}" \
|
||
"$DISCORD_WEBHOOK_URL" || echo "Failed to send Discord notification"
|
||
fi
|
||
|
||
# Создание статистики публикации
|
||
echo "📊 Creating publication statistics..."
|
||
cat > /tmp/publish-stats.json << EOF
|
||
{
|
||
"version": "$VERSION",
|
||
"registry": "$REGISTRY",
|
||
"project": "$PROJECT_NAME",
|
||
"images": [
|
||
{
|
||
"name": "$PROJECT_NAME-backend",
|
||
"tag": "$VERSION",
|
||
"size": "$(docker images --format "{{.Size}}" "$REGISTRY/$PROJECT_NAME-backend:$VERSION" 2>/dev/null || echo "unknown")",
|
||
"published_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||
},
|
||
{
|
||
"name": "$PROJECT_NAME-frontend",
|
||
"tag": "$VERSION",
|
||
"size": "$(docker images --format "{{.Size}}" "$REGISTRY/$PROJECT_NAME-frontend:$VERSION" 2>/dev/null || echo "unknown")",
|
||
"published_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||
}
|
||
],
|
||
"build_info": {
|
||
"build_number": "${DRONE_BUILD_NUMBER:-unknown}",
|
||
"commit_sha": "${DRONE_COMMIT_SHA:-$(git rev-parse HEAD 2>/dev/null || echo "unknown")}",
|
||
"build_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||
"branch": "${DRONE_BRANCH:-$(git branch --show-current 2>/dev/null || echo "unknown")}"
|
||
}
|
||
}
|
||
EOF
|
||
|
||
# Очистка временных файлов
|
||
echo "🧹 Cleaning up..."
|
||
docker system prune -f > /dev/null 2>&1 || true
|
||
|
||
# Выход из registry
|
||
docker logout "$REGISTRY" > /dev/null 2>&1 || true
|
||
|
||
echo "✅ Publication completed successfully!"
|
||
echo ""
|
||
echo "📦 Published Images:"
|
||
echo " 🔗 Backend: $REGISTRY/$PROJECT_NAME-backend:$VERSION"
|
||
echo " 🔗 Frontend: $REGISTRY/$PROJECT_NAME-frontend:$VERSION"
|
||
echo ""
|
||
echo "📄 Release notes: /tmp/release-notes.md"
|
||
echo "📊 Statistics: /tmp/publish-stats.json"
|
||
echo ""
|
||
echo "🚀 Ready for deployment!" |