kugiri 0.2.3

Marker-based block editing CLI
Documentation
name: 'Smart Commit with Trailer Detection'
description: 'Creates or replaces commits based on git trailer detection'
inputs:
  commit_message:
    description: 'Commit message (can be multiline)'
    required: true
  trailer_id:
    description: 'Unique identifier for the trailer (e.g., changelog-update)'
    required: true
  branch:
    description: 'Target branch'
    required: true
  files:
    description: 'Files to commit (newline-separated). If empty, commits all changes'
    required: false
    default: ''
  github_token:
    description: 'GitHub token for API operations'
    required: false
    default: ${{ github.token }}

runs:
  using: 'composite'
  steps:
    - name: Check for changes
      id: check-changes
      shell: bash
      env:
        FILES: ${{ inputs.files }}
      run: |
        # Check if files input is empty - if so, check all changes
        if [ -z "$FILES" ] || [ "$FILES" = "" ]; then
          echo "No files specified, checking all changes"
          # Check if there are any changes at all
          if git diff --quiet HEAD && git diff --cached --quiet HEAD; then
            echo "No changes detected"
            echo "has_changes=false" >> $GITHUB_OUTPUT
          else
            echo "Changes detected"
            echo "has_changes=true" >> $GITHUB_OUTPUT
          fi
        else
          # Convert newline-separated files to space-separated for git diff
          FILES_LIST=$(echo "$FILES" | tr '\n' ' ' | sed 's/[[:space:]]*$//')

          # Check if files list is empty after processing
          if [ -z "$FILES_LIST" ]; then
            echo "No valid files specified after processing, checking all changes"
            if git diff --quiet HEAD && git diff --cached --quiet HEAD; then
              echo "No changes detected"
              echo "has_changes=false" >> $GITHUB_OUTPUT
            else
              echo "Changes detected"
              echo "has_changes=true" >> $GITHUB_OUTPUT
            fi
          else
            # Check if there are any changes in the specified files
            if git diff --quiet HEAD -- $FILES_LIST && git diff --cached --quiet HEAD -- $FILES_LIST; then
              echo "No changes detected in specified files"
              echo "has_changes=false" >> $GITHUB_OUTPUT
            else
              echo "Changes detected in specified files"
              echo "has_changes=true" >> $GITHUB_OUTPUT
            fi
          fi
        fi

    - name: Check if HEAD has matching trailer
      if: steps.check-changes.outputs.has_changes == 'true'
      id: check-trailer
      shell: bash
      env:
        TRAILER_ID: ${{ inputs.trailer_id }}
      run: |
        # Check if HEAD commit has our trailer using git interpret-trailers
        COMMIT_MSG=$(git log -1 --format=%B)
        TRAILER_VALUE=$(echo "$COMMIT_MSG" | git interpret-trailers --parse | grep "^X-Smart-Commit-ID:" | cut -d' ' -f2- || true)

        if [ "$TRAILER_VALUE" = "$TRAILER_ID" ]; then
          echo "HEAD has matching trailer (X-Smart-Commit-ID: $TRAILER_ID)"
          echo "should_reset=true" >> $GITHUB_OUTPUT
          # Store parent SHA for later use
          PARENT_SHA=$(git rev-parse HEAD~1)
          echo "parent_sha=$PARENT_SHA" >> $GITHUB_OUTPUT
        else
          echo "HEAD does not have matching trailer"
          echo "should_reset=false" >> $GITHUB_OUTPUT
        fi

    - name: Reset to parent if needed
      if: steps.check-changes.outputs.has_changes == 'true' && steps.check-trailer.outputs.should_reset == 'true'
      shell: bash
      env:
        GITHUB_TOKEN: ${{ inputs.github_token }}
        BRANCH: ${{ inputs.branch }}
        PARENT_SHA: ${{ steps.check-trailer.outputs.parent_sha }}
      run: |
        echo "Resetting branch to parent commit: $PARENT_SHA"

        # Use GitHub API to update the branch reference to parent
        curl -X PATCH \
          -H "Authorization: token $GITHUB_TOKEN" \
          -H "Accept: application/vnd.github.v3+json" \
          "https://api.github.com/repos/${{ github.repository }}/git/refs/heads/$BRANCH" \
          -d "{\"sha\":\"$PARENT_SHA\",\"force\":true}"

    - name: Create commit with trailer
      if: steps.check-changes.outputs.has_changes == 'true'
      shell: bash
      env:
        GITHUB_TOKEN: ${{ inputs.github_token }}
        BRANCH: ${{ inputs.branch }}
        FILES: ${{ inputs.files }}
        COMMIT_MESSAGE: ${{ inputs.commit_message }}
        TRAILER_ID: ${{ inputs.trailer_id }}
      run: |
        # Create commit message with trailer
        FULL_MESSAGE="${COMMIT_MESSAGE}

        X-Smart-Commit-ID: ${TRAILER_ID}"

        # Get the script path relative to the repository root
        SCRIPT_PATH="${GITHUB_WORKSPACE}/scripts/run-ghcp.sh"

        # Check if files input is empty - if so, commit all changes
        if [ -z "$FILES" ] || [ "$FILES" = "" ]; then
          echo "Committing all changes"
          # Get all modified and new files
          ALL_FILES=$(git diff --name-only HEAD; git diff --cached --name-only HEAD; git ls-files --others --exclude-standard)
          ALL_FILES=$(echo "$ALL_FILES" | sort -u | tr '\n' ' ')

          if [ -z "$ALL_FILES" ]; then
            echo "Error: No files to commit"
            exit 1
          fi

          # Commit using ghcp with all changed files
          "$SCRIPT_PATH" -- commit \
            -r "${{ github.repository }}" \
            -b "$BRANCH" \
            -m "$FULL_MESSAGE" \
            $ALL_FILES
        else
          # Convert newline-separated files to space-separated
          FILES_LIST=$(echo "$FILES" | tr '\n' ' ' | sed 's/[[:space:]]*$//')

          if [ -z "$FILES_LIST" ]; then
            echo "Error: Files list is empty after processing"
            exit 1
          fi

          # Commit using ghcp with specified files
          "$SCRIPT_PATH" -- commit \
            -r "${{ github.repository }}" \
            -b "$BRANCH" \
            -m "$FULL_MESSAGE" \
            $FILES_LIST
        fi

    - name: Sync local git state with remote
      if: steps.check-changes.outputs.has_changes == 'true'
      shell: bash
      env:
        BRANCH: ${{ inputs.branch }}
      run: |
        echo "Syncing local git state with remote branch: $BRANCH"
        # Fetch the latest state of the branch
        git fetch origin "$BRANCH"

        # Reset the current branch to match remote
        # This updates HEAD and the index without touching the working tree
        git reset "origin/$BRANCH"

        # Clean up the index to match HEAD (discard staged changes)
        git reset --mixed HEAD