0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CircleCIで特定のファイルが変更された時のみstepを継続させたい時に使うcommand

Last updated at Posted at 2025-05-02

CircleCIで特定の拡張子のファイル(今回は .go)のみ変更されていた場合にのみjobのstepsを継続させたい
ケースに対応させるためのcommand
動かすのに時間溶かしたのでメモとして残しておきます

Dynamic Configurationを利用した例は見かけましたが
https://qiita.com/hatai/items/76ade5b81a0b2076263c

以下の都合でjob自体は動かしたかったのと既存のCIにサクッと組み込みたかったのでcommandsで実装しました

  • プロダクションコード変更されていないのにLintやtestを動かしたくない
  • GitHubのbranch protectionの都合job自体はskip動作で動かしたい

commands部分の実装

  check_go_changes_in_pr_and_halt:
    description: "Uses GitHub REST API (curl+jq) to find PR target branch, fetches history, checks for *.go changes against base branch, and halts if none found. Requires checkout and GITHUB_TOKEN."
    parameters:
      github-token:
        type: env_var_name
        default: GITHUB_TOKEN
    steps:
      - run:
          name: Determine Target Branch via REST API, Fetch, Check Go Changes
          command: |
            # --- 1. Check Context and Required Env Vars ---
            if [ -z "$CIRCLE_PULL_REQUEST" ]; then
              echo "Not a Pull Request context. Proceeding."
              exit 0
            fi

            if [ -z "${<< parameters.github-token >>}" ]; then
              echo "Error: github-token parameters is not set. Required for GitHub REST API call."
              exit 1 # Configuration error, fail fast
            fi

            # --- 2. Parse PR Info ---
            PR_NUMBER=$(basename "$CIRCLE_PULL_REQUEST")
            if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
                echo "Error: Could not parse PR number from CIRCLE_PULL_REQUEST: $CIRCLE_PULL_REQUEST"
                exit 0 # Proceed safely
            fi

            # Use CircleCI env vars for owner/repo
            OWNER="$CIRCLE_PROJECT_USERNAME"
            REPO="$CIRCLE_PROJECT_REPONAME"
            if [ -z "$OWNER" ] || [ -z "$REPO" ]; then
                echo "Error: Could not determine repository owner/name from CircleCI env vars (CIRCLE_PROJECT_USERNAME, CIRCLE_PROJECT_REPONAME)."
                exit 0 # Proceed safely
            fi
            echo "Detected PR: $OWNER/$REPO #$PR_NUMBER"

            # --- 3. Call GitHub REST API determined Target Branch ---
            API_URL="https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_NUMBER"
            echo "Querying GitHub REST API: $API_URL"

            # Use curl to get PR details, jq to extract base.ref
            # -sS: Silent but show errors. -f: Fail fast on HTTP errors (>=400). -L: Follow redirects.
            if ! HTTP_RESPONSE=$(curl -sSLf \
                                 -H "Authorization: Bearer ${<< parameters.github-token >>}" \
                                 -H "Accept: application/vnd.github.v3+json" \
                                 "$API_URL"); then
                echo "Error: Failed to fetch PR details from GitHub API."
                echo "Check API URL, token permissions (needs 'repo' scope for private repos), and network."
                # Don't echo potentially sensitive response here if curl failed entirely
                echo "Proceeding with job steps as a safety measure."
                exit 0 # Exit script successfully to proceed safely
            fi

            # Parse the JSON response to get the target branch name
            TARGET_BRANCH=$(echo "$HTTP_RESPONSE" | jq -r '.base.ref')

            # Check if jq successfully extracted a non-null, non-empty value
            if [ -z "$TARGET_BRANCH" ] || [ "$TARGET_BRANCH" == "null" ]; then
                echo "Error: Could not parse target branch (.base.ref) from API response."
                # Consider logging $HTTP_RESPONSE only if necessary for debugging, might contain sensitive info
                # echo "API Response: $HTTP_RESPONSE"
                echo "Proceeding with job steps as a safety measure."
                exit 0 # Exit script successfully to proceed safely
            fi
            echo "Successfully determined Target Branch via REST API: $TARGET_BRANCH"

            # --- 4. Perform git diff ---
            echo "Checking for *.go file changes against base branch."
            echo "git diff --name-only --no-prefix origin/$TARGET_BRANCH $CIRCLE_BRANCH"
            if ! git diff --name-only --no-prefix origin/$TARGET_BRANCH $CIRCLE_BRANCH > changed_files.list; then
               echo "Error: 'git diff \"origin/$TARGET_BRANCH\" \"$CIRCLE_BRANCH\"' command failed (Base branch likely not found)."
               rm -f changed_files.list
               exit 0 # Proceed safely
            fi

            # --- 5. Check diff output ---
            echo "Checking for *.go file changes in diff output..."
            if ! grep -q '\.go$' changed_files.list; then
              echo "No *.go files changed. Halting subsequent steps."
              rm -f changed_files.list
              circleci-agent step halt
            else
              echo "*.go files changed. Proceeding."
              rm -f changed_files.list
              exit 0
            fi

呼び出し部分のstepsの実装

jobs:
  build_and_test:
    docker:
      - image: cimg/go:1.24.2 # Or any other image where you can install curl/jq
    steps:
      - checkout

      # Call the command
      - check_go_changes_in_pr_and_halt

      # Subsequent steps (only run if halt was not called)
      - run:
          name: Build Go Project (if changes detected)
          # ...
      - run:
          name: Test Go Project (if changes detected)
          # ...
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?