Compare commits

..

No commits in common. "main" and "v40" have entirely different histories.
main ... v40

37 changed files with 7724 additions and 21790 deletions

View File

@ -208,52 +208,6 @@
"test",
"bug"
]
},
{
"login": "levenleven",
"name": "Aleksey Levenstein",
"avatar_url": "https://avatars.githubusercontent.com/u/6463364?v=4",
"profile": "https://github.com/levenleven",
"contributions": [
"doc"
]
},
{
"login": "dan-hill2802",
"name": "Daniel Hill",
"avatar_url": "https://avatars.githubusercontent.com/u/5046322?v=4",
"profile": "https://github.com/dan-hill2802",
"contributions": [
"doc"
]
},
{
"login": "KeisukeYamashita",
"name": "KeisukeYamashita",
"avatar_url": "https://avatars.githubusercontent.com/u/23056537?v=4",
"profile": "https://keisukeyamashita.com",
"contributions": [
"doc"
]
},
{
"login": "codesculpture",
"name": "Aravind",
"avatar_url": "https://avatars.githubusercontent.com/u/63452117?v=4",
"profile": "https://github.com/codesculpture",
"contributions": [
"code",
"bug"
]
},
{
"login": "Whadup",
"name": "Lukas Pfahler",
"avatar_url": "https://avatars.githubusercontent.com/u/2308119?v=4",
"profile": "https://lukaspfahler.de",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@ -17,13 +17,13 @@ on:
schedule:
- cron: '15 16 * * 2'
permissions:
actions: read
contents: read
security-events: write
jobs:
codacy-security-scan:
# Cancel other workflows that are running for the same branch
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
@ -34,7 +34,7 @@ jobs:
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
continue-on-error: true
uses: codacy/codacy-analysis-cli-action@v4.4.5
uses: codacy/codacy-analysis-cli-action@v4.3.0
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations

View File

@ -20,11 +20,6 @@ on:
schedule:
- cron: '44 20 * * 0'
permissions:
actions: read
contents: read
security-events: write
jobs:
analyze:
name: Analyze

View File

@ -1,18 +0,0 @@
name: Greetings
on: [pull_request_target, issues]
permissions:
pull-requests: write
issues: write
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
continue-on-error: true
with:
repo-token: ${{ secrets.PAT_TOKEN }}
issue-message: "Thanks for reporting this issue, don't forget to star this project if you haven't already to help us reach a wider audience."
pr-message: "Thanks for implementing a fix, could you ensure that the test covers your changes if applicable."

View File

@ -1,8 +1,4 @@
name: Issue Comment Job Example
permissions:
contents: read
name: Issue Comment Test
on:
issue_comment:

View File

@ -1,11 +1,9 @@
name: Manual Triggered Job Example
permissions:
contents: read
name: Manual Test
on:
workflow_dispatch:
jobs:
test:
name: Test changed-files

View File

@ -1,7 +1,4 @@
name: Matrix Example
permissions:
contents: read
name: Matrix Test
on:
workflow_dispatch:
@ -24,7 +21,9 @@ jobs:
id: changed-files
uses: ./
with:
matrix: true
json: true
quotepath: false
escape_json: false
- name: List all changed files
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'

View File

@ -1,67 +0,0 @@
name: Multi Job Example
permissions:
contents: read
on:
push:
branches:
- "**"
pull_request:
branches:
- "**"
jobs:
changed-files:
name: Get changed files
runs-on: ubuntu-latest
outputs:
all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: ./
- name: List all changed files
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
view-changed-files:
name: View all changed files
runs-on: ubuntu-latest
needs: [changed-files]
steps:
- name: List all changed files
run: |
echo '${{ needs.changed-files.outputs.all_changed_files }}'
changed-files-rest-api:
name: Get changed files using REST API
runs-on: ubuntu-latest
outputs:
all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
continue-on-error: ${{ github.event_name == 'push' }}
uses: ./
with:
use_rest_api: true
- name: List all changed files
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
view-changed-files-rest-api:
name: View all changed files using REST API
runs-on: ubuntu-latest
needs: [changed-files-rest-api]
steps:
- name: List all changed files
run: |
echo '${{ needs.changed-files-rest-api.outputs.all_changed_files }}'

View File

@ -1,9 +1,4 @@
name: Update release version
permissions:
contents: write
pull-requests: write
name: Update release version.
on:
release:
types: [published]
@ -37,7 +32,7 @@ jobs:
- name: Run git-cliff
uses: tj-actions/git-cliff@v1
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7.0.5
uses: peter-evans/create-pull-request@v5.0.2
with:
base: "main"
labels: "merge when passing"

View File

@ -1,8 +1,5 @@
name: CI
permissions:
contents: read
on:
push:
branches:
@ -34,9 +31,6 @@ jobs:
runs-on: ubuntu-latest
outputs:
files_changed: ${{ steps.changed_files.outputs.files_changed }}
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
@ -45,7 +39,7 @@ jobs:
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Use Node.js 20.x
uses: actions/setup-node@v4.1.0
uses: actions/setup-node@v4.0.1
with:
cache: 'yarn'
node-version: '20.x'
@ -60,7 +54,7 @@ jobs:
yarn install
- name: Run eslint on changed files
uses: tj-actions/eslint-changed-files@v25
uses: tj-actions/eslint-changed-files@v21
if: github.event_name == 'pull_request'
with:
token: ${{ secrets.PAT_TOKEN }}
@ -70,12 +64,9 @@ jobs:
- name: Run build and test
run: |
yarn all
env:
GITHUB_EVENT_PULL_REQUEST_HEAD_REPO_FORK: ${{ github.event.pull_request.head.repo.fork }}
- name: Verify Changed files
uses: tj-actions/verify-changed-files@v20
if: github.actor != 'dependabot[bot]'
uses: tj-actions/verify-changed-files@v16
id: changed_files
with:
files: |
@ -116,8 +107,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout into dir1
uses: actions/checkout@v4
@ -192,8 +181,7 @@ jobs:
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'push' && needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
uses: actions/checkout@v4
@ -251,8 +239,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
@ -295,8 +281,6 @@ jobs:
github.event_name == 'push' ||
github.event_name == 'pull_request'
) && needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
@ -327,8 +311,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
@ -368,8 +350,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: github.event_name != 'push' && needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
@ -397,8 +377,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: github.event_name != 'push' && needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
@ -433,8 +411,7 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
uses: actions/checkout@v4
@ -488,8 +465,7 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
uses: actions/checkout@v4
@ -570,83 +546,11 @@ jobs:
shell:
bash
test-dir-names-nested-folder:
name: Test changed-files with dir-names in a nested folder
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: true
fetch-depth: 0
- name: Download build assets
uses: actions/download-artifact@v4
with:
name: build-assets
path: dist
- name: Get changed files in the .github folder
id: changed-files
uses: ./
with:
path: .github
json: true
escape_json: false
dir_names: true
dir_names_exclude_current_dir: true
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files.outputs) }}"
shell:
bash
test-non-existing-repository:
name: Test changed-files with non existing repository
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push' && needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout into dir1
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: true
fetch-depth: 0
path: dir1
- name: Download build assets
uses: actions/download-artifact@v4
with:
name: build-assets
path: dir1/dist
- name: Run changed-files with non existing repository
id: changed-files
continue-on-error: true
uses: ./dir1
- name: Verify failed
if: steps.changed-files.outcome != 'failure'
run: |
echo "Expected: (failure) got ${{ steps.changed-files.outcome }}"
exit 1
test-submodules:
name: Test changed-files with submodule
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
@ -685,34 +589,11 @@ jobs:
echo "${{ toJSON(steps.changed-files.outputs) }}"
shell:
bash
- name: Run changed-files excluding submodule
id: changed-files-exclude-submodule
uses: ./
with:
base_sha: "85bd869"
sha: "adde7bb"
fetch_depth: 60000
exclude_submodules: true
- name: Verify no added files
if: steps.changed-files-exclude-submodule.outputs.added_files != ''
run: |
echo "Expected: ('') got ${{ steps.changed-files-exclude-submodule.outputs.added_files }}"
exit 1
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-exclude-submodule.outputs) }}"
shell:
bash
test-yaml:
name: Test changed-files with yaml
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
@ -760,24 +641,6 @@ jobs:
shell:
bash
- name: Run changed-files with files_yaml, files_ignore_yaml
id: changed-files-ignore
uses: ./
with:
files_yaml: |
test:
- test/**.txt
- test/**.md
files_ignore_yaml: |
test:
- test/test.txt
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-ignore.outputs) }}"
shell:
bash
- name: Run changed-files with files_yaml, json and write_output_files
id: changed-files-json-write-output-files
uses: ./
@ -806,8 +669,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
@ -998,8 +859,6 @@ jobs:
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
uses: actions/checkout@v4
@ -1030,19 +889,14 @@ jobs:
bash
test-dir-names-deleted-files-include-only-deleted-dirs-directory:
name: Test dir names deleted files include only deleted dirs
runs-on: ${{ matrix.platform }}
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
steps:
- name: Checkout branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
ref: cd1e384723e4d1a184568182ac2b27c53ebf017f
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: true
fetch-depth: 2
@ -1054,7 +908,6 @@ jobs:
sha: cd1e384723e4d1a184568182ac2b27c53ebf017f
dir_names: true
dir_names_deleted_files_include_only_deleted_dirs: true
fetch_depth: 60000
- name: Show output
run: |
echo '${{ toJSON(steps.changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory.outputs) }}'
@ -1074,43 +927,12 @@ jobs:
exit 1
shell:
bash
- name: Run changed-files with dir_names and dir_names_deleted_files_include_only_deleted_dirs with the test directory deleted returns posix path separator
id: changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory-posix-path-separator
uses: ./
with:
base_sha: a52f8621d26d5d9f54b80f74bda2d9eedff94693
sha: cd1e384723e4d1a184568182ac2b27c53ebf017f
dir_names: true
dir_names_deleted_files_include_only_deleted_dirs: true
use_posix_path_separator: true
fetch_depth: 60000
- name: Show output
run: |
echo '${{ toJSON(steps.changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory-posix-path-separator.outputs) }}'
shell:
bash
- name: Check deleted_files output on non windows platform
if: steps.changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory-posix-path-separator.outputs.deleted_files != 'test/test3' && runner.os != 'Windows'
run: |
echo "Invalid output: Expected (test/test3) got (${{ steps.changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory-posix-path-separator.outputs.deleted_files }})"
exit 1
shell:
bash
- name: Check deleted_files output on windows platform
if: "!contains(steps.changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory-posix-path-separator.outputs.deleted_files, 'test/test3') && runner.os == 'Windows'"
run: |
echo "Invalid output: Expected (test/test3) got (${{ steps.changed-files-dir-names-deleted-files-include-only-deleted-dirs-directory-posix-path-separator.outputs.deleted_files }})"
exit 1
shell:
bash
test-since-last-remote-commit:
name: Test changed-files since last remote commit
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
@ -1138,10 +960,10 @@ jobs:
with:
since_last_remote_commit: true
- name: Verify succeeded pull_request(closed)
if: steps.changed-files-since-last-remote-commit.outcome != 'success' && matrix.fetch-depth == 1 && github.event.action == 'closed' && github.event_name == 'pull_request'
- name: Verify failed
if: steps.changed-files-since-last-remote-commit.outcome != 'failure' && matrix.fetch-depth == 1 && github.event.action == 'closed' && github.event_name == 'pull_request'
run: |
echo "Expected: (success) got ${{ steps.changed-files-since-last-remote-commit.outcome }}"
echo "Expected: (failure) got ${{ steps.changed-files-since-last-remote-commit.outcome }}"
exit 1
- name: Verify succeeded
@ -1161,8 +983,6 @@ jobs:
runs-on: ${{ matrix.platform }}
needs: build
if: needs.build.outputs.files_changed != 'true'
permissions:
contents: read
strategy:
fail-fast: false
max-parallel: 4
@ -1193,7 +1013,7 @@ jobs:
echo '${{ toJSON(steps.changed-files.outputs) }}'
shell:
bash
- name: Run changed-files with dir name pattern
- name: Run changed-files with dir name
id: changed-files-dir-name
uses: ./
with:

View File

@ -1,9 +1,5 @@
name: Format README.md
permissions:
contents: read
pull-requests: write
on:
push:
branches:
@ -27,7 +23,7 @@ jobs:
uses: tj-actions/remark@v3
- name: Verify Changed files
uses: tj-actions/verify-changed-files@v20
uses: tj-actions/verify-changed-files@v16
id: verify_changed_files
with:
files: |
@ -41,7 +37,7 @@ jobs:
- name: Create Pull Request
if: failure()
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v5
with:
base: "main"
labels: "merge when passing"

View File

@ -1,41 +0,0 @@
name: Workflow Run Example
on:
workflow_run:
workflows: [Matrix Example]
types: [completed]
permissions:
contents: read
jobs:
on-success:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get changed files
id: changed-files
uses: ./
- name: Echo list of changed files on success
run: |
echo "Changed files on success:"
echo "${{ steps.changed-files.outputs.all_changed_files }}"
on-failure:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get changed files
id: changed-files
uses: ./
- name: Echo list of changed files on failure
run: |
echo "Changed files on failure:"
echo "${{ steps.changed-files.outputs.all_changed_files }}"

1525
HISTORY.md

File diff suppressed because it is too large Load Diff

514
README.md

File diff suppressed because it is too large Load Diff

View File

@ -127,25 +127,21 @@ inputs:
required: false
default: "false"
json:
description: "Output list of changed files in a JSON formatted string which can be used for matrix jobs. Example: https://github.com/tj-actions/changed-files/blob/main/.github/workflows/matrix-example.yml"
description: "Output list of changed files in a JSON formatted string which can be used for matrix jobs. Example: https://github.com/tj-actions/changed-files/blob/main/.github/workflows/matrix-test.yml"
required: false
default: "false"
escape_json:
description: "Escape JSON output."
required: false
default: "true"
safe_output:
description: "Apply sanitization to output filenames before being set as output."
required: false
default: "true"
fetch_depth:
description: "Depth of additional branch history fetched. NOTE: This can be adjusted to resolve errors with insufficient history."
required: false
default: "25"
default: "50"
skip_initial_fetch:
description: |
Skip initially fetching additional history to improve performance for shallow repositories.
NOTE: This could lead to errors with missing history. It's intended to be used when you've fetched all necessary history to perform the diff.
Skip the initial fetch to improve performance for shallow repositories.
NOTE: This could lead to errors with missing history and the intended use is limited to when you've fetched the history necessary to perform the diff.
required: false
default: "false"
fetch_additional_submodule_history:
@ -203,10 +199,6 @@ inputs:
description: "Github API URL."
required: false
default: ${{ github.api_url }}
use_rest_api:
description: "Force the use of Github's REST API even when a local copy of the repository exists"
required: false
default: "false"
fail_on_initial_diff_error:
description: "Fail when the initial diff fails."
required: false
@ -219,31 +211,6 @@ inputs:
description: "Apply the negation patterns first. NOTE: This affects how changed files are matched."
required: false
default: "false"
matrix:
description: "Output changed files in a format that can be used for matrix jobs. Alias for setting inputs `json` to `true` and `escape_json` to `false`."
required: false
default: "false"
exclude_submodules:
description: "Exclude changes to submodules."
required: false
default: "false"
fetch_missing_history_max_retries:
description: "Maximum number of retries to fetch missing history."
required: false
default: "20"
use_posix_path_separator:
description: "Use POSIX path separator `/` for output file paths on Windows."
required: false
default: "false"
tags_pattern:
description: "Tags pattern to include."
required: false
default: "*"
tags_ignore_pattern:
description: "Tags pattern to ignore."
required: false
default: ""
outputs:
added_files:
@ -283,45 +250,45 @@ outputs:
unknown_files_count:
description: "Returns the number of `unknown_files`"
all_changed_and_modified_files:
description: "Returns all changed and modified files i.e. a combination of (ACMRDTUX)"
description: "Returns all changed and modified files i.e. *a combination of (ACMRDTUX)*"
all_changed_and_modified_files_count:
description: "Returns the number of `all_changed_and_modified_files`"
all_changed_files:
description: "Returns all changed files i.e. a combination of all added, copied, modified and renamed files (ACMR)"
description: "Returns all changed files i.e. *a combination of all added, copied, modified and renamed files (ACMR)*"
all_changed_files_count:
description: "Returns the number of `all_changed_files`"
any_changed:
description: "Returns `true` when any of the filenames provided using the `files*` or `files_ignore*` inputs have changed. This defaults to `true` when no patterns are specified. i.e. *includes a combination of all added, copied, modified and renamed files (ACMR)*."
description: "Returns `true` when any of the filenames provided using the `files*` or `files_ignore*` inputs has changed. i.e. *includes a combination of all added, copied, modified and renamed files (ACMR)*."
only_changed:
description: "Returns `true` when only files provided using the `files*` or `files_ignore*` inputs have changed. i.e. *includes a combination of all added, copied, modified and renamed files (ACMR)*."
description: "Returns `true` when only files provided using the `files*` or `files_ignore*` inputs has changed. i.e. *includes a combination of all added, copied, modified and renamed files (ACMR)*."
other_changed_files:
description: "Returns all other changed files not listed in the files input i.e. includes a combination of all added, copied, modified and renamed files (ACMR)."
description: "Returns all other changed files not listed in the files input i.e. *includes a combination of all added, copied, modified and renamed files (ACMR)*."
other_changed_files_count:
description: "Returns the number of `other_changed_files`"
all_modified_files:
description: "Returns all changed files i.e. a combination of all added, copied, modified, renamed and deleted files (ACMRD)."
description: "Returns all changed files i.e. *a combination of all added, copied, modified, renamed and deleted files (ACMRD)*."
all_modified_files_count:
description: "Returns the number of `all_modified_files`"
any_modified:
description: "Returns `true` when any of the filenames provided using the `files*` or `files_ignore*` inputs have been modified. This defaults to `true` when no patterns are specified. i.e. *includes a combination of all added, copied, modified, renamed, and deleted files (ACMRD)*."
description: "Returns `true` when any of the filenames provided using the `files*` or `files_ignore*` inputs has been modified. i.e. *includes a combination of all added, copied, modified, renamed, and deleted files (ACMRD)*."
only_modified:
description: "Returns `true` when only files provided using the `files*` or `files_ignore*` inputs have been modified. (ACMRD)."
description: "Returns `true` when only files provided using the `files*` or `files_ignore*` inputs has been modified. (ACMRD)."
other_modified_files:
description: "Returns all other modified files not listed in the files input i.e. a combination of all added, copied, modified, and deleted files (ACMRD)"
description: "Returns all other modified files not listed in the files input i.e. *a combination of all added, copied, modified, and deleted files (ACMRD)*"
other_modified_files_count:
description: "Returns the number of `other_modified_files`"
any_deleted:
description: "Returns `true` when any of the filenames provided using the `files*` or `files_ignore*` inputs have been deleted. This defaults to `true` when no patterns are specified. (D)"
description: "Returns `true` when any of the filenames provided using the `files*` or `files_ignore*` inputs has been deleted. (D)"
only_deleted:
description: "Returns `true` when only files provided using the `files*` or `files_ignore*` inputs have been deleted. (D)"
description: "Returns `true` when only files provided using the `files*` or `files_ignore*` inputs has been deleted. (D)"
other_deleted_files:
description: "Returns all other deleted files not listed in the files input i.e. a combination of all deleted files (D)"
description: "Returns all other deleted files not listed in the files input i.e. *a combination of all deleted files (D)*"
other_deleted_files_count:
description: "Returns the number of `other_deleted_files`"
modified_keys:
description: "Returns all modified YAML keys when the `files_yaml` input is used. i.e. key that contains any path that has either been added, copied, modified, and deleted (ACMRD)"
description: "Returns all modified YAML keys when the `files_yaml` input is used. i.e. *key that contains any path that has either been added, copied, modified, and deleted (ACMRD)*"
changed_keys:
description: "Returns all changed YAML keys when the `files_yaml` input is used. i.e. key that contains any path that has either been added, copied, modified, and renamed (ACMR)"
description: "Returns all changed YAML keys when the `files_yaml` input is used. i.e. *key that contains any path that has either been added, copied, modified, and renamed (ACMR)*"
runs:
using: 'node20'

17445
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

5264
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load Diff

2
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -10,4 +10,4 @@ module.exports = {
setupFiles: [
"<rootDir>/jest/setupEnv.cjs"
]
};
}

View File

@ -1,5 +1,6 @@
const path = require('path')
process.env.TESTING = "1"
process.env.GITHUB_WORKSPACE = path.join(
path.resolve(__dirname, '..'), '.'
)

View File

@ -1,6 +1,6 @@
{
"name": "@tj-actions/changed-files",
"version": "45.0.4",
"version": "40.2.2",
"description": "Github action to retrieve all (added, copied, modified, deleted, renamed, type changed, unmerged, unknown) files and directories.",
"main": "lib/main.js",
"publishConfig": {
@ -14,7 +14,6 @@
"lint:fix": "eslint --fix src/*.ts src/**/*.ts",
"package": "ncc build lib/main.js --source-map --license licenses.txt",
"test": "jest --coverage",
"update-snapshot": "jest -u",
"all": "yarn build && yarn format && yarn lint && yarn package && yarn test"
},
"repository": {
@ -36,8 +35,7 @@
"@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0",
"@octokit/rest": "^21.0.0",
"@stdlib/utils-convert-path": "^0.2.1",
"@octokit/rest": "^20.0.1",
"lodash": "^4.17.21",
"micromatch": "^4.0.5",
"yaml": "^2.3.1"
@ -46,16 +44,16 @@
"@types/jest": "^29.5.2",
"@types/lodash": "^4.14.195",
"@types/micromatch": "^4.0.2",
"@types/node": "^22.0.0",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"@types/node": "^20.3.2",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vercel/ncc": "^0.38.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-github": "^5.0.0",
"eslint-plugin-jest": "^28.0.0",
"eslint-plugin-github": "^4.8.0",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-prettier": "^5.0.0-alpha.2",
"eslint-config-prettier": "^9.0.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"ts-jest": "^29.1.0",

View File

@ -1,373 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`getInputs should correctly parse boolean inputs 1`] = `
{
"apiUrl": "",
"baseSha": "",
"diffRelative": "false",
"dirNames": "false",
"dirNamesDeletedFilesIncludeOnlyDeletedDirs": "false",
"dirNamesExcludeCurrentDir": "false",
"dirNamesIncludeFiles": "",
"dirNamesIncludeFilesSeparator": "",
"escapeJson": false,
"excludeSubmodules": "false",
"failOnInitialDiffError": "false",
"failOnSubmoduleDiffError": "false",
"fetchAdditionalSubmoduleHistory": "false",
"fetchMissingHistoryMaxRetries": 20,
"files": "",
"filesFromSourceFile": "",
"filesFromSourceFileSeparator": "",
"filesIgnore": "",
"filesIgnoreFromSourceFile": "",
"filesIgnoreFromSourceFileSeparator": "",
"filesIgnoreSeparator": "",
"filesIgnoreYaml": "",
"filesIgnoreYamlFromSourceFile": "",
"filesIgnoreYamlFromSourceFileSeparator": "",
"filesSeparator": "",
"filesYaml": "",
"filesYamlFromSourceFile": "",
"filesYamlFromSourceFileSeparator": "",
"includeAllOldNewRenamedFiles": "false",
"json": true,
"negationPatternsFirst": "false",
"oldNewFilesSeparator": " ",
"oldNewSeparator": ",",
"outputDir": "",
"outputRenamedFilesAsDeletedAndAdded": "false",
"path": ".",
"quotepath": "false",
"recoverDeletedFiles": "false",
"recoverDeletedFilesToDestination": "",
"recoverFiles": "",
"recoverFilesIgnore": "",
"recoverFilesIgnoreSeparator": "
",
"recoverFilesSeparator": "
",
"safeOutput": "false",
"separator": "",
"sha": "",
"since": "",
"sinceLastRemoteCommit": "false",
"skipInitialFetch": "true",
"tagsIgnorePattern": "",
"tagsPattern": "*",
"token": "",
"until": "",
"usePosixPathSeparator": "false",
"useRestApi": "false",
"writeOutputFiles": "false",
}
`;
exports[`getInputs should correctly parse numeric inputs 1`] = `
{
"apiUrl": "",
"baseSha": "",
"diffRelative": true,
"dirNames": false,
"dirNamesDeletedFilesIncludeOnlyDeletedDirs": false,
"dirNamesExcludeCurrentDir": false,
"dirNamesIncludeFiles": "",
"dirNamesIncludeFilesSeparator": "",
"dirNamesMaxDepth": 2,
"escapeJson": false,
"excludeSubmodules": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
"fetchDepth": 5,
"files": "",
"filesFromSourceFile": "",
"filesFromSourceFileSeparator": "",
"filesIgnore": "",
"filesIgnoreFromSourceFile": "",
"filesIgnoreFromSourceFileSeparator": "",
"filesIgnoreSeparator": "",
"filesIgnoreYaml": "",
"filesIgnoreYamlFromSourceFile": "",
"filesIgnoreYamlFromSourceFileSeparator": "",
"filesSeparator": "",
"filesYaml": "",
"filesYamlFromSourceFile": "",
"filesYamlFromSourceFileSeparator": "",
"includeAllOldNewRenamedFiles": false,
"json": false,
"negationPatternsFirst": false,
"oldNewFilesSeparator": "",
"oldNewSeparator": "",
"outputDir": "",
"outputRenamedFilesAsDeletedAndAdded": false,
"path": "",
"quotepath": true,
"recoverDeletedFiles": false,
"recoverDeletedFilesToDestination": "",
"recoverFiles": "",
"recoverFilesIgnore": "",
"recoverFilesIgnoreSeparator": "",
"recoverFilesSeparator": "",
"safeOutput": false,
"separator": "",
"sha": "",
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "",
"until": "",
"usePosixPathSeparator": false,
"useRestApi": false,
"writeOutputFiles": false,
}
`;
exports[`getInputs should correctly parse string inputs 1`] = `
{
"apiUrl": "https://api.github.com",
"baseSha": "",
"diffRelative": true,
"dirNames": false,
"dirNamesDeletedFilesIncludeOnlyDeletedDirs": false,
"dirNamesExcludeCurrentDir": false,
"dirNamesIncludeFiles": "",
"dirNamesIncludeFilesSeparator": "",
"escapeJson": false,
"excludeSubmodules": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
"files": "",
"filesFromSourceFile": "",
"filesFromSourceFileSeparator": "",
"filesIgnore": "",
"filesIgnoreFromSourceFile": "",
"filesIgnoreFromSourceFileSeparator": "",
"filesIgnoreSeparator": "",
"filesIgnoreYaml": "",
"filesIgnoreYamlFromSourceFile": "",
"filesIgnoreYamlFromSourceFileSeparator": "",
"filesSeparator": "",
"filesYaml": "",
"filesYamlFromSourceFile": "",
"filesYamlFromSourceFileSeparator": "",
"includeAllOldNewRenamedFiles": false,
"json": false,
"negationPatternsFirst": false,
"oldNewFilesSeparator": "",
"oldNewSeparator": "",
"outputDir": "",
"outputRenamedFilesAsDeletedAndAdded": false,
"path": "",
"quotepath": true,
"recoverDeletedFiles": false,
"recoverDeletedFilesToDestination": "",
"recoverFiles": "",
"recoverFilesIgnore": "",
"recoverFilesIgnoreSeparator": "",
"recoverFilesSeparator": "",
"safeOutput": false,
"separator": "",
"sha": "",
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "token",
"until": "",
"usePosixPathSeparator": false,
"useRestApi": false,
"writeOutputFiles": false,
}
`;
exports[`getInputs should handle invalid numeric inputs correctly 1`] = `
{
"apiUrl": "",
"baseSha": "",
"diffRelative": true,
"dirNames": false,
"dirNamesDeletedFilesIncludeOnlyDeletedDirs": false,
"dirNamesExcludeCurrentDir": false,
"dirNamesIncludeFiles": "",
"dirNamesIncludeFilesSeparator": "",
"dirNamesMaxDepth": 2,
"escapeJson": false,
"excludeSubmodules": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
"fetchDepth": NaN,
"files": "",
"filesFromSourceFile": "",
"filesFromSourceFileSeparator": "",
"filesIgnore": "",
"filesIgnoreFromSourceFile": "",
"filesIgnoreFromSourceFileSeparator": "",
"filesIgnoreSeparator": "",
"filesIgnoreYaml": "",
"filesIgnoreYamlFromSourceFile": "",
"filesIgnoreYamlFromSourceFileSeparator": "",
"filesSeparator": "",
"filesYaml": "",
"filesYamlFromSourceFile": "",
"filesYamlFromSourceFileSeparator": "",
"includeAllOldNewRenamedFiles": false,
"json": false,
"negationPatternsFirst": false,
"oldNewFilesSeparator": "",
"oldNewSeparator": "",
"outputDir": "",
"outputRenamedFilesAsDeletedAndAdded": false,
"path": "",
"quotepath": true,
"recoverDeletedFiles": false,
"recoverDeletedFilesToDestination": "",
"recoverFiles": "",
"recoverFilesIgnore": "",
"recoverFilesIgnoreSeparator": "",
"recoverFilesSeparator": "",
"safeOutput": false,
"separator": "",
"sha": "",
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "",
"until": "",
"usePosixPathSeparator": false,
"useRestApi": false,
"writeOutputFiles": false,
}
`;
exports[`getInputs should handle negative numeric inputs correctly 1`] = `
{
"apiUrl": "",
"baseSha": "",
"diffRelative": true,
"dirNames": false,
"dirNamesDeletedFilesIncludeOnlyDeletedDirs": false,
"dirNamesExcludeCurrentDir": false,
"dirNamesIncludeFiles": "",
"dirNamesIncludeFilesSeparator": "",
"dirNamesMaxDepth": -2,
"escapeJson": false,
"excludeSubmodules": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
"fetchDepth": 2,
"files": "",
"filesFromSourceFile": "",
"filesFromSourceFileSeparator": "",
"filesIgnore": "",
"filesIgnoreFromSourceFile": "",
"filesIgnoreFromSourceFileSeparator": "",
"filesIgnoreSeparator": "",
"filesIgnoreYaml": "",
"filesIgnoreYamlFromSourceFile": "",
"filesIgnoreYamlFromSourceFileSeparator": "",
"filesSeparator": "",
"filesYaml": "",
"filesYamlFromSourceFile": "",
"filesYamlFromSourceFileSeparator": "",
"includeAllOldNewRenamedFiles": false,
"json": false,
"negationPatternsFirst": false,
"oldNewFilesSeparator": "",
"oldNewSeparator": "",
"outputDir": "",
"outputRenamedFilesAsDeletedAndAdded": false,
"path": "",
"quotepath": true,
"recoverDeletedFiles": false,
"recoverDeletedFilesToDestination": "",
"recoverFiles": "",
"recoverFilesIgnore": "",
"recoverFilesIgnoreSeparator": "",
"recoverFilesSeparator": "",
"safeOutput": false,
"separator": "",
"sha": "",
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "",
"until": "",
"usePosixPathSeparator": false,
"useRestApi": false,
"writeOutputFiles": false,
}
`;
exports[`getInputs should return default values when no inputs are provided 1`] = `
{
"apiUrl": "",
"baseSha": "",
"diffRelative": true,
"dirNames": false,
"dirNamesDeletedFilesIncludeOnlyDeletedDirs": false,
"dirNamesExcludeCurrentDir": false,
"dirNamesIncludeFiles": "",
"dirNamesIncludeFilesSeparator": "",
"escapeJson": false,
"excludeSubmodules": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
"fetchMissingHistoryMaxRetries": 20,
"files": "",
"filesFromSourceFile": "",
"filesFromSourceFileSeparator": "",
"filesIgnore": "",
"filesIgnoreFromSourceFile": "",
"filesIgnoreFromSourceFileSeparator": "",
"filesIgnoreSeparator": "",
"filesIgnoreYaml": "",
"filesIgnoreYamlFromSourceFile": "",
"filesIgnoreYamlFromSourceFileSeparator": "",
"filesSeparator": "",
"filesYaml": "",
"filesYamlFromSourceFile": "",
"filesYamlFromSourceFileSeparator": "",
"includeAllOldNewRenamedFiles": false,
"json": false,
"negationPatternsFirst": false,
"oldNewFilesSeparator": " ",
"oldNewSeparator": ",",
"outputDir": "",
"outputRenamedFilesAsDeletedAndAdded": false,
"path": ".",
"quotepath": true,
"recoverDeletedFiles": false,
"recoverDeletedFilesToDestination": "",
"recoverFiles": "",
"recoverFilesIgnore": "",
"recoverFilesIgnoreSeparator": "
",
"recoverFilesSeparator": "
",
"safeOutput": false,
"separator": "",
"sha": "",
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"tagsIgnorePattern": "",
"tagsPattern": "*",
"token": "",
"until": "",
"usePosixPathSeparator": false,
"useRestApi": false,
"writeOutputFiles": false,
}
`;

View File

@ -1,153 +0,0 @@
import * as core from '@actions/core'
import {getInputs, Inputs} from '../inputs'
import {DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS} from '../constant'
jest.mock('@actions/core')
describe('getInputs', () => {
afterEach(() => {
jest.clearAllMocks()
})
test('should return default values when no inputs are provided', () => {
;(core.getInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
'') as string
})
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
false) as boolean
})
expect(getInputs()).toMatchSnapshot()
})
test('should correctly parse boolean inputs', () => {
;(core.getInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
'') as string
})
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
switch (name) {
case 'matrix':
return 'true'
case 'skip_initial_fetch':
return 'true'
default:
return 'false'
}
})
expect(getInputs()).toMatchSnapshot()
})
test('should handle matrix alias correctly', () => {
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
return name === 'matrix' ? 'true' : 'false'
})
const inputs = getInputs()
expect(inputs).toHaveProperty('json', true)
expect(inputs).toHaveProperty('escapeJson', false)
})
test('should correctly parse string inputs', () => {
;(core.getInput as jest.Mock).mockImplementation(name => {
switch (name) {
case 'token':
return 'token'
case 'api_url':
return 'https://api.github.com'
default:
return ''
}
})
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
false) as boolean
})
expect(getInputs()).toMatchSnapshot()
})
test('should correctly parse numeric inputs', () => {
;(core.getInput as jest.Mock).mockImplementation(name => {
switch (name) {
case 'fetch_depth':
return '5'
case 'dir_names_max_depth':
return '2'
default:
return ''
}
})
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
false) as boolean
})
expect(getInputs()).toMatchSnapshot()
})
test('should handle invalid numeric inputs correctly', () => {
;(core.getInput as jest.Mock).mockImplementation(name => {
// TODO: Add validation for invalid numbers which should result in an error instead of NaN
switch (name) {
case 'fetch_depth':
return 'invalid'
case 'dir_names_max_depth':
return '2'
default:
return ''
}
})
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
false) as boolean
})
expect(getInputs()).toMatchSnapshot()
})
test('should handle negative numeric inputs correctly', () => {
;(core.getInput as jest.Mock).mockImplementation(name => {
// TODO: Add validation for negative numbers which should result in an error
switch (name) {
case 'fetch_depth':
return '-5'
case 'dir_names_max_depth':
return '-2'
default:
return ''
}
})
;(core.getBooleanInput as jest.Mock).mockImplementation(name => {
const camelCaseName = name.replace(/_([a-z])/g, (g: string[]) => {
return g[1].toUpperCase()
}) as keyof Inputs
return (DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[camelCaseName] ||
false) as boolean
})
expect(getInputs()).toMatchSnapshot()
})
})

View File

@ -1,14 +1,9 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import {ChangeTypeEnum} from '../changedFiles'
import {Inputs} from '../inputs'
import {
getDirname,
getDirnameMaxDepth,
getFilteredChangedFiles,
getPreviousGitTag,
normalizeSeparators,
warnUnsupportedRESTAPIInputs
normalizeSeparators
} from '../utils'
const originalPlatform = process.platform
@ -580,182 +575,4 @@ describe('utils test', () => {
expect(filteredFiles[ChangeTypeEnum.Modified]).toEqual([])
})
})
describe('warnUnsupportedRESTAPIInputs', () => {
// Warns about unsupported inputs when using the REST API.
it('should warn about unsupported inputs when all inputs are supported', async () => {
const inputs: Inputs = {
files: '',
filesSeparator: '\n',
filesFromSourceFile: '',
filesFromSourceFileSeparator: '\n',
filesYaml: '',
filesYamlFromSourceFile: '',
filesYamlFromSourceFileSeparator: '\n',
filesIgnore: '',
filesIgnoreSeparator: '\n',
filesIgnoreFromSourceFile: '',
filesIgnoreFromSourceFileSeparator: '\n',
filesIgnoreYaml: '',
filesIgnoreYamlFromSourceFile: '',
filesIgnoreYamlFromSourceFileSeparator: '\n',
separator: ' ',
includeAllOldNewRenamedFiles: false,
oldNewSeparator: ',',
oldNewFilesSeparator: ' ',
sha: '1313123',
baseSha: '',
since: '',
until: '',
path: '.',
quotepath: true,
diffRelative: true,
dirNames: false,
dirNamesMaxDepth: undefined,
dirNamesExcludeCurrentDir: false,
dirNamesIncludeFiles: '',
dirNamesIncludeFilesSeparator: '\n',
dirNamesDeletedFilesIncludeOnlyDeletedDirs: false,
json: false,
escapeJson: true,
safeOutput: true,
fetchDepth: 50,
fetchAdditionalSubmoduleHistory: false,
sinceLastRemoteCommit: false,
writeOutputFiles: false,
outputDir: '.github/outputs',
outputRenamedFilesAsDeletedAndAdded: false,
recoverDeletedFiles: false,
recoverDeletedFilesToDestination: '',
recoverFiles: '',
recoverFilesSeparator: '\n',
recoverFilesIgnore: '',
recoverFilesIgnoreSeparator: '\n',
token: '${{ github.token }}',
apiUrl: '${{ github.api_url }}',
skipInitialFetch: false,
failOnInitialDiffError: false,
failOnSubmoduleDiffError: false,
negationPatternsFirst: false,
useRestApi: false,
excludeSubmodules: false,
fetchMissingHistoryMaxRetries: 20,
usePosixPathSeparator: false,
tagsPattern: '*',
tagsIgnorePattern: ''
}
const coreWarningSpy = jest.spyOn(core, 'warning')
await warnUnsupportedRESTAPIInputs({
inputs
})
expect(coreWarningSpy).toHaveBeenCalledWith(
'Input "sha" is not supported when using GitHub\'s REST API to get changed files'
)
expect(coreWarningSpy).toHaveBeenCalledTimes(1)
})
})
describe('getPreviousGitTag', () => {
// Check if the environment variable GITHUB_REPOSITORY_OWNER is 'tj-actions'
const shouldSkip = !!process.env.GITHUB_EVENT_PULL_REQUEST_HEAD_REPO_FORK
// Function returns the second-latest tag and its SHA
it('should return the second latest tag and its SHA when multiple tags are present', async () => {
if (shouldSkip) {
return
}
const result = await getPreviousGitTag({
cwd: '.',
tagsPattern: '*',
tagsIgnorePattern: '',
currentBranch: 'v1.0.1'
})
expect(result).toEqual({
tag: 'v1.0.0',
sha: 'f0751de6af436d4e79016e2041cf6400e0833653'
})
})
// Tags are filtered by a specified pattern when 'tagsPattern' is provided
it('should filter tags by the specified pattern', async () => {
if (shouldSkip) {
return
}
const result = await getPreviousGitTag({
cwd: '.',
tagsPattern: 'v1.*',
tagsIgnorePattern: '',
currentBranch: 'v1.0.1'
})
expect(result).toEqual({
tag: 'v1.0.0',
sha: 'f0751de6af436d4e79016e2041cf6400e0833653'
})
})
// Tags are excluded by a specified ignore pattern when 'tagsIgnorePattern' is provided
it('should exclude tags by the specified ignore pattern', async () => {
if (shouldSkip) {
return
}
const result = await getPreviousGitTag({
cwd: '.',
tagsPattern: '*',
tagsIgnorePattern: 'v0.*.*',
currentBranch: 'v1.0.1'
})
expect(result).toEqual({
tag: 'v1.0.0',
sha: 'f0751de6af436d4e79016e2041cf6400e0833653'
})
})
// No tags are available in the repository
it('should return empty values when no tags are available in the repository', async () => {
jest.spyOn(exec, 'getExecOutput').mockResolvedValueOnce({
stdout: '',
stderr: '',
exitCode: 0
})
const result = await getPreviousGitTag({
cwd: '.',
tagsPattern: '*',
tagsIgnorePattern: '',
currentBranch: ''
})
expect(result).toEqual({tag: '', sha: ''})
})
// Only one tag is available, making it impossible to find a previous tag
it('should return empty values when only one tag is available', async () => {
jest.spyOn(exec, 'getExecOutput').mockResolvedValueOnce({
stdout:
'v1.0.1|f0751de6af436d4e79016e2041cf6400e0833653|2021-01-01T00:00:00Z',
stderr: '',
exitCode: 0
})
const result = await getPreviousGitTag({
cwd: '.',
tagsPattern: '*',
tagsIgnorePattern: '',
currentBranch: 'v1.0.1'
})
expect(result).toEqual({tag: '', sha: ''})
})
// Git commands fail and throw errors
it('should throw an error when git commands fail', async () => {
jest
.spyOn(exec, 'getExecOutput')
.mockRejectedValue(new Error('git command failed'))
await expect(
getPreviousGitTag({
cwd: '.',
tagsPattern: '*',
tagsIgnorePattern: '',
currentBranch: 'v1.0.1'
})
).rejects.toThrow('git command failed')
})
})
})

View File

@ -2,7 +2,6 @@ import * as core from '@actions/core'
import * as github from '@actions/github'
import type {RestEndpointMethodTypes} from '@octokit/rest'
import flatten from 'lodash/flatten'
import convertPath from '@stdlib/utils-convert-path'
import mm from 'micromatch'
import * as path from 'path'
import {setOutputsAndGetModifiedAndChangedFilesStatus} from './changedFilesOutput'
@ -122,13 +121,13 @@ export const processChangedFiles = async ({
export const getRenamedFiles = async ({
inputs,
workingDirectory,
diffSubmodule,
hasSubmodule,
diffResult,
submodulePaths
}: {
inputs: Inputs
workingDirectory: string
diffSubmodule: boolean
hasSubmodule: boolean
diffResult: DiffResult
submodulePaths: string[]
}): Promise<{paths: string; count: string}> => {
@ -140,7 +139,7 @@ export const getRenamedFiles = async ({
oldNewSeparator: inputs.oldNewSeparator
})
if (diffSubmodule) {
if (hasSubmodule) {
for (const submodulePath of submodulePaths) {
const submoduleShaResult = await gitSubmoduleDiffSHA({
cwd: workingDirectory,
@ -167,7 +166,7 @@ export const getRenamedFiles = async ({
}))
) {
let message = `Unable to use three dot diff for: ${submodulePath} submodule. Falling back to two dot diff. You can set 'fetch_additional_submodule_history: true' to fetch additional submodule history in order to use three dot diff`
if (inputs.fetchAdditionalSubmoduleHistory) {
if (inputs.fetchSubmoduleHistory) {
message = `To fetch additional submodule history for: ${submodulePath} you can increase history depth using 'fetch_depth' input`
}
core.info(message)
@ -218,20 +217,20 @@ export type ChangedFiles = {
export const getAllDiffFiles = async ({
workingDirectory,
diffSubmodule,
hasSubmodule,
diffResult,
submodulePaths,
outputRenamedFilesAsDeletedAndAdded,
fetchAdditionalSubmoduleHistory,
fetchSubmoduleHistory,
failOnInitialDiffError,
failOnSubmoduleDiffError
}: {
workingDirectory: string
diffSubmodule: boolean
hasSubmodule: boolean
diffResult: DiffResult
submodulePaths: string[]
outputRenamedFilesAsDeletedAndAdded: boolean
fetchAdditionalSubmoduleHistory: boolean
fetchSubmoduleHistory: boolean
failOnInitialDiffError: boolean
failOnSubmoduleDiffError: boolean
}): Promise<ChangedFiles> => {
@ -244,7 +243,7 @@ export const getAllDiffFiles = async ({
failOnInitialDiffError
})
if (diffSubmodule) {
if (hasSubmodule) {
for (const submodulePath of submodulePaths) {
const submoduleShaResult = await gitSubmoduleDiffSHA({
cwd: workingDirectory,
@ -271,7 +270,7 @@ export const getAllDiffFiles = async ({
}))
) {
let message = `Set 'fetch_additional_submodule_history: true' to fetch additional submodule history for: ${submodulePath}`
if (fetchAdditionalSubmoduleHistory) {
if (fetchSubmoduleHistory) {
message = `To fetch additional submodule history for: ${submodulePath} you can increase history depth using 'fetch_depth' input`
}
core.warning(message)
@ -356,11 +355,7 @@ function* getChangeTypeFilesGenerator({
filePaths,
dirNamesIncludeFilePatterns
})) {
if (isWindows() && inputs.usePosixPathSeparator) {
yield convertPath(filePath, 'mixed')
} else {
yield filePath
}
yield filePath
}
}
}
@ -407,11 +402,7 @@ function* getAllChangeTypeFilesGenerator({
filePaths,
dirNamesIncludeFilePatterns
})) {
if (isWindows() && inputs.usePosixPathSeparator) {
yield convertPath(filePath, 'mixed')
} else {
yield filePath
}
yield filePath
}
}
@ -484,7 +475,7 @@ export const getChangedFilesFromGithubAPI = async ({
if (changeType === ChangeTypeEnum.Renamed) {
if (inputs.outputRenamedFilesAsDeletedAndAdded) {
changedFiles[ChangeTypeEnum.Deleted].push(item.previous_filename || '')
changedFiles[ChangeTypeEnum.Deleted].push(item.filename)
changedFiles[ChangeTypeEnum.Added].push(item.filename)
} else {
changedFiles[ChangeTypeEnum.Renamed].push(item.filename)

View File

@ -43,8 +43,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
key: getOutputKey('added_files_count', outputPrefix),
@ -65,8 +64,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -88,8 +86,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -111,8 +108,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -134,8 +130,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -157,8 +152,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -180,8 +174,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -206,8 +199,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -234,8 +226,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -247,7 +238,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
await setOutput({
key: getOutputKey('any_changed', outputPrefix),
value: allChangedFiles.paths.length > 0,
value: allChangedFiles.paths.length > 0 && filePatterns.length > 0,
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json
@ -323,8 +314,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -336,7 +326,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
await setOutput({
key: getOutputKey('any_modified', outputPrefix),
value: allModifiedFiles.paths.length > 0,
value: allModifiedFiles.paths.length > 0 && filePatterns.length > 0,
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json
@ -429,8 +419,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
await setOutput({
@ -442,7 +431,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
await setOutput({
key: getOutputKey('any_deleted', outputPrefix),
value: deletedFiles.paths.length > 0,
value: deletedFiles.paths.length > 0 && filePatterns.length > 0,
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json
@ -496,7 +485,7 @@ export const setOutputsAndGetModifiedAndChangedFilesStatus = async ({
})
return {
anyModified: allModifiedFiles.paths.length > 0,
anyChanged: allChangedFiles.paths.length > 0
anyModified: allModifiedFiles.paths.length > 0 && filePatterns.length > 0,
anyChanged: allChangedFiles.paths.length > 0 && filePatterns.length > 0
}
}

View File

@ -86,27 +86,15 @@ export interface DiffResult {
initialCommit?: boolean
}
interface SHAForNonPullRequestEvent {
inputs: Inputs
env: Env
workingDirectory: string
isShallow: boolean
diffSubmodule: boolean
gitFetchExtraArgs: string[]
export const getSHAForNonPullRequestEvent = async (
inputs: Inputs,
env: Env,
workingDirectory: string,
isShallow: boolean,
hasSubmodule: boolean,
gitFetchExtraArgs: string[],
isTag: boolean
remoteName: string
}
export const getSHAForNonPullRequestEvent = async ({
inputs,
env,
workingDirectory,
isShallow,
diffSubmodule,
gitFetchExtraArgs,
isTag,
remoteName
}: SHAForNonPullRequestEvent): Promise<DiffResult> => {
): Promise<DiffResult> => {
let targetBranch = env.GITHUB_REF_NAME
let currentBranch = targetBranch
let initialCommit = false
@ -134,8 +122,8 @@ export const getSHAForNonPullRequestEvent = async ({
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
remoteName,
`+refs/heads/${sourceBranch}:refs/remotes/${remoteName}/${sourceBranch}`
'origin',
`+refs/heads/${sourceBranch}:refs/remotes/origin/${sourceBranch}`
]
})
} else {
@ -146,13 +134,13 @@ export const getSHAForNonPullRequestEvent = async ({
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
remoteName,
`+refs/heads/${targetBranch}:refs/remotes/${remoteName}/${targetBranch}`
'origin',
`+refs/heads/${targetBranch}:refs/remotes/origin/${targetBranch}`
]
})
}
if (diffSubmodule) {
if (hasSubmodule) {
await gitFetchSubmodules({
cwd: workingDirectory,
args: [
@ -164,7 +152,7 @@ export const getSHAForNonPullRequestEvent = async ({
})
}
} else {
if (diffSubmodule && inputs.fetchAdditionalSubmoduleHistory) {
if (hasSubmodule && inputs.fetchSubmoduleHistory) {
await gitFetchSubmodules({
cwd: workingDirectory,
args: [
@ -240,12 +228,7 @@ export const getSHAForNonPullRequestEvent = async ({
}
} else if (isTag) {
core.debug('Getting previous SHA for tag...')
const {sha, tag} = await getPreviousGitTag({
cwd: workingDirectory,
tagsPattern: inputs.tagsPattern,
tagsIgnorePattern: inputs.tagsIgnorePattern,
currentBranch
})
const {sha, tag} = await getPreviousGitTag({cwd: workingDirectory})
previousSha = sha
targetBranch = tag
} else {
@ -324,23 +307,14 @@ export const getSHAForNonPullRequestEvent = async ({
}
}
interface SHAForPullRequestEvent {
inputs: Inputs
workingDirectory: string
isShallow: boolean
diffSubmodule: boolean
export const getSHAForPullRequestEvent = async (
inputs: Inputs,
env: Env,
workingDirectory: string,
isShallow: boolean,
hasSubmodule: boolean,
gitFetchExtraArgs: string[]
remoteName: string
}
export const getSHAForPullRequestEvent = async ({
inputs,
workingDirectory,
isShallow,
diffSubmodule,
gitFetchExtraArgs,
remoteName
}: SHAForPullRequestEvent): Promise<DiffResult> => {
): Promise<DiffResult> => {
let targetBranch = github.context.payload.pull_request?.base?.ref
const currentBranch = github.context.payload.pull_request?.head?.ref
if (inputs.sinceLastRemoteCommit) {
@ -356,7 +330,7 @@ export const getSHAForPullRequestEvent = async ({
...gitFetchExtraArgs,
'-u',
'--progress',
remoteName,
'origin',
`pull/${github.context.payload.pull_request?.number}/head:${currentBranch}`
]
})
@ -369,8 +343,8 @@ export const getSHAForPullRequestEvent = async ({
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
remoteName,
`+refs/heads/${currentBranch}*:refs/remotes/${remoteName}/${currentBranch}*`
'origin',
`+refs/heads/${currentBranch}*:refs/remotes/origin/${currentBranch}*`
]
})
}
@ -380,32 +354,35 @@ export const getSHAForPullRequestEvent = async ({
'Failed to fetch pull request branch. Please ensure "persist-credentials" is set to "true" when checking out the repository. See: https://github.com/actions/checkout#usage'
)
}
core.debug('Fetching target branch...')
await gitFetch({
cwd: workingDirectory,
args: [
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
remoteName,
`+refs/heads/${github.context.payload.pull_request?.base?.ref}:refs/remotes/${remoteName}/${github.context.payload.pull_request?.base?.ref}`
]
})
if (diffSubmodule) {
await gitFetchSubmodules({
if (!inputs.sinceLastRemoteCommit) {
core.debug('Fetching target branch...')
await gitFetch({
cwd: workingDirectory,
args: [
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`
`--deepen=${inputs.fetchDepth}`,
'origin',
`+refs/heads/${targetBranch}:refs/remotes/origin/${targetBranch}`
]
})
if (hasSubmodule) {
await gitFetchSubmodules({
cwd: workingDirectory,
args: [
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`
]
})
}
}
} else {
if (diffSubmodule && inputs.fetchAdditionalSubmoduleHistory) {
if (hasSubmodule && inputs.fetchSubmoduleHistory) {
await gitFetchSubmodules({
cwd: workingDirectory,
args: [
@ -450,7 +427,10 @@ export const getSHAForPullRequestEvent = async ({
}
}
if (!github.context.payload.pull_request?.base?.ref) {
if (
!github.context.payload.pull_request?.base?.ref ||
github.context.payload.head?.repo?.fork === 'true'
) {
diff = '..'
}
@ -507,14 +487,17 @@ export const getSHAForPullRequestEvent = async ({
}
}
} else {
previousSha = github.context.payload.pull_request?.base?.sha
if (!previousSha) {
if (github.context.payload.action === 'closed') {
previousSha = github.context.payload.pull_request?.base?.sha
} else {
previousSha = await getRemoteBranchHeadSha({
cwd: workingDirectory,
remoteName,
branch: targetBranch
})
if (!previousSha) {
previousSha = github.context.payload.pull_request?.base?.sha
}
}
if (isShallow) {
@ -530,11 +513,7 @@ export const getSHAForPullRequestEvent = async ({
'Merge base is not in the local history, fetching remote target branch...'
)
for (
let i = 1;
i <= (inputs.fetchMissingHistoryMaxRetries || 10);
i++
) {
for (let i = 1; i <= 10; i++) {
await gitFetch({
cwd: workingDirectory,
args: [
@ -542,8 +521,8 @@ export const getSHAForPullRequestEvent = async ({
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
remoteName,
`+refs/heads/${targetBranch}:refs/remotes/${remoteName}/${targetBranch}`
'origin',
`+refs/heads/${targetBranch}:refs/remotes/origin/${targetBranch}`
]
})

View File

@ -1,29 +0,0 @@
import {Inputs} from './inputs'
export const DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS: Partial<Inputs> = {
sha: '',
baseSha: '',
since: '',
until: '',
path: '.',
quotepath: true,
diffRelative: true,
sinceLastRemoteCommit: false,
recoverDeletedFiles: false,
recoverDeletedFilesToDestination: '',
recoverFiles: '',
recoverFilesSeparator: '\n',
recoverFilesIgnore: '',
recoverFilesIgnoreSeparator: '\n',
includeAllOldNewRenamedFiles: false,
oldNewSeparator: ',',
oldNewFilesSeparator: ' ',
skipInitialFetch: false,
fetchAdditionalSubmoduleHistory: false,
dirNamesDeletedFilesIncludeOnlyDeletedDirs: false,
excludeSubmodules: false,
fetchMissingHistoryMaxRetries: 20,
usePosixPathSeparator: false,
tagsPattern: '*',
tagsIgnorePattern: ''
}

View File

@ -1,10 +1,13 @@
import * as core from '@actions/core'
export type Env = {
GITHUB_REF_NAME: string
GITHUB_REF: string
GITHUB_WORKSPACE: string
}
export const getEnv = async (): Promise<Env> => {
core.debug(`Process Env: ${JSON.stringify(process.env, null, 2)}`)
return {
GITHUB_REF_NAME: process.env.GITHUB_REF_NAME || '',
GITHUB_REF: process.env.GITHUB_REF || '',

View File

@ -24,7 +24,7 @@ export type Inputs = {
since: string
until: string
path: string
quotepath: boolean
quotePath: boolean
diffRelative: boolean
dirNames: boolean
dirNamesMaxDepth?: number
@ -34,9 +34,8 @@ export type Inputs = {
dirNamesDeletedFilesIncludeOnlyDeletedDirs: boolean
json: boolean
escapeJson: boolean
safeOutput: boolean
fetchDepth?: number
fetchAdditionalSubmoduleHistory: boolean
fetchSubmoduleHistory: boolean
sinceLastRemoteCommit: boolean
writeOutputFiles: boolean
outputDir: string
@ -53,12 +52,6 @@ export type Inputs = {
failOnInitialDiffError: boolean
failOnSubmoduleDiffError: boolean
negationPatternsFirst: boolean
useRestApi: boolean
excludeSubmodules: boolean
fetchMissingHistoryMaxRetries?: number
usePosixPathSeparator: boolean
tagsPattern: string
tagsIgnorePattern?: string
}
export const getInputs = (): Inputs => {
@ -137,7 +130,7 @@ export const getInputs = (): Inputs => {
const since = core.getInput('since', {required: false})
const until = core.getInput('until', {required: false})
const path = core.getInput('path', {required: false})
const quotepath = core.getBooleanInput('quotepath', {required: false})
const quotePath = core.getBooleanInput('quotepath', {required: false})
const diffRelative = core.getBooleanInput('diff_relative', {required: false})
const dirNames = core.getBooleanInput('dir_names', {required: false})
const dirNamesMaxDepth = core.getInput('dir_names_max_depth', {
@ -159,16 +152,8 @@ export const getInputs = (): Inputs => {
trimWhitespace: false
}
)
let json = core.getBooleanInput('json', {required: false})
let escapeJson = core.getBooleanInput('escape_json', {required: false})
const matrix = core.getBooleanInput('matrix', {required: false})
if (matrix) {
json = true
escapeJson = false
}
const safeOutput = core.getBooleanInput('safe_output', {required: false})
const json = core.getBooleanInput('json', {required: false})
const escapeJson = core.getBooleanInput('escape_json', {required: false})
const fetchDepth = core.getInput('fetch_depth', {required: false})
const sinceLastRemoteCommit = core.getBooleanInput(
'since_last_remote_commit',
@ -209,7 +194,7 @@ export const getInputs = (): Inputs => {
const skipInitialFetch = core.getBooleanInput('skip_initial_fetch', {
required: false
})
const fetchAdditionalSubmoduleHistory = core.getBooleanInput(
const fetchSubmoduleHistory = core.getBooleanInput(
'fetch_additional_submodule_history',
{
required: false
@ -241,35 +226,6 @@ export const getInputs = (): Inputs => {
}
)
const useRestApi = core.getBooleanInput('use_rest_api', {
required: false
})
const excludeSubmodules = core.getBooleanInput('exclude_submodules', {
required: false
})
const fetchMissingHistoryMaxRetries = core.getInput(
'fetch_missing_history_max_retries',
{required: false}
)
const usePosixPathSeparator = core.getBooleanInput(
'use_posix_path_separator',
{
required: false
}
)
const tagsPattern = core.getInput('tags_pattern', {
required: false,
trimWhitespace: false
})
const tagsIgnorePattern = core.getInput('tags_ignore_pattern', {
required: false,
trimWhitespace: false
})
const inputs: Inputs = {
files,
filesSeparator,
@ -294,7 +250,7 @@ export const getInputs = (): Inputs => {
since,
until,
path,
quotepath,
quotePath,
diffRelative,
sinceLastRemoteCommit,
recoverDeletedFiles,
@ -307,12 +263,8 @@ export const getInputs = (): Inputs => {
oldNewSeparator,
oldNewFilesSeparator,
skipInitialFetch,
fetchAdditionalSubmoduleHistory,
fetchSubmoduleHistory,
dirNamesDeletedFilesIncludeOnlyDeletedDirs,
excludeSubmodules,
usePosixPathSeparator,
tagsPattern,
tagsIgnorePattern,
// End Not Supported via REST API
dirNames,
dirNamesExcludeCurrentDir,
@ -320,18 +272,15 @@ export const getInputs = (): Inputs => {
dirNamesIncludeFilesSeparator,
json,
escapeJson,
safeOutput,
writeOutputFiles,
outputDir,
outputRenamedFilesAsDeletedAndAdded,
token,
apiUrl,
negationPatternsFirst,
useRestApi
negationPatternsFirst
}
if (fetchDepth) {
// Fallback to at least 2 if the fetch_depth is less than 2
inputs.fetchDepth = Math.max(parseInt(fetchDepth, 10), 2)
}
@ -339,13 +288,5 @@ export const getInputs = (): Inputs => {
inputs.dirNamesMaxDepth = parseInt(dirNamesMaxDepth, 10)
}
if (fetchMissingHistoryMaxRetries) {
// Fallback to at least 1 if the fetch_missing_history_max_retries is less than 1
inputs.fetchMissingHistoryMaxRetries = Math.max(
parseInt(fetchMissingHistoryMaxRetries, 10),
1
)
}
return inputs
}

View File

@ -26,8 +26,7 @@ import {
setOutput,
submoduleExists,
updateGitGlobalConfig,
verifyMinimumGitVersion,
warnUnsupportedRESTAPIInputs
verifyMinimumGitVersion
} from './utils'
const getChangedFilesFromLocalGitHistory = async ({
@ -45,15 +44,15 @@ const getChangedFilesFromLocalGitHistory = async ({
}): Promise<void> => {
await verifyMinimumGitVersion()
let quotepathValue = 'on'
let quotePathValue = 'on'
if (!inputs.quotepath) {
quotepathValue = 'off'
if (!inputs.quotePath) {
quotePathValue = 'off'
}
await updateGitGlobalConfig({
name: 'core.quotepath',
value: quotepathValue
value: quotePathValue
})
if (inputs.diffRelative) {
@ -64,26 +63,14 @@ const getChangedFilesFromLocalGitHistory = async ({
}
const isShallow = await isRepoShallow({cwd: workingDirectory})
let diffSubmodule = false
let gitFetchExtraArgs = ['--no-tags', '--prune']
if (inputs.excludeSubmodules) {
core.info('Excluding submodules from the diff')
} else {
diffSubmodule = await submoduleExists({cwd: workingDirectory})
}
if (diffSubmodule) {
gitFetchExtraArgs.push('--recurse-submodules')
}
const hasSubmodule = await submoduleExists({cwd: workingDirectory})
let gitFetchExtraArgs = ['--no-tags', '--prune', '--recurse-submodules']
const isTag = env.GITHUB_REF?.startsWith('refs/tags/')
const remoteName = 'origin'
const outputRenamedFilesAsDeletedAndAdded =
inputs.outputRenamedFilesAsDeletedAndAdded
let submodulePaths: string[] = []
if (diffSubmodule) {
if (hasSubmodule) {
submodulePaths = await getSubmodulePath({cwd: workingDirectory})
}
@ -95,30 +82,29 @@ const getChangedFilesFromLocalGitHistory = async ({
if (!github.context.payload.pull_request?.base?.ref) {
core.info(`Running on a ${github.context.eventName || 'push'} event...`)
diffResult = await getSHAForNonPullRequestEvent({
diffResult = await getSHAForNonPullRequestEvent(
inputs,
env,
workingDirectory,
isShallow,
diffSubmodule,
hasSubmodule,
gitFetchExtraArgs,
isTag,
remoteName
})
isTag
)
} else {
core.info(
`Running on a ${github.context.eventName || 'pull_request'} (${
github.context.payload.action
}) event...`
)
diffResult = await getSHAForPullRequestEvent({
diffResult = await getSHAForPullRequestEvent(
inputs,
env,
workingDirectory,
isShallow,
diffSubmodule,
gitFetchExtraArgs,
remoteName
})
hasSubmodule,
gitFetchExtraArgs
)
}
if (diffResult.initialCommit) {
@ -133,11 +119,11 @@ const getChangedFilesFromLocalGitHistory = async ({
const allDiffFiles = await getAllDiffFiles({
workingDirectory,
diffSubmodule,
hasSubmodule,
diffResult,
submodulePaths,
outputRenamedFilesAsDeletedAndAdded,
fetchAdditionalSubmoduleHistory: inputs.fetchAdditionalSubmoduleHistory,
fetchSubmoduleHistory: inputs.fetchSubmoduleHistory,
failOnInitialDiffError: inputs.failOnInitialDiffError,
failOnSubmoduleDiffError: inputs.failOnSubmoduleDiffError
})
@ -159,7 +145,7 @@ const getChangedFilesFromLocalGitHistory = async ({
deletedFiles: allDiffFiles[ChangeTypeEnum.Deleted],
recoverPatterns,
diffResult,
diffSubmodule,
hasSubmodule,
submodulePaths
})
}
@ -177,7 +163,7 @@ const getChangedFilesFromLocalGitHistory = async ({
const allOldNewRenamedFiles = await getRenamedFiles({
inputs,
workingDirectory,
diffSubmodule,
hasSubmodule,
diffResult,
submodulePaths
})
@ -187,8 +173,7 @@ const getChangedFilesFromLocalGitHistory = async ({
value: allOldNewRenamedFiles.paths,
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
safeOutput: inputs.safeOutput
json: inputs.json
})
await setOutput({
key: 'all_old_new_renamed_files_count',
@ -234,9 +219,11 @@ export async function run(): Promise<void> {
const inputs = getInputs()
core.debug(`Inputs: ${JSON.stringify(inputs, null, 2)}`)
core.debug(`Github Context: ${JSON.stringify(github.context, null, 2)}`)
const workingDirectory = path.resolve(
env.GITHUB_WORKSPACE || process.cwd(),
inputs.useRestApi ? '.' : inputs.path
inputs.path
)
core.debug(`Working directory: ${workingDirectory}`)
@ -255,19 +242,35 @@ export async function run(): Promise<void> {
})
core.debug(`Yaml file patterns: ${JSON.stringify(yamlFilePatterns)}`)
if (inputs.useRestApi && !github.context.payload.pull_request?.number) {
throw new Error(
"Only pull_request* events are supported when using GitHub's REST API."
)
}
if (
inputs.token &&
github.context.payload.pull_request?.number &&
(!hasGitDirectory || inputs.useRestApi)
!hasGitDirectory
) {
core.info("Using GitHub's REST API to get changed files")
await warnUnsupportedRESTAPIInputs({inputs})
const unsupportedInputs: (keyof Inputs)[] = [
'sha',
'baseSha',
'since',
'until',
'sinceLastRemoteCommit',
'recoverDeletedFiles',
'recoverDeletedFilesToDestination',
'recoverFiles',
'recoverFilesIgnore',
'includeAllOldNewRenamedFiles',
'skipInitialFetch',
'fetchSubmoduleHistory',
'dirNamesDeletedFilesIncludeOnlyDeletedDirs'
]
for (const input of unsupportedInputs) {
if (inputs[input]) {
core.warning(
`Input "${input}" is not supported when using GitHub's REST API to get changed files`
)
}
}
await getChangedFilesFromRESTAPI({
inputs,
filePatterns,
@ -275,9 +278,10 @@ export async function run(): Promise<void> {
})
} else {
if (!hasGitDirectory) {
throw new Error(
`Unable to locate the git repository in the given path: ${workingDirectory}.\n Please run actions/checkout before this action (Make sure the 'path' input is correct).\n If you intend to use Github's REST API note that only pull_request* events are supported. Current event is "${github.context.eventName}".`
core.setFailed(
"Can't find local .git directory. Please run actions/checkout before this action"
)
return
}
core.info('Using local .git directory')
@ -291,8 +295,10 @@ export async function run(): Promise<void> {
}
}
// eslint-disable-next-line github/no-then
run().catch(e => {
core.setFailed(e.message || e)
process.exit(1)
})
/* istanbul ignore if */
if (!process.env.TESTING) {
// eslint-disable-next-line github/no-then
run().catch(e => {
core.setFailed(e.message || e)
})
}

View File

@ -3,14 +3,14 @@ import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as github from '@actions/github'
import {createReadStream, promises as fs} from 'fs'
import {flattenDeep, snakeCase} from 'lodash'
import {readFile} from 'fs/promises'
import {flattenDeep} from 'lodash'
import mm from 'micromatch'
import * as path from 'path'
import {createInterface} from 'readline'
import {parseDocument} from 'yaml'
import {ChangedFiles, ChangeTypeEnum} from './changedFiles'
import {DiffResult} from './commitSha'
import {DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS} from './constant'
import {Inputs} from './inputs'
const MINIMUM_GIT_VERSION = '2.18.0'
@ -32,13 +32,11 @@ export const normalizeSeparators = (p: string): string => {
// Remove redundant slashes
const isUnc = /^\\\\+[^\\]/.test(p) // e.g. \\hello
p = (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\') // preserve leading \\ for UNC
} else {
// Remove redundant slashes on Linux/macOS
p = p.replace(/\/\/+/g, '/')
return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\') // preserve leading \\ for UNC
}
return p
// Remove redundant slashes
return p.replace(/\/\/+/g, '/')
}
/**
@ -173,16 +171,15 @@ async function* lineOfFileGenerator({
input: fileStream,
crlfDelay: Infinity
})
for await (let line of rl) {
for await (const line of rl) {
if (!line.startsWith('#') && line !== '') {
if (excludedFiles) {
line = line.startsWith('!') ? line : `!${line}`
if (line.endsWith(path.sep)) {
line = `${line}**`
if (line.startsWith('!')) {
yield line
} else {
yield `!${line}`
}
yield line
} else {
line = line.endsWith(path.sep) ? `${line}**` : line
yield line
}
}
@ -288,7 +285,6 @@ export const submoduleExists = async ({
* Fetches the git repository
* @param args - arguments for fetch command
* @param cwd - working directory
* @returns exit code
*/
export const gitFetch = async ({
args,
@ -337,7 +333,6 @@ export const gitFetchSubmodules = async ({
/**
* Retrieves all the submodule paths
* @param cwd - working directory
* @returns submodule paths
*/
export const getSubmodulePath = async ({
cwd
@ -372,7 +367,6 @@ export const getSubmodulePath = async ({
* @param parentSha2 - parent commit sha
* @param submodulePath - path of submodule
* @param diff - diff type between parent commits (`..` or `...`)
* @returns commit sha of submodule
*/
export const gitSubmoduleDiffSHA = async ({
cwd,
@ -687,16 +681,14 @@ export const isInsideWorkTree = async ({
export const getRemoteBranchHeadSha = async ({
cwd,
branch,
remoteName
branch
}: {
cwd: string
branch: string
remoteName: string
}): Promise<string> => {
const {stdout} = await exec.getExecOutput(
'git',
['rev-parse', `${remoteName}/${branch}`],
['rev-parse', `origin/${branch}`],
{
cwd,
silent: !core.isDebug()
@ -831,80 +823,41 @@ export const cleanShaInput = async ({
return stdout.trim()
}
export const getPreviousGitTag = async ({
cwd,
tagsPattern,
currentBranch,
tagsIgnorePattern
cwd
}: {
cwd: string
tagsPattern: string
currentBranch: string
tagsIgnorePattern?: string
}): Promise<{tag: string; sha: string}> => {
const ignorePatterns: string[] = []
let currentShaDate: Date | null = null
const {stdout} = await exec.getExecOutput(
'git',
[
'tag',
'--sort=-creatordate',
'--format=%(refname:short)|%(objectname)|%(creatordate:iso)'
],
['tag', '--sort=-creatordate'],
{
cwd,
silent: !core.isDebug()
}
)
if (tagsIgnorePattern) {
ignorePatterns.push(tagsIgnorePattern)
}
if (currentBranch) {
ignorePatterns.push(currentBranch)
try {
const {stdout: currentShaDateOutput} = await exec.getExecOutput(
'git',
['show', '-s', '--format=%ai', currentBranch],
{
cwd,
silent: !core.isDebug()
}
)
currentShaDate = new Date(currentShaDateOutput.trim())
} catch (error) {
// Handle the case where the current branch doesn't exist
// This might happen in detached head state
core.warning(`Failed to get date for current branch ${currentBranch}`)
}
}
const previousTag: {tag: string; sha: string} = {tag: '', sha: ''}
const tags = stdout.trim().split('\n')
for (const tagData of tags) {
const [tag, sha, dateString] = tagData.split('|')
if (!mm.isMatch(tag, tagsPattern) || mm.isMatch(tag, ignorePatterns)) {
continue
}
const date = new Date(dateString)
if (currentShaDate && date >= currentShaDate) {
continue
}
// Found a suitable tag, no need to continue
previousTag.tag = tag
previousTag.sha = sha
break
}
if (!previousTag.tag) {
if (tags.length < 2) {
core.warning('No previous tag found')
return {tag: '', sha: ''}
}
return previousTag
const previousTag = tags[1]
const {stdout: stdout2} = await exec.getExecOutput(
'git',
['rev-parse', previousTag],
{
cwd,
silent: !core.isDebug()
}
)
const sha = stdout2.trim()
return {tag: previousTag, sha}
}
export const canDiffCommits = async ({
@ -945,7 +898,7 @@ export const canDiffCommits = async ({
} else {
const {exitCode, stderr} = await exec.getExecOutput(
'git',
['diff', '--no-patch', sha1, sha2],
['diff', '--quiet', sha1, sha2],
{
cwd,
ignoreReturnCode: true,
@ -1042,7 +995,6 @@ export const getFilePatterns = async ({
if (inputs.files) {
const filesPatterns = inputs.files
.split(inputs.filesSeparator)
.map(p => (p.endsWith(path.sep) ? `${p}**` : p))
.filter(Boolean)
cleanedFilePatterns.push(...filesPatterns)
@ -1074,9 +1026,8 @@ export const getFilePatterns = async ({
.split(inputs.filesIgnoreSeparator)
.filter(Boolean)
.map(p => {
p = p.startsWith('!') ? p : `!${p}`
if (p.endsWith(path.sep)) {
p = `${p}**`
if (!p.startsWith('!')) {
p = `!${p}`
}
return p
})
@ -1177,7 +1128,7 @@ const getYamlFilePatternsFromContents = async ({
throw new Error(`File does not exist: ${filePath}`)
}
source = await fs.readFile(filePath, 'utf8')
source = await readFile(filePath, 'utf8')
} else {
source = content
}
@ -1258,11 +1209,16 @@ export const getYamlFilePatterns = async ({
const newFilePatterns = await getYamlFilePatternsFromContents({filePath})
for (const key in newFilePatterns) {
if (key in filePatterns) {
filePatterns[key] = [...filePatterns[key], ...newFilePatterns[key]]
} else {
filePatterns[key] = newFilePatterns[key]
core.warning(
`files_yaml_from_source_file: Duplicated key ${key} detected in ${filePath}, the ${filePatterns[key]} will be overwritten by ${newFilePatterns[key]}.`
)
}
}
filePatterns = {
...filePatterns,
...newFilePatterns
}
}
}
@ -1274,12 +1230,9 @@ export const getYamlFilePatterns = async ({
for (const key in newIgnoreFilePatterns) {
if (key in filePatterns) {
filePatterns[key] = [
...filePatterns[key],
...newIgnoreFilePatterns[key]
]
} else {
filePatterns[key] = newIgnoreFilePatterns[key]
core.warning(
`files_ignore_yaml: Duplicated key ${key} detected, the ${filePatterns[key]} will be overwritten by ${newIgnoreFilePatterns[key]}.`
)
}
}
}
@ -1303,14 +1256,16 @@ export const getYamlFilePatterns = async ({
for (const key in newIgnoreFilePatterns) {
if (key in filePatterns) {
filePatterns[key] = [
...filePatterns[key],
...newIgnoreFilePatterns[key]
]
} else {
filePatterns[key] = newIgnoreFilePatterns[key]
core.warning(
`files_ignore_yaml_from_source_file: Duplicated key ${key} detected in ${filePath}, the ${filePatterns[key]} will be overwritten by ${newIgnoreFilePatterns[key]}.`
)
}
}
filePatterns = {
...filePatterns,
...newIgnoreFilePatterns
}
}
}
@ -1369,8 +1324,7 @@ export const setArrayOutput = async ({
writeOutputFiles: inputs.writeOutputFiles,
outputDir: inputs.outputDir,
json: inputs.json,
shouldEscape: inputs.escapeJson,
safeOutput: inputs.safeOutput
shouldEscape: inputs.escapeJson
})
}
@ -1380,8 +1334,7 @@ export const setOutput = async ({
writeOutputFiles,
outputDir,
json = false,
shouldEscape = false,
safeOutput = false
shouldEscape = false
}: {
key: string
value: string | string[] | boolean
@ -1389,7 +1342,6 @@ export const setOutput = async ({
outputDir: string
json?: boolean
shouldEscape?: boolean
safeOutput?: boolean
}): Promise<void> => {
let cleanedValue
if (json) {
@ -1398,11 +1350,6 @@ export const setOutput = async ({
cleanedValue = value.toString().trim()
}
// if safeOutput is true, escape special characters for bash shell
if (safeOutput) {
cleanedValue = cleanedValue.replace(/[^\x20-\x7E]|[:*?<>|;`$()&!]/g, '\\$&')
}
core.setOutput(key, cleanedValue)
if (writeOutputFiles) {
@ -1450,7 +1397,7 @@ export const recoverDeletedFiles = async ({
deletedFiles,
recoverPatterns,
diffResult,
diffSubmodule,
hasSubmodule,
submodulePaths
}: {
inputs: Inputs
@ -1458,7 +1405,7 @@ export const recoverDeletedFiles = async ({
deletedFiles: string[]
recoverPatterns: string[]
diffResult: DiffResult
diffSubmodule: boolean
hasSubmodule: boolean
submodulePaths: string[]
}): Promise<void> => {
let recoverableDeletedFiles = deletedFiles
@ -1488,7 +1435,7 @@ export const recoverDeletedFiles = async ({
const submodulePath = submodulePaths.find(p => deletedFile.startsWith(p))
if (diffSubmodule && submodulePath) {
if (hasSubmodule && submodulePath) {
const submoduleShaResult = await gitSubmoduleDiffSHA({
cwd: workingDirectory,
parentSha1: diffResult.previousSha,
@ -1536,12 +1483,6 @@ export const recoverDeletedFiles = async ({
}
}
/**
* Determines whether the specified working directory has a local Git directory.
*
* @param workingDirectory - The path of the working directory.
* @returns A boolean value indicating whether the working directory has a local Git directory.
*/
export const hasLocalGitDirectory = async ({
workingDirectory
}: {
@ -1551,33 +1492,3 @@ export const hasLocalGitDirectory = async ({
cwd: workingDirectory
})
}
/**
* Warns about unsupported inputs when using the REST API.
*
* @param inputs - The inputs object.
*/
export const warnUnsupportedRESTAPIInputs = async ({
inputs
}: {
inputs: Inputs
}): Promise<void> => {
for (const key of Object.keys(DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS)) {
const defaultValue = Object.hasOwnProperty.call(
DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS,
key
)
? DEFAULT_VALUES_OF_UNSUPPORTED_API_INPUTS[
key as keyof Inputs
]?.toString()
: ''
if (defaultValue !== inputs[key as keyof Inputs]?.toString()) {
core.warning(
`Input "${snakeCase(
key
)}" is not supported when using GitHub's REST API to get changed files`
)
}
}
}

View File

@ -1 +0,0 @@
This is a test markdown file

View File

@ -1 +1 @@
This is a test file...
This is a test file.

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */

2880
yarn.lock

File diff suppressed because it is too large Load Diff