[IMPORT] Ubuntu #7
This file contains 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: Process Image Import Request | |
on: | |
issues: | |
types: [opened, edited, labeled] | |
jobs: | |
process-import-request: | |
if: contains(github.event.issue.labels.*.name, 'import-request') | |
runs-on: ubuntu-latest | |
permissions: | |
issues: write | |
contents: read | |
packages: write | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Extract issue body | |
id: extract_data | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const issue = context.payload.issue | |
const body = issue.body | |
// Parse the form data | |
const sourceMatch = body.match(/### Image Source\s*\n\s*(.*)/); | |
const repoMatch = body.match(/### Repository Name\s*\n\s*(.*)/); | |
const imageMatch = body.match(/### Image Name\s*\n\s*(.*)/); | |
const versionMatch = body.match(/### Image Version\/Tag\s*\n\s*(.*)/); | |
const useLatestMatch = body.match(/- \[(?:x|X)\] Import the latest version of this image/); | |
const isOfficialMatch = body.match(/- \[(?:x|X)\] This is an official Docker Hub image/); | |
const source = sourceMatch ? sourceMatch[1].trim() : null; | |
const repo = repoMatch ? repoMatch[1].trim() : null; | |
const image = imageMatch ? imageMatch[1].trim() : null; | |
const version = versionMatch ? versionMatch[1].trim() : null; | |
const useLatest = Boolean(useLatestMatch); | |
const isOfficial = Boolean(isOfficialMatch); | |
const imageTag = useLatest || !version ? 'latest' : version; | |
if (!source || !image) { | |
await github.rest.issues.createComment({ | |
issue_number: issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: '⚠️ Error: Missing required information. Please make sure to provide source and image name.' | |
}); | |
return core.setFailed('Missing required information'); | |
} | |
// For non-official images, repository is required | |
if (!isOfficial && !repo) { | |
await github.rest.issues.createComment({ | |
issue_number: issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: '⚠️ Error: Repository name is required for non-official images. If this is an official image, please check the "This is an official Docker Hub image" option.' | |
}); | |
return core.setFailed('Missing repository name for non-official image'); | |
} | |
core.setOutput('source', source); | |
core.setOutput('repo', repo || 'library'); // For official images, use 'library' as repository | |
core.setOutput('image', image); | |
core.setOutput('version', imageTag); | |
core.setOutput('isOfficial', isOfficial); | |
core.setOutput('useLatest', useLatest.toString()); | |
// Format the source image string based on whether it's an official image or not | |
const sourceImageDisplay = isOfficial ? `${image}:${imageTag}` : `${repo}/${image}:${imageTag}`; | |
// Add comment about processing | |
await github.rest.issues.createComment({ | |
issue_number: issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: `## 🔄 Processing Import Request | |
Processing request to import \`${sourceImageDisplay}\` from ${source}. | |
- **Source**: ${source} | |
- **Image**: ${sourceImageDisplay} | |
- **Type**: ${isOfficial ? 'Official Image' : 'Repository Image'} | |
- **Version**: ${imageTag} | |
Starting import process. Please wait...` | |
}); | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
# - name: Login to DockerHub | |
# uses: docker/login-action@v3 | |
# with: | |
# username: ${{ secrets.DOCKERHUB_USERNAME }} | |
# password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Pull and push image | |
id: docker_pull_push | |
env: | |
SOURCE_REPO: ${{ steps.extract_data.outputs.repo }} | |
IMAGE_NAME: ${{ steps.extract_data.outputs.image }} | |
IMAGE_VERSION: ${{ steps.extract_data.outputs.version }} | |
IS_OFFICIAL: ${{ steps.extract_data.outputs.isOfficial }} | |
USE_LATEST: ${{ steps.extract_data.outputs.useLatest }} | |
run: | | |
echo "::group::Import Process Details" | |
# Handle official images vs repository images | |
if [[ "$IS_OFFICIAL" == "true" ]]; then | |
SOURCE_IMAGE="${IMAGE_NAME}:${IMAGE_VERSION}" | |
else | |
SOURCE_IMAGE="${SOURCE_REPO}/${IMAGE_NAME}:${IMAGE_VERSION}" | |
fi | |
TARGET_IMAGE="ghcr.io/${{ github.repository_owner }}/dockerhub-${IMAGE_NAME}:${IMAGE_VERSION}" | |
echo "Source Image: ${SOURCE_IMAGE}" | |
echo "Target Image: ${TARGET_IMAGE}" | |
# Check if target image already exists | |
if docker manifest inspect "${TARGET_IMAGE}" > /dev/null 2>&1; then | |
echo "Target image already exists in GitHub Packages" | |
# If it's a 'latest' image, we should update it even if it exists | |
if [[ "$IMAGE_VERSION" == "latest" || "$USE_LATEST" == "true" ]]; then | |
echo "This is a 'latest' image request - updating the existing image" | |
echo "image_exists=true" >> $GITHUB_OUTPUT | |
echo "update_latest=true" >> $GITHUB_OUTPUT | |
echo "target_image=${TARGET_IMAGE}" >> $GITHUB_OUTPUT | |
# Get old digest before updating | |
OLD_TARGET_DIGEST=$(docker pull "${TARGET_IMAGE}" > /dev/null && docker inspect --format='{{index .RepoDigests 0}}' "${TARGET_IMAGE}" | cut -d '@' -f 2) | |
echo "old_target_digest=${OLD_TARGET_DIGEST}" >> $GITHUB_OUTPUT | |
# Proceed with the update process - force pull the latest | |
echo "Pulling latest ${SOURCE_IMAGE}..." | |
docker pull --no-cache "${SOURCE_IMAGE}" | |
else | |
# For non-latest images, we just mark as duplicate and exit | |
echo "::warning::Image ${TARGET_IMAGE} already exists in GitHub Packages" | |
echo "image_exists=true" >> $GITHUB_OUTPUT | |
echo "update_latest=false" >> $GITHUB_OUTPUT | |
echo "target_image=${TARGET_IMAGE}" >> $GITHUB_OUTPUT | |
exit 0 | |
fi | |
else | |
# Image doesn't exist yet | |
echo "image_exists=false" >> $GITHUB_OUTPUT | |
echo "update_latest=false" >> $GITHUB_OUTPUT | |
# Pull source image | |
echo "Pulling ${SOURCE_IMAGE}..." | |
docker pull "${SOURCE_IMAGE}" | |
fi | |
# Get image digest | |
SOURCE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "${SOURCE_IMAGE}" | cut -d '@' -f 2) | |
echo "Source Image Digest: ${SOURCE_DIGEST}" | |
echo "source_digest=${SOURCE_DIGEST}" >> $GITHUB_OUTPUT | |
# Tag image for GitHub Packages | |
docker tag "${SOURCE_IMAGE}" "${TARGET_IMAGE}" | |
# Push to GitHub Packages | |
echo "Pushing to GitHub Packages as ${TARGET_IMAGE}..." | |
docker push "${TARGET_IMAGE}" | |
# Get target image digest | |
TARGET_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "${TARGET_IMAGE}" | cut -d '@' -f 2) | |
echo "Target Image Digest: ${TARGET_DIGEST}" | |
echo "target_image=${TARGET_IMAGE}" >> $GITHUB_OUTPUT | |
echo "target_digest=${TARGET_DIGEST}" >> $GITHUB_OUTPUT | |
echo "::endgroup::" | |
- name: Update issue with results | |
uses: actions/github-script@v6 | |
env: | |
IMAGE_EXISTS: ${{ steps.docker_pull_push.outputs.image_exists }} | |
UPDATE_LATEST: ${{ steps.docker_pull_push.outputs.update_latest }} | |
TARGET_IMAGE: ${{ steps.docker_pull_push.outputs.target_image }} | |
SOURCE_DIGEST: ${{ steps.docker_pull_push.outputs.source_digest }} | |
TARGET_DIGEST: ${{ steps.docker_pull_push.outputs.target_digest }} | |
OLD_TARGET_DIGEST: ${{ steps.docker_pull_push.outputs.old_target_digest }} | |
with: | |
script: | | |
const imageExists = process.env.IMAGE_EXISTS === 'true'; | |
const updateLatest = process.env.UPDATE_LATEST === 'true'; | |
const targetImage = process.env.TARGET_IMAGE; | |
const sourceDigest = process.env.SOURCE_DIGEST; | |
const targetDigest = process.env.TARGET_DIGEST; | |
const oldTargetDigest = process.env.OLD_TARGET_DIGEST; | |
const workflowRunUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
let commentBody = ''; | |
let labels = []; | |
if (imageExists && !updateLatest) { | |
// Regular duplicate image case - no update needed | |
commentBody = `## ℹ️ Image Already Exists | |
The requested image already exists in GitHub Packages. | |
- **Image**: \`${targetImage}\` | |
- **Workflow Run**: [View Logs](${workflowRunUrl}) | |
You can use this image in your workflows or deployments.`; | |
labels = ['import-request', 'duplicate', 'resolved']; | |
} else if (imageExists && updateLatest) { | |
// Latest image was updated | |
commentBody = `## 🔄 Latest Image Updated | |
Successfully updated the latest image in GitHub Packages. | |
- **Image**: \`${targetImage}\` | |
- **Previous Digest**: \`${oldTargetDigest}\` | |
- **Source Digest**: \`${sourceDigest}\` | |
- **New Target Digest**: \`${targetDigest}\` | |
- **Workflow Run**: [View Logs](${workflowRunUrl}) | |
- **Update Timestamp**: ${new Date().toISOString()} | |
- **Updated by**: @${context.actor} | |
You can now use this updated image in your workflows or deployments.`; | |
labels = ['import-request', 'updated-latest', 'resolved']; | |
} else { | |
// New image was imported | |
commentBody = `## ✅ Import Complete | |
Successfully imported the image to GitHub Packages. | |
- **Image**: \`${targetImage}\` | |
- **Source Digest**: \`${sourceDigest}\` | |
- **Target Digest**: \`${targetDigest}\` | |
- **Workflow Run**: [View Logs](${workflowRunUrl}) | |
- **Import Timestamp**: ${new Date().toISOString()} | |
- **Imported by**: @${context.actor} | |
You can now use this image in your workflows or deployments.`; | |
labels = ['import-request', 'imported', 'resolved']; | |
} | |
await github.rest.issues.createComment({ | |
issue_number: context.payload.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: commentBody | |
}); | |
// Close the issue with appropriate labels | |
await github.rest.issues.update({ | |
issue_number: context.payload.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
state: 'closed', | |
labels: labels | |
}); |