diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f681eb3f..c6a56994 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -417,6 +417,27 @@ jobs: echo '${{ toJSON(steps.changed-files-quotepath.outputs) }}' shell: bash + - name: Run changed-files with dir_names and dir_names_max_depth + id: changed-files-dir-names-max-depth + uses: ./ + with: + base_sha: ba788ed + sha: 0a5b7c6 + fetch_depth: 60000 + dir_names: "true" + dir_names_max_depth: 3 + - name: Show output + run: | + echo '${{ toJSON(steps.changed-files-dir-names-max-depth.outputs) }}' + shell: + bash + - name: Check dir_names output + if: "!contains(steps.changed-files-dir-names-max-depth.outputs.all_changed_files, 'test/test2/test3')" + run: | + echo "Invalid output: Expected to include (test/test2/test3) got (${{ steps.changed-files-dir-names-max-depth.outputs.all_changed_files }})" + exit 1 + shell: + bash - name: Run changed-files with dir_names id: changed-files-dir-names uses: ./ diff --git a/action.yml b/action.yml index 160846a6..c5232984 100644 --- a/action.yml +++ b/action.yml @@ -73,6 +73,9 @@ inputs: default: "false" description: "Output unique changed directories instead of filenames. **NOTE:** This returns `.` for changed files located in the root of the project." required: false + dir_names_max_depth: + description: "Maximum depth of directories to output. e.g test/test1/test2 with max depth of 2 returns test/test1" + required: false json: description: "Output list of changed files in a JSON formatted string which can be used for matrix jobs." required: false @@ -221,6 +224,7 @@ runs: INPUT_OLD_NEW_FILES_SEPARATOR: ${{ inputs.old_new_files_separator }} INPUT_DIFF_RELATIVE: ${{ inputs.diff_relative }} INPUT_DIR_NAMES: ${{ inputs.dir_names }} + INPUT_DIR_NAMES_MAX_DEPTH: ${{ inputs.dir_names_max_depth }} INPUT_JSON: ${{ inputs.json }} INPUT_HAS_CUSTOM_PATTERNS: ${{ steps.glob.outputs.has-custom-patterns }} diff --git a/get-changed-paths.sh b/get-changed-paths.sh index 265ac711..746737ca 100755 --- a/get-changed-paths.sh +++ b/get-changed-paths.sh @@ -24,6 +24,31 @@ if [[ -n $INPUT_DIFF_RELATIVE ]]; then git config --global diff.relative "$INPUT_DIFF_RELATIVE" fi +function get_dirname_max_depth() { + while IFS='' read -r line; do + local dir="$line" + local dirs=() + IFS='/' read -ra dirs <<<"$dir" + + local max_depth=${#dirs[@]} + local input_dir_names_max_depth="${INPUT_DIR_NAMES_MAX_DEPTH:-$max_depth}" + + if [[ -n "$input_dir_names_max_depth" && "$input_dir_names_max_depth" -lt "$max_depth" ]]; then + max_depth="$input_dir_names_max_depth" + fi + + local output="${dirs[0]}" + local depth="1" + + while [ "$depth" -lt "$max_depth" ]; do + output="$output/${dirs[${depth}]}" + depth=$((depth + 1)) + done + + echo "$output" + done < <(uniq) +} + function get_diff() { local base="$1" local sha="$2" @@ -43,17 +68,17 @@ function get_diff() { fi if [ -n "$sub_commit_cur" ]; then - ( - cd "$sub" && ( - # the strange magic number is a hardcoded "empty tree" commit sha - get_diff "${sub_commit_pre:-4b825dc642cb6eb9a060e54bf8d69288fbee4904}" "${sub_commit_cur}" "$filter" | awk -v r="$sub" '{ print "" r "/" $0}' + ( + cd "$sub" && ( + # the strange magic number is a hardcoded "empty tree" commit sha + get_diff "${sub_commit_pre:-4b825dc642cb6eb9a060e54bf8d69288fbee4904}" "${sub_commit_cur}" "$filter" | awk -v r="$sub" '{ print "" r "/" $0}' + ) ) - ) fi done < <(git submodule | awk '{print $2}') if [[ "$INPUT_DIR_NAMES" == "true" ]]; then - git diff --diff-filter="$filter" --name-only --ignore-submodules=all "$base$DIFF$sha" | xargs -I {} dirname {} | uniq && exit_status=$? || exit_status=$? + git diff --diff-filter="$filter" --name-only --ignore-submodules=all "$base$DIFF$sha" | xargs -I {} dirname {} | get_dirname_max_depth | uniq && exit_status=$? || exit_status=$? if [[ $exit_status -ne 0 ]]; then echo "::error::Failed to get changed directories between: $base$DIFF$sha" @@ -80,24 +105,24 @@ function get_renames() { exit 1 fi - sub_commit_cur="$(git diff "$base$DIFF$sha" -- "$sub" | { grep '^[+]Subproject commit' || true; } | awk '{print $3}')" && exit_status=$? || exit_status=$? + sub_commit_cur="$(git diff "$base$DIFF$sha" -- "$sub" | { grep '^[+]Subproject commit' || true; } | awk '{print $3}')" && exit_status=$? || exit_status=$? if [[ $exit_status -ne 0 ]]; then echo "::error::Failed to get current commit for submodule ($sub) between: $base$DIFF$sha" exit 1 fi if [ -n "$sub_commit_cur" ]; then - ( - cd "$sub" && ( - # the strange magic number is a hardcoded "empty tree" commit sha - get_renames "${sub_commit_pre:-4b825dc642cb6eb9a060e54bf8d69288fbee4904}" "${sub_commit_cur}" | awk -v r="$sub" '{ print "" r "/" $0}' + ( + cd "$sub" && ( + # the strange magic number is a hardcoded "empty tree" commit sha + get_renames "${sub_commit_pre:-4b825dc642cb6eb9a060e54bf8d69288fbee4904}" "${sub_commit_cur}" | awk -v r="$sub" '{ print "" r "/" $0}' + ) ) - ) fi done < <(git submodule | awk '{print $2}') if [[ "$INPUT_DIR_NAMES" == "true" ]]; then - git log --name-status --ignore-submodules=all "$base" "$sha" | { grep -E "^R" || true; } | awk -F '\t' -v d="$INPUT_OLD_NEW_SEPARATOR" '{print $2d$3}' | xargs -I {} dirname {} | uniq && exit_status=$? || exit_status=$? + git log --name-status --ignore-submodules=all "$base" "$sha" | { grep -E "^R" || true; } | awk -F '\t' -v d="$INPUT_OLD_NEW_SEPARATOR" '{print $2d$3}' | xargs -I {} dirname {} | get_dirname_max_depth | uniq && exit_status=$? || exit_status=$? if [[ $exit_status -ne 0 ]]; then echo "::error::Failed to get renamed directories between: $base → $sha" @@ -145,19 +170,19 @@ if [[ "$INPUT_HAS_CUSTOM_PATTERNS" == "false" ]]; then ALL_OLD_NEW_RENAMED=$(get_renames "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" | awk -v d="$INPUT_OLD_NEW_FILES_SEPARATOR" '{s=(NR==1?s:s d)$0}END{print s}') fi else - ADDED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" A | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - COPIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" C | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - DELETED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" D | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - MODIFIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" M | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - RENAMED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" R | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - TYPE_CHANGED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" T | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - UNMERGED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" U | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - UNKNOWN=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" X | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - ALL_CHANGED_AND_MODIFIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" "*ACDMRTUX" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - ALL_CHANGED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" "ACMR" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) - ALL_MODIFIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" "ACMRD" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + ADDED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" A | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + COPIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" C | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + DELETED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" D | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + MODIFIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" M | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + RENAMED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" R | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + TYPE_CHANGED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" T | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + UNMERGED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" U | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + UNKNOWN=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" X | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + ALL_CHANGED_AND_MODIFIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" "*ACDMRTUX" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + ALL_CHANGED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" "ACMR" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + ALL_MODIFIED=$(get_diff "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" "ACMRD" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) if [[ $INPUT_INCLUDE_ALL_OLD_NEW_RENAMED_FILES == "true" ]]; then - ALL_OLD_NEW_RENAMED=$(get_renames "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}'| jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) + ALL_OLD_NEW_RENAMED=$(get_renames "$INPUT_PREVIOUS_SHA" "$INPUT_CURRENT_SHA" | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}' | jq -R 'split("|") | @json' | sed -r 's/^"|"$//g' | tr -s /) fi fi else @@ -183,13 +208,13 @@ else if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=any_changed::true" else - echo "any_changed=true" >> "$GITHUB_OUTPUT" + echo "any_changed=true" >>"$GITHUB_OUTPUT" fi else if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=any_changed::false" else - echo "any_changed=false" >> "$GITHUB_OUTPUT" + echo "any_changed=false" >>"$GITHUB_OUTPUT" fi fi @@ -197,7 +222,7 @@ else if [[ -n $ALL_OTHER_CHANGED ]]; then if [[ -n "$ALL_CHANGED" ]]; then - OTHER_CHANGED=$(echo "${ALL_OTHER_CHANGED}|${ALL_CHANGED}" | awk '{gsub(/\|/,"\n"); print $0;}' | sort | uniq -u | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}') + OTHER_CHANGED=$(echo "${ALL_OTHER_CHANGED}|${ALL_CHANGED}" | awk '{gsub(/\|/,"\n"); print $0;}' | sort | uniq -u | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}') else OTHER_CHANGED=$ALL_OTHER_CHANGED fi @@ -216,15 +241,15 @@ else echo "::set-output name=only_changed::false" echo "::set-output name=other_changed_files::$OTHER_CHANGED" else - echo "only_changed=false" >> "$GITHUB_OUTPUT" - echo "other_changed_files=$OTHER_CHANGED" >> "$GITHUB_OUTPUT" + echo "only_changed=false" >>"$GITHUB_OUTPUT" + echo "other_changed_files=$OTHER_CHANGED" >>"$GITHUB_OUTPUT" fi elif [[ -n "${ALL_CHANGED}" ]]; then if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=only_changed::true" else - echo "only_changed=true" >> "$GITHUB_OUTPUT" + echo "only_changed=true" >>"$GITHUB_OUTPUT" fi fi @@ -235,13 +260,13 @@ else if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=any_modified::true" else - echo "any_modified=true" >> "$GITHUB_OUTPUT" + echo "any_modified=true" >>"$GITHUB_OUTPUT" fi else if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=any_modified::false" else - echo "any_modified=false" >> "$GITHUB_OUTPUT" + echo "any_modified=false" >>"$GITHUB_OUTPUT" fi fi @@ -249,7 +274,7 @@ else if [[ -n $ALL_OTHER_MODIFIED ]]; then if [[ -n "$ALL_MODIFIED" ]]; then - OTHER_MODIFIED=$(echo "${ALL_OTHER_MODIFIED}|${ALL_MODIFIED}" | awk '{gsub(/\|/,"\n"); print $0;}' | sort | uniq -u | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}') + OTHER_MODIFIED=$(echo "${ALL_OTHER_MODIFIED}|${ALL_MODIFIED}" | awk '{gsub(/\|/,"\n"); print $0;}' | sort | uniq -u | awk -v d="|" '{s=(NR==1?s:s d)$0}END{print s}') else OTHER_MODIFIED=$ALL_OTHER_MODIFIED fi @@ -268,14 +293,14 @@ else echo "::set-output name=only_modified::false" echo "::set-output name=other_modified_files::$OTHER_MODIFIED" else - echo "only_modified=false" >> "$GITHUB_OUTPUT" - echo "other_modified_files=$OTHER_MODIFIED" >> "$GITHUB_OUTPUT" + echo "only_modified=false" >>"$GITHUB_OUTPUT" + echo "other_modified_files=$OTHER_MODIFIED" >>"$GITHUB_OUTPUT" fi elif [[ -n "${ALL_MODIFIED}" ]]; then if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=only_modified::true" else - echo "only_modified=true" >> "$GITHUB_OUTPUT" + echo "only_modified=true" >>"$GITHUB_OUTPUT" fi fi @@ -286,13 +311,13 @@ else if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=any_deleted::true" else - echo "any_deleted=true" >> "$GITHUB_OUTPUT" + echo "any_deleted=true" >>"$GITHUB_OUTPUT" fi else if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=any_deleted::false" else - echo "any_deleted=false" >> "$GITHUB_OUTPUT" + echo "any_deleted=false" >>"$GITHUB_OUTPUT" fi fi @@ -318,14 +343,14 @@ else echo "::set-output name=only_deleted::false" echo "::set-output name=other_deleted_files::$OTHER_DELETED" else - echo "only_deleted=false" >> "$GITHUB_OUTPUT" - echo "other_deleted_files=$OTHER_DELETED" >> "$GITHUB_OUTPUT" + echo "only_deleted=false" >>"$GITHUB_OUTPUT" + echo "other_deleted_files=$OTHER_DELETED" >>"$GITHUB_OUTPUT" fi elif [[ -n "${DELETED}" ]]; then if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=only_deleted::true" else - echo "only_deleted=true" >> "$GITHUB_OUTPUT" + echo "only_deleted=true" >>"$GITHUB_OUTPUT" fi fi if [[ "$INPUT_JSON" == "false" ]]; then @@ -383,7 +408,7 @@ if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=all_changed_files::$ALL_CHANGED" echo "::set-output name=all_modified_files::$ALL_MODIFIED" else - cat <> "$GITHUB_OUTPUT" + cat <>"$GITHUB_OUTPUT" added_files=$ADDED copied_files=$COPIED deleted_files=$DELETED @@ -402,7 +427,7 @@ if [[ $INPUT_INCLUDE_ALL_OLD_NEW_RENAMED_FILES == "true" ]]; then if [[ -z "$GITHUB_OUTPUT" ]]; then echo "::set-output name=all_old_new_renamed_files::$ALL_OLD_NEW_RENAMED" else - echo "all_old_new_renamed_files=$ALL_OLD_NEW_RENAMED" >> "$GITHUB_OUTPUT" + echo "all_old_new_renamed_files=$ALL_OLD_NEW_RENAMED" >>"$GITHUB_OUTPUT" fi fi diff --git a/test/test/test.txt b/test/test/test.txt index 6de7b8c6..9f4b6d8b 100644 --- a/test/test/test.txt +++ b/test/test/test.txt @@ -1 +1 @@ -This is a test file. +This is a test file diff --git a/test/test2/test.txt b/test/test2/test.txt new file mode 100644 index 00000000..570d0dbf --- /dev/null +++ b/test/test2/test.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adip eget, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file diff --git a/test/test2/test3/new.txt b/test/test2/test3/new.txt new file mode 100644 index 00000000..7b03026c --- /dev/null +++ b/test/test2/test3/new.txt @@ -0,0 +1 @@ +Test file. \ No newline at end of file diff --git a/test/test2/test3/test4/test.txt b/test/test2/test3/test4/test.txt new file mode 100644 index 00000000..7b03026c --- /dev/null +++ b/test/test2/test3/test4/test.txt @@ -0,0 +1 @@ +Test file. \ No newline at end of file