Skip to content

Docker image tag fails with uppercase repository name - requires lowercase conversion #10

Description

@Patechoc

Description:

Problem
When using the workflow template to build and push Docker images, the build fails with the error:

Root Cause
The GitHub Actions workflow uses ${{ github.repository }} directly in Docker image tags. However, Docker registry conventions require repository names to be lowercase. When a GitHub username contains uppercase letters (e.g., "Patechoc"), this causes the build to fail.

Solution
The workflow should NOT convert the repository name to lowercase before building the Docker image, but only the full path/URL to the image artifact.

Use this as example:

# filename: templates/python-basic-webserver/.github/workflows/urbalurba-build-and-push.yaml
# 
# GitHub Actions workflow for building and pushing Docker images with unique tags
# and updating Kubernetes manifests for GitOps with ArgoCD
#
# This workflow solves the problem of ArgoCD not detecting new image builds
# when using the same image tag (like "latest"). Instead, it:
#
# 1. Generates a unique tag using commit SHA and timestamp
# 2. Builds and pushes the image with this unique tag 
# 3. Updates the Kubernetes manifest with the new tag
# 4. Commits the updated manifest back to the repository
#
# The workflow includes safeguards to prevent infinite build loops:
# - Ignores changes to files in the manifests/ directory 
# - Adds [ci-skip] to commit messages for automated changes
# - Checks if the commit was made by GitHub Actions
#
# REQUIREMENTS:
# - Repository needs write permissions for GitHub token (for pushing changes back)
# - Kubernetes manifests must be in a "manifests" directory with deployment.yaml
# - Image reference in deployment.yaml should follow the pattern:
#   image: ghcr.io/username/repo-name:tag

name: Build and Push
on:
  push:
    branches: [main]
    paths-ignore:
      - 'manifests/**'  # Ignore changes to manifest files to prevent workflow loops

permissions:
  contents: write  # Needed for pushing manifest changes back to repository
  packages: write  # Needed for pushing to GitHub Container Registry

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}  # Use token for pushing changes
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'  # Using Python 3.11
      
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
      
      - name: Generate unique tag
        id: tag
        run: |
          # Create a unique tag using commit SHA and timestamp
          # This ensures each build has a unique, traceable identifier
          TIMESTAMP=$(date +%Y%m%d%H%M%S)
          echo "IMAGE_TAG=${GITHUB_SHA::7}-${TIMESTAMP}" >> $GITHUB_ENV
      
      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
          
      - name: Extract GitHub username and repository name
        run: |
          # Extract username and repo name from the full repository name
          # This is used for correctly formatting the image reference
          REPO_FULL_NAME="${{ github.repository }}"
          echo "GITHUB_USERNAME=$(echo $REPO_FULL_NAME | cut -d'/' -f1)" >> $GITHUB_ENV
          echo "REPO_NAME=$(echo $REPO_FULL_NAME | cut -d'/' -f2)" >> $GITHUB_ENV
          # Lowercase version for Docker image URL (Docker requires lowercase)
          echo "DOCKER_IMAGE_URL=$(echo $REPO_FULL_NAME | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
      
      - name: Build and push Docker image
        run: |
          # Build and push with the unique tag
          echo "Building and pushing image with tag: ${{ env.IMAGE_TAG }}"
          docker build -t ghcr.io/${{ env.DOCKER_IMAGE_URL }}:${{ env.IMAGE_TAG }} .
          docker push ghcr.io/${{ env.DOCKER_IMAGE_URL }}:${{ env.IMAGE_TAG }}
          
          # Also update latest tag for reference
          echo "Updating latest tag to point to the new image"
          docker tag ghcr.io/${{ env.DOCKER_IMAGE_URL }}:${{ env.IMAGE_TAG }} ghcr.io/${{ env.DOCKER_IMAGE_URL }}:latest
          docker push ghcr.io/${{ env.DOCKER_IMAGE_URL }}:latest
      
      - name: Update Kubernetes manifest
        run: |
          # Skip this step if this is already an automated commit
          # This prevents infinite loops of workflow runs
          if [ "$(git log -1 --pretty=format:'%an')" = "GitHub Actions" ]; then
            echo "Skipping manifest update as this is an automated commit"
            exit 0
          fi
          
          echo "Updating deployment.yaml with new image tag: ${{ env.IMAGE_TAG }}"
          # Update the image tag in the deployment manifest (using lowercase image URL for Docker)
          sed -i "s|image: ghcr.io/.*:.*|image: ghcr.io/${{ env.DOCKER_IMAGE_URL }}:${{ env.IMAGE_TAG }}|" manifests/deployment.yaml
          
          # Configure Git for the commit
          git config --global user.name "GitHub Actions"
          git config --global user.email "github-actions@github.com"
          
          # Commit and push the changes with a skip tag to prevent loops
          git add manifests/deployment.yaml
          git commit -m "[ci-skip] Update deployment image to ${{ env.IMAGE_TAG }}"
          
          echo "Pushing updated manifest to repository"
          git push

Use the lowercase version in Docker commands:
Impact
This affects any repository where the owner's GitHub username contains uppercase letters, making the template incompatible with those accounts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions