Compare commits

...

86 Commits

Author SHA1 Message Date
tj-actions[bot]
e1754a427f Updated README.md (#1274)
Co-authored-by: repo-ranger[bot] <repo-ranger[bot]@users.noreply.github.com>
2023-06-17 03:30:45 +00:00
Tonye Jack
f573054697 feat: add support for returning changed file counts (#1273)
Co-authored-by: GitHub Action <action@github.com>
2023-06-17 03:13:40 +00:00
Tonye Jack
c3c3db7fee feat: move deleted file recovery to leverage filter (#1272) 2023-06-16 20:33:42 -06:00
renovate[bot]
480e87dd66 chore(deps): lock file maintenance (#1271)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-16 20:33:22 -06:00
tj-actions[bot]
7fcd53ac00 Updated README.md (#1270)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-16 19:40:34 -06:00
Tonye Jack
749fe3bb28 Merge branch 'feat/add-support-for-recovering-deleted-files' 2023-06-16 19:01:25 -06:00
Tonye Jack
d7af20bab3 Update README.md 2023-06-16 18:59:17 -06:00
Tonye Jack
690b721958 Update README.md 2023-06-16 18:57:56 -06:00
Tonye Jack
77f9e6c7c6 feat: add support for recovering deleted files (#1269)
Co-authored-by: GitHub Action <action@github.com>
2023-06-17 00:57:12 +00:00
Tonye Jack
c82a34e7e5 Updated the test 2023-06-16 18:44:56 -06:00
Tonye Jack
7a1c64e8b1 Updated the test 2023-06-16 18:30:35 -06:00
Tonye Jack
71290f02ff Updated dist assets 2023-06-16 18:25:34 -06:00
Tonye Jack
ecf455a884 Updated test 2023-06-16 18:25:09 -06:00
Tonye Jack
432e0c810c Removed test file 2023-06-16 18:25:09 -06:00
Tonye Jack
fcdeb5b3d7 Added deleted file 2023-06-16 18:25:09 -06:00
GitHub Action
01e83d6024 Added missing changes and modified dist assets. 2023-06-16 23:54:47 +00:00
Tonye Jack
c706c70eed Merge d4f86e9d16 into 0621d936c0 2023-06-16 17:53:39 -06:00
Tonye Jack
d4f86e9d16 Merge branch 'main' into feat/add-support-for-recovering-deleted-files 2023-06-16 17:53:37 -06:00
Tonye Jack
d9105a4631 feat: add support for recovering deleted files 2023-06-16 17:52:27 -06:00
renovate[bot]
0621d936c0 chore(deps): update dependency eslint to v8.43.0 (#1268)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-16 23:08:47 +00:00
Tonye Jack
024cd58ac6 Update README.md 2023-06-16 11:27:13 -06:00
Tonye Jack
c9a1c56f6d Update README.md 2023-06-16 01:37:49 -06:00
tj-actions[bot]
54a8c99a03 Upgraded to v36.3.0 (#1267)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-16 07:06:33 +00:00
tj-actions[bot]
9bf09145c3 Updated README.md (#1266)
Co-authored-by: repo-ranger[bot] <repo-ranger[bot]@users.noreply.github.com>
2023-06-16 06:35:24 +00:00
Tonye Jack
c25c77a67a feat: add support for complex filters (#1265)
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: tj-actions[bot] <109116665+tj-actions-bot@users.noreply.github.com>
2023-06-16 06:17:13 +00:00
Tonye Jack
ea90b5ced9 chore: update test.yml 2023-06-15 12:33:00 -06:00
tj-actions[bot]
d144c0c92d Updated README.md (#1264)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2023-06-15 17:01:34 +00:00
Tonye Jack
341b80da8b Update README.md 2023-06-15 09:07:39 -06:00
Tonye Jack
6cf9c8246e chore: move check out of loop 2023-06-14 19:45:42 -06:00
renovate[bot]
955946132d chore(deps): lock file maintenance (#1263)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 21:07:00 +00:00
tj-actions[bot]
1f2cb3b00f Upgraded to v36.2.1 (#1262)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-14 20:46:50 +00:00
tj-actions[bot]
c9124514c3 Updated README.md (#1261)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-14 14:01:14 -06:00
Tonye Jack
90ef0b1b22 feat: add support for outputting renamed files as deleted and added (#1260)
Co-authored-by: GitHub Action <action@github.com>
2023-06-14 13:59:31 -06:00
tj-actions[bot]
c648759d89 Upgraded to v36.2.0 (#1258)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-14 19:37:43 +00:00
Tonye Jack
b9ea510e42 chore: rename git fetch arguments (#1259)
Co-authored-by: GitHub Action <action@github.com>
2023-06-14 13:22:47 -06:00
Tonye Jack
174a2a6360 feat: switch to use name status (#1230)
Co-authored-by: tj-actions[bot] <109116665+tj-actions-bot@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2023-06-14 12:45:32 -06:00
renovate[bot]
2d0b52f440 chore(deps): update peter-evans/create-pull-request action to v5.0.2 (#1256)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 02:19:30 +00:00
renovate[bot]
d0e3a7c3aa chore(deps): update typescript-eslint monorepo to v5.59.11 (#1253)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 00:45:47 +00:00
tj-actions[bot]
2c6893c21a Updated README.md (#1255)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-12 18:13:36 -06:00
Tonye Jack
17ca5bb3e5 Update action.yml 2023-06-12 18:07:35 -06:00
renovate[bot]
61845c2b19 chore(deps): lock file maintenance (#1252)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-12 01:50:52 +00:00
renovate[bot]
417f924dea chore(deps): update tj-actions/verify-changed-files action to v15 (#1251)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-11 06:22:47 +00:00
renovate[bot]
c51a48d4f6 chore(deps): lock file maintenance (#1250)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-11 02:36:09 +00:00
tj-actions[bot]
a625ca325f Updated README.md (#1249)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-10 17:31:27 +00:00
tj-actions[bot]
752970edd0 Updated README.md (#1248)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
Co-authored-by: Tonye Jack <jtonye@ymail.com>
2023-06-10 11:02:12 -06:00
Tonye Jack
7b64c76932 Update action.yml 2023-06-10 10:57:00 -06:00
Tonye Jack
6d9ee62035 chore: Update README.md 2023-06-09 12:17:49 -06:00
Tonye Jack
b27dcc252a chore: Update README.md 2023-06-09 12:16:46 -06:00
renovate[bot]
b60e479cea chore(deps): update dependency @types/uuid to v9.0.2 (#1247)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 00:14:45 +00:00
tj-actions[bot]
ab8493166b Upgraded to v36.1.0 (#1245)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-08 14:45:51 +00:00
tj-actions[bot]
9333a5cf0c Updated README.md (#1246)
Co-authored-by: repo-ranger[bot] <repo-ranger[bot]@users.noreply.github.com>
2023-06-08 14:26:50 +00:00
tj-actions[bot]
8ec721eb3b chore: Update README.md (#1237)
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-08 13:31:33 +00:00
tj-actions[bot]
7d1d4d2cce chore: Update README.md (#1240) 2023-06-08 13:30:09 +00:00
Tonye Jack
fb20f4d248 chore: fix bug with nx set shas (#1244) 2023-06-08 06:56:26 -06:00
Tonye Jack
b2a0ba40a4 chore: update test (#1243) 2023-06-08 06:25:07 -06:00
Tonye Jack
c467712045 chore: update event name (#1242)
Co-authored-by: GitHub Action <action@github.com>
2023-06-08 06:12:03 -06:00
Tonye Jack
f41e41fa3f feat: improve warning message (#1241)
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-08 05:20:11 -06:00
tj-actions[bot]
f490eeaa59 chore: update test.yml 2023-06-08 05:11:10 -06:00
Tonye Jack
37e5be95e2 Update test.yml 2023-06-07 19:05:54 -06:00
Tonye Jack
e208eb429a fix: bug with errors from fork prs (#1239)
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2023-06-08 00:29:48 +00:00
Tonye Jack
c784b6f1c4 chore: improve test coverage (#1235)
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-07 23:13:00 +00:00
Tonye Jack
6dc4095801 fix: bug with only_(changed|modified|deleted) outputs (#1238)
Co-authored-by: GitHub Action <action@github.com>
2023-06-07 22:56:42 +00:00
tj-actions[bot]
a522bdb715 Upgraded to v36.0.18 (#1234)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-06 14:07:38 +00:00
tj-actions[bot]
07e0177b72 Updated README.md (#1233)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-06 07:45:21 -06:00
tj-actions[bot]
fee9327009 Updated README.md (#1232)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-06 07:24:46 -06:00
Tonye Jack
f991633730 Update action.yml 2023-06-06 06:48:25 -06:00
tj-actions[bot]
1fc4377f03 Updated README.md (#1231)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-06 12:19:39 +00:00
Tonye Jack
353ea22e6f feat: add dir_names_exclude_current_dir input and cleaned up logic to retrieve the current sha (#1229)
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: tj-actions[bot] <109116665+tj-actions-bot@users.noreply.github.com>
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-06 06:00:56 -06:00
tj-actions[bot]
cdf9afcec8 Updated README.md (#1228)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-06 00:29:02 +00:00
Tonye Jack
f58fe58af9 Update README.md 2023-06-05 18:04:41 -06:00
Tonye Jack
9ab423063b Update action.yml 2023-06-05 18:01:34 -06:00
renovate[bot]
b8dd3a1a06 chore(deps): update typescript-eslint monorepo to v5.59.9 (#1227)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-05 21:24:08 +00:00
tj-actions[bot]
6e4b6b77a3 Upgraded to v36.0.17 (#1226)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-05 04:13:36 +00:00
Tonye Jack
b13786805a chore: update README.md (#1225)
Co-authored-by: GitHub Action <action@github.com>
2023-06-04 21:51:28 -06:00
renovate[bot]
7c72320404 chore(deps): lock file maintenance (#1224)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tonye Jack <jtonye@ymail.com>
Co-authored-by: GitHub Action <action@github.com>
2023-06-04 21:46:30 -06:00
Tonye Jack
763a7bfbb5 chore: Update test.yml (#1223)
Co-authored-by: tj-actions[bot] <109116665+tj-actions-bot@users.noreply.github.com>
2023-06-04 20:09:02 -06:00
tj-actions[bot]
c789aecfa6 Upgraded to v36.0.16 (#1222)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-04 16:48:50 +00:00
renovate[bot]
1aae16084a chore(deps): lock file maintenance (#1221)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-03 01:21:45 +00:00
renovate[bot]
a593948c90 chore(deps): update dependency eslint to v8.42.0 (#1220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-03 01:07:36 +00:00
tj-actions[bot]
96134b7430 Upgraded to v36.0.15 (#1219)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
2023-06-02 13:53:01 +00:00
renovate[bot]
5d2fcdb4cb chore(deps): update dependency typescript to v5.1.3 (#1215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-02 04:39:26 +00:00
renovate[bot]
c0a8bcfa6a chore(deps): update dependency eslint-plugin-github to v4.8.0 (#1218)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-02 04:19:39 +00:00
renovate[bot]
4bc117de0c chore(deps): lock file maintenance (#1217)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-02 03:47:13 +00:00
Tonye Jack
47db5bd435 fix: bug retrieving base sha for force push (#1216) 2023-06-01 21:16:31 -06:00
tj-actions[bot]
eeb5a258f5 Upgraded to v36.0.14 (#1214)
Co-authored-by: jackton1 <jackton1@users.noreply.github.com>
Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com>
2023-06-01 17:57:50 +00:00
Tonye Jack
5436326dcf Update README.md 2023-06-01 11:29:04 -06:00
22 changed files with 35074 additions and 7263 deletions

View File

@@ -60,6 +60,8 @@
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"no-shadow": "off",
"@typescript-eslint/no-shadow": "error",
"semi": "off",
"filenames/match-regex": [
"error",

View File

@@ -19,7 +19,7 @@ jobs:
git submodule update --remote --recursive
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5.0.1
uses: peter-evans/create-pull-request@v5.0.2
with:
title: "Updated submodule"
labels: "merge when passing"

View File

@@ -24,7 +24,7 @@ jobs:
- name: Run git-cliff
uses: tj-actions/git-cliff@v1
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5.0.1
uses: peter-evans/create-pull-request@v5.0.2
with:
base: "main"
labels: "merge when passing"

View File

@@ -4,14 +4,31 @@ on:
push:
branches:
- "**"
pull_request:
branches:
- main
- sec
pull_request_review:
types: [edited, dismissed, submitted]
pull_request_target:
pull_request:
types:
- assigned
- unassigned
- labeled
- unlabeled
- opened
- edited
- closed
- reopened
- synchronize
- converted_to_draft
- ready_for_review
- locked
- unlocked
- review_requested
- review_request_removed
- auto_merge_enabled
- auto_merge_disabled
branches:
- main
- sec
jobs:
shellcheck:
@@ -19,7 +36,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
- name: shellcheck
uses: reviewdog/action-shellcheck@v1.17
@@ -31,6 +48,7 @@ jobs:
with:
persist-credentials: false
fetch-depth: 0
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Use Node.js 16.x
uses: actions/setup-node@v3.6.0
@@ -49,7 +67,7 @@ jobs:
- name: Run eslint on changed files
uses: tj-actions/eslint-changed-files@v19
if: github.event_name != 'push'
if: github.event_name == 'pull_request'
with:
token: ${{ secrets.PAT_TOKEN }}
config_path: ".eslintrc.json"
@@ -60,16 +78,16 @@ jobs:
yarn all
- name: Verify Changed files
uses: tj-actions/verify-changed-files@v14
uses: tj-actions/verify-changed-files@v15
id: changed_files
if: github.event_name != 'push'
if: github.event_name == 'pull_request'
with:
files: |
src
dist
- name: Commit files
if: steps.changed_files.outputs.files_changed == 'true' && github.event_name != 'push'
if: steps.changed_files.outputs.files_changed == 'true' && github.event_name == 'pull_request'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
@@ -78,6 +96,7 @@ jobs:
- name: Push changes
if: steps.changed_files.outputs.files_changed == 'true' && github.event_name == 'pull_request'
continue-on-error: true
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.PAT_TOKEN }}
@@ -104,6 +123,7 @@ jobs:
- name: Checkout into dir1
uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: true
fetch-depth: 0
path: dir1
@@ -136,6 +156,7 @@ jobs:
- name: Checkout into dir2
uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
submodules: true
fetch-depth: 0
path: dir2
@@ -167,9 +188,10 @@ jobs:
if: github.event_name == 'push'
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0
- name: Download build assets
@@ -223,9 +245,10 @@ jobs:
needs: build
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0
- name: Download build assets
@@ -259,9 +282,10 @@ jobs:
needs: build
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0
- name: Download build assets
@@ -294,9 +318,10 @@ jobs:
input-fetch_depth: [1, 50]
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: ${{ matrix.fetch-depth }}
- name: Download build assets
@@ -323,7 +348,7 @@ jobs:
if: github.event_name != 'push'
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
@@ -355,11 +380,12 @@ jobs:
fetch-depth: [1, 2, 0]
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
fetch-depth: ${{ matrix.fetch-depth }}
persist-credentials: false
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Download build assets
uses: actions/download-artifact@v3
@@ -382,7 +408,7 @@ jobs:
needs: build
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
- name: Download build assets
@@ -435,7 +461,7 @@ jobs:
needs: build
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
- name: Download build assets
@@ -493,7 +519,7 @@ jobs:
fetch-depth: [0, 1, 2]
steps:
- name: Checkout to branch
- name: Checkout branch
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
@@ -524,6 +550,205 @@ jobs:
echo "${{ toJSON(steps.changed-files.outputs) }}"
shell:
bash
test-yaml:
name: Test changed-files with yaml
runs-on: ubuntu-latest
needs: build
strategy:
fail-fast: false
max-parallel: 4
matrix:
fetch-depth: [0, 1, 2]
steps:
- name: Checkout branch
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
submodules: recursive
fetch-depth: ${{ matrix.fetch-depth }}
- name: Download build assets
uses: actions/download-artifact@v3
with:
name: build-assets
- name: Run changed-files with files_yaml
id: changed-files
uses: ./
with:
files_yaml: |
test:
- test/**.txt
- test/**.md
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files.outputs) }}"
shell:
bash
- name: Run changed-files with files_yaml_from_source_file
id: changed-files-from-source-file
uses: ./
with:
files_yaml_from_source_file: |
test/changed-files.yml
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-from-source-file.outputs) }}"
shell:
bash
test_recover_deleted_file:
name: Test changed-files recover deleted file
runs-on: ubuntu-latest
needs: build
strategy:
fail-fast: false
max-parallel: 4
matrix:
fetch-depth: [0, 1, 2]
steps:
- name: Checkout branch
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
submodules: recursive
fetch-depth: ${{ matrix.fetch-depth }}
- name: Download build assets
uses: actions/download-artifact@v3
with:
name: build-assets
- name: Run changed-files with recover_deleted_files
id: changed-files-recover-deleted-files
uses: ./
with:
base_sha: "fcdeb5b3d797752d95f6dbe98552a95c29dad338"
sha: "432e0c810c60ef1332850a971c5ec39022034b4c"
recover_deleted_files: true
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-recover-deleted-files.outputs) }}"
shell:
bash
- name: Verify deleted files
if: steps.changed-files-recover-deleted-files.outputs.deleted_files != 'test/test deleted.txt'
run: |
echo "Expected: (test/test deleted.txt) got ${{ steps.changed-files-recover-deleted-files.outputs.deleted_files }}"
exit 1
- name: Verify that test/test deleted.txt is restored
run: |
if [ ! -f "test/test deleted.txt" ]; then
echo "Expected: (test/test deleted.txt) to exist"
exit 1
else
cat "test/test deleted.txt"
rm "test/test deleted.txt"
fi
- name: Run changed-files with recover_deleted_files and files input
id: changed-files-recover-deleted-files-with-files
uses: ./
with:
base_sha: "fcdeb5b3d797752d95f6dbe98552a95c29dad338"
sha: "432e0c810c60ef1332850a971c5ec39022034b4c"
files: |
test
recover_deleted_files: true
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-recover-deleted-files-with-files.outputs) }}"
shell:
bash
- name: Verify deleted files
if: steps.changed-files-recover-deleted-files-with-files.outputs.deleted_files != 'test/test deleted.txt'
run: |
echo "Expected: (test/test deleted.txt) got ${{ steps.changed-files-recover-deleted-files-with-files.outputs.deleted_files }}"
exit 1
- name: Verify that test/test deleted.txt is restored
run: |
if [ ! -f "test/test deleted.txt" ]; then
echo "Expected: (test/test deleted.txt) to exist"
exit 1
else
cat "test/test deleted.txt"
rm "test/test deleted.txt"
fi
- name: Run changed-files with recover_deleted_files and files_yaml input
id: changed-files-recover-deleted-files-with-files-yaml
uses: ./
with:
base_sha: "fcdeb5b3d797752d95f6dbe98552a95c29dad338"
sha: "432e0c810c60ef1332850a971c5ec39022034b4c"
files_yaml: |
test:
- test/**.txt
- test/**.md
recover_deleted_files: true
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-recover-deleted-files-with-files-yaml.outputs) }}"
shell:
bash
- name: Verify deleted files
if: steps.changed-files-recover-deleted-files-with-files-yaml.outputs.test_deleted_files != 'test/test deleted.txt'
run: |
echo "Expected: (test/test deleted.txt) got ${{ steps.changed-files-recover-deleted-files-with-files-yaml.outputs.test_deleted_files }}"
exit 1
- name: Verify that test/test deleted.txt is restored
run: |
if [ ! -f "test/test deleted.txt" ]; then
echo "Expected: (test/test deleted.txt) to exist"
exit 1
else
cat "test/test deleted.txt"
rm "test/test deleted.txt"
fi
- name: Run changed-files with recover_deleted_files and recover_deleted_files_to_destination
id: changed-files-recover-deleted-files-to-destination
uses: ./
with:
base_sha: "fcdeb5b3d797752d95f6dbe98552a95c29dad338"
sha: "432e0c810c60ef1332850a971c5ec39022034b4c"
recover_deleted_files: true
recover_deleted_files_to_destination: "deleted_files"
- name: Show output
run: |
echo "${{ toJSON(steps.changed-files-recover-deleted-files-to-destination.outputs) }}"
shell:
bash
- name: Verify deleted files
if: steps.changed-files-recover-deleted-files-to-destination.outputs.deleted_files != 'test/test deleted.txt'
run: |
echo "Expected: (test/test deleted.txt) got ${{ steps.changed-files-recover-deleted-files-to-destination.outputs.deleted_files }}"
exit 1
- name: Verify that test/test deleted.txt is restored
run: |
if [ ! -f "deleted_files/test/test deleted.txt" ]; then
echo "Expected: (deleted_files/test/test deleted.txt) to exist"
exit 1
else
cat "deleted_files/test/test deleted.txt"
fi
test:
name: Test changed-files
@@ -541,6 +766,7 @@ jobs:
uses: actions/checkout@v3
with:
submodules: true
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: ${{ matrix.fetch-depth }}
- name: Download build assets
uses: actions/download-artifact@v3
@@ -842,6 +1068,41 @@ jobs:
exit 1
shell:
bash
- name: Run changed-files for old new filenames test rename 2 output as deleted and added
id: changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added
uses: ./
with:
base_sha: 4d04215
sha: fe238e6
fetch_depth: 60000
include_all_old_new_renamed_files: true
output_renamed_files_as_deleted_and_added: true
- name: Show output
run: |
echo '${{ toJSON(steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs) }}'
shell:
bash
- name: Check all_old_new_renamed_files output
if: "!contains(steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs.all_old_new_renamed_files, 'test/test rename 2.txt,test/test rename-2.txt')"
run: |
echo "Invalid output: Expected to include (test/test rename 2.txt test/test rename-2.txt) got (${{ steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs.all_old_new_renamed_files }})"
exit 1
shell:
bash
- name: Check deleted_files output
if: "!contains(steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs.deleted_files, 'test/test rename 2.txt')"
run: |
echo "Invalid output: Expected to include (test/test rename 2.txt) got (${{ steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs.deleted_files }})"
exit 1
shell:
bash
- name: Check added_files output
if: "!contains(steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs.added_files, 'test/test rename-2.txt')"
run: |
echo "Invalid output: Expected to include (test/test rename-2.txt) got (${{ steps.changed-files-all-old-new-renamed-files-2-output-as-deleted-and-added.outputs.added_files }})"
exit 1
shell:
bash
- name: Run changed-files with specific files
id: changed-files-specific
uses: ./
@@ -1231,7 +1492,7 @@ jobs:
main-branch-name: ${{ steps.branch-name.outputs.base_ref_branch }}
workflow-id: 'test.yml'
- name: Run changed-files with a custom base sha
if: github.event_name != 'push' && github.event.action != 'closed' && matrix.fetch-depth == 0
if: github.event_name != 'push' && github.event.action != 'closed' && matrix.fetch-depth == 0 && steps.last_successful_commit.outputs.base != steps.last_successful_commit.outputs.head
id: changed-files-custom-base-sha
uses: ./
with:

View File

@@ -20,7 +20,7 @@ jobs:
uses: tj-actions/remark@v3
- name: Verify Changed files
uses: tj-actions/verify-changed-files@v14
uses: tj-actions/verify-changed-files@v15
id: verify_changed_files
with:
files: |

12110
HISTORY.md

File diff suppressed because it is too large Load Diff

219
README.md
View File

@@ -19,7 +19,7 @@
## changed-files
Retrieve all changed files and directories relative to a target branch, preceeding commit or the last remote commit returning a **relative path** from the project root.
Effortlessly track all changed files and directories relative to a target branch, preceding commit or the last remote commit returning **relative paths** from the project root.
## Table of contents
@@ -39,28 +39,36 @@ Retrieve all changed files and directories relative to a target branch, preceedi
## Features
* Fast execution (0-10 seconds on average).
* Easy to debug.
* Scales to large repositories.
* Provides fast execution, averaging 0-10 seconds.
* Facilitates easy debugging.
* Scales to handle large repositories.
* Supports Git submodules.
* Escaped JSON output which can be used to run matrix jobs based on changed files.
* List changed directories.
* Restrict the max depth of matching changed directories.
* Write outputs to a `.txt` or `.json` file at a specified location for further processing.
* Monorepos (Fetches a fixed number of commits).
* Supports all platforms (Linux, MacOS, Windows).
* [GitHub-hosted runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners) support
* [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.3/admin/github-actions/getting-started-with-github-actions-for-your-enterprise/getting-started-with-github-actions-for-github-enterprise-server) support.
* [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) support.
* List all files and directories that have changed:
* Generates escaped JSON output for running matrix jobs based on changed files.
* Lists changed directories.
* Allows limiting the matching changed directories to a specified maximum depth.
* Optionally excludes the current directory.
* Writes outputs to a designated `.txt` or `.json` file for further processing.
* Restores deleted files to their previous location or a newly specified location.
* Supports Monorepos by fetching a fixed number of commits.
* Compatible with all platforms (Linux, MacOS, Windows).
* Supports [GitHub-hosted runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners).
* Supports [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.3/admin/github-actions/getting-started-with-github-actions-for-your-enterprise/getting-started-with-github-actions-for-github-enterprise-server).
* Supports [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
* Lists all files and directories that have changed:
* Between the current pull request branch and the last commit on the target branch.
* Between the last commit and the current pushed change.
* Between the last remote branch commit and the current HEAD.
* Restrict change detection to a subset of files and directories:
* Boolean output indicating that certain files have been changed.
* Using [Glob pattern](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet) matching.
* Globstar.
* Brace expansion.
* Restricts change detection to a subset of files and directories:
* Provides boolean output indicating changes in specific files.
* Uses [Glob pattern](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet) matching.
* Supports Globstar.
* Supports brace expansion.
* Supports negation.
* Uses [YAML](https://yaml.org/) syntax for specifying patterns.
* Supports [YAML anchors & aliases](https://www.educative.io/blog/advanced-yaml-syntax-cheatsheet#anchors).
* Supports [YAML multi-line strings](https://learnxinyminutes.com/docs/yaml/).
And many more.
## Usage
@@ -68,8 +76,9 @@ Retrieve all changed files and directories relative to a target branch, preceedi
>
> * **IMPORTANT:** For `push` events when configuring [`actions/checkout`](https://github.com/actions/checkout#usage) the `fetch-depth` should be set to either `fetch-depth: 0` **OR** `fetch-depth: 2` depending on your use case.
> * For monorepos where pulling all the branch history might not be desired, you can omit [`actions/checkout`](https://github.com/actions/checkout#usage) - `fetch-depth` for `pull_request` events.
> * All multiline inputs should not use double or single quotes since the value is already a string seperated by a newline character. See [Examples](#examples) for more information.
> * All multiline inputs should not use double or single quotes since the value is already a string separated by a newline character. See [Examples](#examples) for more information.
> * Ensure that `persist-credentials` is set to `true` when configuring [`actions/checkout`](https://github.com/actions/checkout#usage) if `fetch-depth` isn't set to `0`.
> * For repositories that have PRs generated from forks when configuring [`actions/checkout`](https://github.com/actions/checkout#usage) set the `repository` to `${{ github.event.pull_request.head.repo.full_name }}`. See: [Example](https://github.com/tj-actions/changed-files/blob/main/.github/workflows/test.yml#L47-L51)
```yaml
name: CI
@@ -83,7 +92,7 @@ on:
- main
# ------------------------------------------------------------------------------------------------------------
# Event `push`: Compare the preceeding commit -> to the current commit of the main branch.
# Event `push`: Compare the preceding commit -> to the current commit of the main branch.
# Event `pull_request`: Compare the last commit of main -> to the current commit of a Pull Request branch.
# ------------------------------------------------------------------------------------------------------------
@@ -139,6 +148,35 @@ jobs:
run: |
echo "One or more .js file(s) or any file in the static folder but not in the doc folder has changed."
echo "List all the files that have changed: ${{ steps.changed-files-excluded.outputs.all_changed_files }}"
# Example 4
- name: Get all test, doc and src files that have changed
id: changed-files-yml
uses: tj-actions/changed-files@v36
with:
files_yaml: |
doc:
- *.md
- docs/**
- !docs/README.md
test:
- test/**
- !test/README.md
src:
- src/**
# Optionally set `files_yaml_from_source_file` to read the YAML from a file. e.g `files_yaml_from_source_file: .github/changed-files.yml`
- name: Run step if test file(s) change
if: steps.changed-files-yml.outputs.test_any_changed == 'true'
run: |
echo "One or more test file(s) has changed."
echo "List all the files that have changed: ${{ steps.changed-files-yml.outputs.test_all_changed_files }}"
- name: Run step if doc file(s) change
if: steps.changed-files-yml.outputs.doc_any_changed == 'true'
run: |
echo "One or more doc file(s) has changed."
echo "List all the files that have changed: ${{ steps.changed-files-yml.outputs.doc_all_changed_files }}"
```
To access more examples, navigate to the [Examples](#examples) section.
@@ -170,29 +208,44 @@ Support this project with a :star:
<!-- AUTO-DOC-OUTPUT:START - Do not remove or modify this section -->
| OUTPUT | TYPE | DESCRIPTION |
|--------------------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| added\_files | string | Returns only files that are <br>Added (A). |
| all\_changed\_and\_modified\_files | string | Returns all changed and modified <br>files i.e. *a combination of (ACMRDTUX)* |
| all\_changed\_files | string | Returns all changed files i.e. <br>*a combination of all added, copied, modified and renamed files (ACMR)* |
| all\_modified\_files | string | Returns all changed files i.e. <br>*a combination of all added, copied, modified, renamed and deleted files (ACMRD)*. |
| all\_old\_new\_renamed\_files | string | Returns only files that are <br>Renamed and list their old <br>and new names. **NOTE:** This <br>requires setting `include_all_old_new_renamed_files` to `true` <br>(R) |
| any\_changed | string | Returns `true` when any of <br>the filenames provided using the <br>`files` input has changed. i.e. <br>*using a combination of all added, copied, modified and renamed files (ACMR)*. |
| any\_deleted | string | Returns `true` when any of <br>the filenames provided using the <br>`files` input has been deleted. <br>(D) |
| any\_modified | string | Returns `true` when any of <br>the filenames provided using the <br>`files` input has been modified. <br>i.e. *using a combination of all added, copied, modified, renamed, and deleted files (ACMRD)*. |
| copied\_files | string | Returns only files that are <br>Copied (C). |
| deleted\_files | string | Returns only files that are <br>Deleted (D). |
| modified\_files | string | Returns only files that are <br>Modified (M). |
| only\_changed | string | Returns `true` when only files <br>provided using the `files` input <br>has changed. i.e. *using a combination of all added, copied, modified and renamed files (ACMR)*. |
| only\_deleted | string | Returns `true` when only files <br>provided using the `files` input <br>has been deleted. (D) |
| only\_modified | string | Returns `true` when only files <br>provided using the `files` input <br>has been modified. (ACMRD). |
| other\_changed\_files | string | Returns all other changed files <br>not listed in the files <br>input i.e. *using a combination of all added, copied, modified and renamed files (ACMR)*. |
| other\_deleted\_files | string | Returns all other deleted files <br>not listed in the files <br>input i.e. *a combination of all deleted files (D)* |
| other\_modified\_files | string | Returns all other modified files <br>not listed in the files <br>input i.e. *a combination of all added, copied, modified, and deleted files (ACMRD)* |
| renamed\_files | string | Returns only files that are <br>Renamed (R). |
| type\_changed\_files | string | Returns only files that have <br>their file type changed (T). |
| unknown\_files | string | Returns only files that are <br>Unknown (X). |
| unmerged\_files | string | Returns only files that are <br>Unmerged (U). |
| OUTPUT | TYPE | DESCRIPTION |
|--------------------------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| added\_files | string | Returns only files that are <br>Added (A). |
| added\_files\_count | string | Returns the number of `added_files` |
| all\_changed\_and\_modified\_files | string | Returns all changed and modified <br>files i.e. *a combination of (ACMRDTUX)* |
| all\_changed\_and\_modified\_files\_count | string | Returns the number of `all_changed_and_modified_files` |
| all\_changed\_files | string | Returns all changed files i.e. <br>*a combination of all added, copied, modified and renamed files (ACMR)* |
| all\_changed\_files\_count | string | Returns the number of `all_changed_files` |
| all\_modified\_files | string | Returns all changed files i.e. <br>*a combination of all added, copied, modified, renamed and deleted files (ACMRD)*. |
| all\_modified\_files\_count | string | Returns the number of `all_modified_files` |
| all\_old\_new\_renamed\_files | string | Returns only files that are <br>Renamed and lists their old <br>and new names. **NOTE:** This <br>requires setting `include_all_old_new_renamed_files` to `true`. <br>Also, keep in mind that <br>this output is global and <br>wouldn't be nested in outputs <br>generated when the `*_yaml_*` input <br>is used. (R) |
| all\_old\_new\_renamed\_files\_count | string | Returns the number of `all_old_new_renamed_files` |
| any\_changed | string | Returns `true` when any of <br>the filenames provided using the <br>`files*` or `files_ignore*` inputs has changed. i.e. <br>*using a combination of all added, copied, modified and renamed files (ACMR)*. |
| any\_deleted | string | Returns `true` when any of <br>the filenames provided using the <br>`files*` or `files_ignore*` inputs has been deleted. <br>(D) |
| any\_modified | string | Returns `true` when any of <br>the filenames provided using the <br>`files*` or `files_ignore*` inputs has been modified. <br>i.e. *using a combination of all added, copied, modified, renamed, and deleted files (ACMRD)*. |
| copied\_files | string | Returns only files that are <br>Copied (C). |
| copied\_files\_count | string | Returns the number of `copied_files` |
| deleted\_files | string | Returns only files that are <br>Deleted (D). |
| deleted\_files\_count | string | Returns the number of `deleted_files` |
| modified\_files | string | Returns only files that are <br>Modified (M). |
| modified\_files\_count | string | Returns the number of `modified_files` |
| only\_changed | string | Returns `true` when only files <br>provided using the `files*` or `files_ignore*` inputs <br>has changed. i.e. *using a combination of all added, copied, modified and renamed files (ACMR)*. |
| only\_deleted | string | Returns `true` when only files <br>provided using the `files*` or `files_ignore*` inputs <br>has been deleted. (D) |
| only\_modified | string | Returns `true` when only files <br>provided using the `files*` or `files_ignore*` inputs <br>has been modified. (ACMRD). |
| other\_changed\_files | string | Returns all other changed files <br>not listed in the files <br>input i.e. *using a combination of all added, copied, modified and renamed files (ACMR)*. |
| other\_changed\_files\_count | string | Returns the number of `other_changed_files` |
| other\_deleted\_files | string | Returns all other deleted files <br>not listed in the files <br>input i.e. *a combination of all deleted files (D)* |
| other\_deleted\_files\_count | string | Returns the number of `other_deleted_files` |
| other\_modified\_files | string | Returns all other modified files <br>not listed in the files <br>input i.e. *a combination of all added, copied, modified, and deleted files (ACMRD)* |
| other\_modified\_files\_count | string | Returns the number of `other_modified_files` |
| renamed\_files | string | Returns only files that are <br>Renamed (R). |
| renamed\_files\_count | string | Returns the number of `renamed_files` |
| type\_changed\_files | string | Returns only files that have <br>their file type changed (T). |
| type\_changed\_files\_count | string | Returns the number of `type_changed_files` |
| unknown\_files | string | Returns only files that are <br>Unknown (X). |
| unknown\_files\_count | string | Returns the number of `unknown_files` |
| unmerged\_files | string | Returns only files that are <br>Unmerged (U). |
| unmerged\_files\_count | string | Returns the number of `unmerged_files` |
<!-- AUTO-DOC-OUTPUT:END -->
@@ -200,36 +253,46 @@ Support this project with a :star:
<!-- AUTO-DOC-INPUT:START - Do not remove or modify this section -->
| INPUT | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|-----------------------------------------|--------|----------|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| base\_sha | string | false | | Specify a different base commit <br>SHA used for comparing changes |
| diff\_relative | string | false | `"true"` | Exclude changes outside the current <br>directory and show path names <br>relative to it. **NOTE:** This <br>requires you to specify the <br>top level directory via the <br>`path` input. |
| dir\_names | string | false | `"false"` | Output unique changed directories instead <br>of filenames. **NOTE:** This returns <br>`.` for changed files located <br>in the root of the <br>project. |
| dir\_names\_exclude\_root | string | false | `"false"` | Exclude the root directory represented <br>by `.` from the output <br>when `dir_names`is set to `true`. |
| dir\_names\_max\_depth | string | false | | Maximum depth of directories to <br>output. e.g `test/test1/test2` with max <br>depth of `2` returns `test/test1`. |
| escape\_json | string | false | `"true"` | Escape JSON output. |
| fetch\_depth | string | false | `"50"` | Depth of additional branch history <br>fetched. **NOTE**: This can be <br>adjusted to resolve errors with <br>insufficient history. |
| files | string | false | | File and directory patterns to <br>detect changes using only these <br>list of file(s) (Defaults to the entire repo) **NOTE:** <br>Multiline file/directory patterns should not <br>include quotes. |
| files\_from\_source\_file | string | false | | Source file(s) used to populate <br>the `files` input. |
| files\_from\_source\_file\_separator | string | false | `"\n"` | Separator used to split the <br>`files_from_source_file` input |
| files\_ignore | string | false | | Ignore changes to these file(s) <br>**NOTE:** Multiline file/directory patterns should <br>not include quotes. |
| files\_ignore\_from\_source\_file | string | false | | Source file(s) used to populate <br>the `files_ignore` input |
| files\_ignore\_from\_source\_file\_separator | string | false | `"\n"` | Separator used to split the <br>`files_ignore_from_source_file` input |
| files\_ignore\_separator | string | false | `"\n"` | Separator used to split the <br>`files_ignore` input |
| files\_separator | string | false | `"\n"` | Separator used to split the <br>`files` input |
| include\_all\_old\_new\_renamed\_files | string | false | `"false"` | Include `all_old_new_renamed_files` output. Note this <br>can generate a large output <br>See: [#501](https://github.com/tj-actions/changed-files/issues/501). |
| json | string | false | `"false"` | Output list of changed files <br>in a JSON formatted string <br>which can be used for <br>matrix jobs. |
| old\_new\_files\_separator | string | false | `" "` | Split character for old and <br>new renamed filename pairs. |
| old\_new\_separator | string | false | `","` | Split character for old and <br>new filename pairs. |
| output\_dir | string | false | `".github/outputs"` | Directory to store output files. |
| path | string | false | `"."` | Specify a relative path under <br>`$GITHUB_WORKSPACE` to locate the repository. |
| quotepath | string | false | `"true"` | Use non ascii characters to <br>match files and output the <br>filenames completely verbatim by setting <br>this to `false` |
| separator | string | false | `" "` | Split character for output strings |
| sha | string | false | | Specify a different commit SHA <br>used for comparing changes |
| since | string | false | | Get changed files for commits <br>whose timestamp is older than <br>the given time. |
| since\_last\_remote\_commit | string | false | `"false"` | Use the last commit on <br>the remote branch as the <br>`base_sha`. Defaults to the last <br>non merge commit on the <br>target branch for pull request <br>events and the previous remote <br>commit of the current branch <br>for push events. |
| until | string | false | | Get changed files for commits <br>whose timestamp is earlier than <br>the given time. |
| write\_output\_files | string | false | `"false"` | Write outputs to files in <br>the `.github/outputs` folder by default. |
| INPUT | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|------------------------------------------------------------------------------|--------|----------|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| base\_sha | string | false | | Specify a different base commit <br>SHA used for comparing changes |
| diff\_relative | string | false | `"true"` | Exclude changes outside the current <br>directory and show path names <br>relative to it. **NOTE:** This <br>requires you to specify the <br>top level directory via the <br>`path` input. |
| dir\_names | string | false | `"false"` | Output unique changed directories instead <br>of filenames. **NOTE:** This returns <br>`.` for changed files located <br>in the current working directory <br>which defaults to `$GITHUB_WORKSPACE`. |
| dir\_names\_exclude\_current\_dir | string | false | `"false"` | Exclude the current directory represented <br>by `.` from the output <br>when `dir_names` is set to <br>`true`. |
| ~~dir\_names\_exclude\_root~~ <br> Use `dir_names_exclude_current_dir` instead. | string | false | `"false"` | **Deprecated:** Exclude the root directory <br>represented by `.` from the <br>output when `dir_names`is set to <br>`true`. |
| dir\_names\_max\_depth | string | false | | Limit the directory output to <br>a maximum depth e.g `test/test1/test2` <br>with max depth of `2` <br>returns `test/test1`. |
| escape\_json | string | false | `"true"` | Escape JSON output. |
| fetch\_depth | string | false | `"50"` | Depth of additional branch history <br>fetched. **NOTE**: This can be <br>adjusted to resolve errors with <br>insufficient history. |
| files | string | false | | File and directory patterns used <br>to detect changes (Defaults to the entire repo if unset) **NOTE:** <br>Multiline file/directory patterns should not <br>include quotes. |
| files\_from\_source\_file | string | false | | Source file(s) used to populate <br>the `files` input. |
| files\_from\_source\_file\_separator | string | false | `"\n"` | Separator used to split the <br>`files_from_source_file` input |
| files\_ignore | string | false | | Ignore changes to these file(s) <br>**NOTE:** Multiline file/directory patterns should <br>not include quotes. |
| files\_ignore\_from\_source\_file | string | false | | Source file(s) used to populate <br>the `files_ignore` input |
| files\_ignore\_from\_source\_file\_separator | string | false | `"\n"` | Separator used to split the <br>`files_ignore_from_source_file` input |
| files\_ignore\_separator | string | false | `"\n"` | Separator used to split the <br>`files_ignore` input |
| files\_ignore\_yaml | string | false | | YAML used to define a <br>set of file patterns to <br>ignore changes |
| files\_ignore\_yaml\_from\_source\_file | string | false | | Source file(s) used to populate <br>the `files_ignore_yaml` input. [Example](https://github.com/tj-actions/changed-files/blob/main/test/changed-files.yml) |
| files\_ignore\_yaml\_from\_source\_file\_separator | string | false | `"\n"` | Separator used to split the <br>`files_ignore_yaml_from_source_file` input |
| files\_separator | string | false | `"\n"` | Separator used to split the <br>`files` input |
| files\_yaml | string | false | | YAML used to define a <br>set of file patterns to <br>detect changes |
| files\_yaml\_from\_source\_file | string | false | | Source file(s) used to populate <br>the `files_yaml` input. [Example](https://github.com/tj-actions/changed-files/blob/main/test/changed-files.yml) |
| files\_yaml\_from\_source\_file\_separator | string | false | `"\n"` | Separator used to split the <br>`files_yaml_from_source_file` input |
| include\_all\_old\_new\_renamed\_files | string | false | `"false"` | Include `all_old_new_renamed_files` output. Note this <br>can generate a large output <br>See: [#501](https://github.com/tj-actions/changed-files/issues/501). |
| json | string | false | `"false"` | Output list of changed files <br>in a JSON formatted string <br>which can be used for <br>matrix jobs. |
| old\_new\_files\_separator | string | false | `" "` | Split character for old and <br>new renamed filename pairs. |
| old\_new\_separator | string | false | `","` | Split character for old and <br>new filename pairs. |
| output\_dir | string | false | `".github/outputs"` | Directory to store output files. |
| output\_renamed\_files\_as\_deleted\_and\_added | string | false | `"false"` | Output renamed files as deleted <br>and added files. |
| path | string | false | `"."` | Specify a relative path under <br>`$GITHUB_WORKSPACE` to locate the repository. |
| quotepath | string | false | `"true"` | Use non-ascii characters to match <br>files and output the filenames <br>completely verbatim by setting this <br>to `false` |
| recover\_deleted\_files | string | false | `"false"` | Recover deleted files. |
| recover\_deleted\_files\_to\_destination | string | false | | Recover deleted files to a <br>new destination directory, defaults to <br>the original location. |
| separator | string | false | `" "` | Split character for output strings |
| sha | string | false | | Specify a different commit SHA <br>used for comparing changes |
| since | string | false | | Get changed files for commits <br>whose timestamp is older than <br>the given time. |
| since\_last\_remote\_commit | string | false | `"false"` | Use the last commit on <br>the remote branch as the <br>`base_sha`. Defaults to the last <br>non-merge commit on the target <br>branch for pull request events <br>and the previous remote commit <br>of the current branch for <br>push events. |
| until | string | false | | Get changed files for commits <br>whose timestamp is earlier than <br>the given time. |
| write\_output\_files | string | false | `"false"` | Write outputs to the `output_dir` <br>defaults to `.github/outputs` folder. **NOTE:** <br>This creates a `.txt` file <br>by default and a `.json` <br>file if `json` is set <br>to `true`. |
<!-- AUTO-DOC-INPUT:END -->
@@ -239,11 +302,11 @@ This GitHub Action follows the principles of [Semantic Versioning](https://semve
The format of the version string is as follows:
major: is a major release number that indicates significant changes or new features that may not be backward compatible.
* major: indicates significant changes or new features that may not be backward compatible.
minor: is a minor release number that indicates minor changes or new features that are backward compatible.
* minor: indicates minor changes or new features that are backward compatible.
patch : is a patch release number that indicates bug fixes or other small changes that are backward compatible.
* patch: indicates bug fixes or other small changes that are backward compatible.
## Examples
@@ -735,6 +798,8 @@ See [inputs](#inputs) for more information.
* [aws-doc-sdk-examples: uses tj-actions/changed-files to automate testing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/2393723ef6b0cad9502f4852f5c72f7be58ca89d/.github/workflows/javascript.yml#L22)
![image](https://github.com/tj-actions/changed-files/assets/17484350/23767413-4c51-42fb-ab1c-39ef72c44904)
And many more...
## Known Limitation

View File

@@ -28,13 +28,37 @@ inputs:
default: "\n"
required: false
files:
description: "File and directory patterns to detect changes using only these list of file(s) (Defaults to the entire repo) **NOTE:** Multiline file/directory patterns should not include quotes."
description: "File and directory patterns used to detect changes (Defaults to the entire repo if unset) **NOTE:** Multiline file/directory patterns should not include quotes."
required: false
default: ""
files_separator:
description: "Separator used to split the `files` input"
default: "\n"
required: false
files_yaml:
description: "YAML used to define a set of file patterns to detect changes"
required: false
default: ""
files_yaml_from_source_file:
description: "Source file(s) used to populate the `files_yaml` input. [Example](https://github.com/tj-actions/changed-files/blob/main/test/changed-files.yml)"
required: false
default: ""
files_yaml_from_source_file_separator:
description: 'Separator used to split the `files_yaml_from_source_file` input'
default: "\n"
required: false
files_ignore_yaml:
description: "YAML used to define a set of file patterns to ignore changes"
required: false
default: ""
files_ignore_yaml_from_source_file:
description: "Source file(s) used to populate the `files_ignore_yaml` input. [Example](https://github.com/tj-actions/changed-files/blob/main/test/changed-files.yml)"
required: false
default: ""
files_ignore_yaml_from_source_file_separator:
description: 'Separator used to split the `files_ignore_yaml_from_source_file` input'
default: "\n"
required: false
files_ignore:
description: "Ignore changes to these file(s) **NOTE:** Multiline file/directory patterns should not include quotes."
required: false
@@ -70,7 +94,7 @@ inputs:
required: false
default: "."
quotepath:
description: "Use non ascii characters to match files and output the filenames completely verbatim by setting this to `false`"
description: "Use non-ascii characters to match files and output the filenames completely verbatim by setting this to `false`"
default: "true"
required: false
diff_relative:
@@ -79,15 +103,20 @@ inputs:
default: "true"
dir_names:
default: "false"
description: "Output unique changed directories instead of filenames. **NOTE:** This returns `.` for changed files located in the root of the project."
description: "Output unique changed directories instead of filenames. **NOTE:** This returns `.` for changed files located in the current working directory which defaults to `$GITHUB_WORKSPACE`."
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`."
description: "Limit the directory output to a maximum depth e.g `test/test1/test2` with max depth of `2` returns `test/test1`."
required: false
dir_names_exclude_current_dir:
description: "Exclude the current directory represented by `.` from the output when `dir_names` is set to `true`."
required: false
default: "false"
dir_names_exclude_root:
description: "Exclude the root directory represented by `.` from the output when `dir_names`is set to `true`."
required: false
default: "false"
deprecationMessage: "Use `dir_names_exclude_current_dir` instead."
json:
description: "Output list of changed files in a JSON formatted string which can be used for matrix jobs."
required: false
@@ -101,61 +130,103 @@ inputs:
required: false
default: "50"
since_last_remote_commit:
description: "Use the last commit on the remote branch as the `base_sha`. Defaults to the last non merge commit on the target branch for pull request events and the previous remote commit of the current branch for push events."
description: "Use the last commit on the remote branch as the `base_sha`. Defaults to the last non-merge commit on the target branch for pull request events and the previous remote commit of the current branch for push events."
required: false
default: "false"
write_output_files:
description: "Write outputs to files in the `.github/outputs` folder by default."
description: "Write outputs to the `output_dir` defaults to `.github/outputs` folder. **NOTE:** This creates a `.txt` file by default and a `.json` file if `json` is set to `true`."
required: false
default: "false"
output_dir:
description: "Directory to store output files."
required: false
default: ".github/outputs"
output_renamed_files_as_deleted_and_added:
description: "Output renamed files as deleted and added files."
required: false
default: "false"
recover_deleted_files:
description: "Recover deleted files."
required: false
default: "false"
recover_deleted_files_to_destination:
description: "Recover deleted files to a new destination directory, defaults to the original location."
required: false
default: ""
outputs:
added_files:
description: "Returns only files that are Added (A)."
added_files_count:
description: "Returns the number of `added_files`"
copied_files:
description: "Returns only files that are Copied (C)."
copied_files_count:
description: "Returns the number of `copied_files`"
deleted_files:
description: "Returns only files that are Deleted (D)."
deleted_files_count:
description: "Returns the number of `deleted_files`"
modified_files:
description: "Returns only files that are Modified (M)."
modified_files_count:
description: "Returns the number of `modified_files`"
renamed_files:
description: "Returns only files that are Renamed (R)."
renamed_files_count:
description: "Returns the number of `renamed_files`"
all_old_new_renamed_files:
description: "Returns only files that are Renamed and list their old and new names. **NOTE:** This requires setting `include_all_old_new_renamed_files` to `true` (R)"
description: "Returns only files that are Renamed and lists their old and new names. **NOTE:** This requires setting `include_all_old_new_renamed_files` to `true`. Also, keep in mind that this output is global and wouldn't be nested in outputs generated when the `*_yaml_*` input is used. (R)"
all_old_new_renamed_files_count:
description: "Returns the number of `all_old_new_renamed_files`"
type_changed_files:
description: "Returns only files that have their file type changed (T)."
type_changed_files_count:
description: "Returns the number of `type_changed_files`"
unmerged_files:
description: "Returns only files that are Unmerged (U)."
unmerged_files_count:
description: "Returns the number of `unmerged_files`"
unknown_files:
description: "Returns only files that are Unknown (X)."
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)*"
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)*"
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` input has changed. i.e. *using 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. *using a combination of all added, copied, modified and renamed files (ACMR)*."
only_changed:
description: "Returns `true` when only files provided using the `files` input has changed. i.e. *using 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. *using 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. *using 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)*."
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` input has been modified. i.e. *using 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. *using a combination of all added, copied, modified, renamed, and deleted files (ACMRD)*."
only_modified:
description: "Returns `true` when only files provided using the `files` input has 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)*"
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` input has been deleted. (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` input has 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)*"
other_deleted_files_count:
description: "Returns the number of `other_deleted_files`"
runs:
using: 'node16'

27289
dist/index.js generated vendored

File diff suppressed because it is too large Load Diff

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

68
dist/licenses.txt generated vendored
View File

@@ -134,6 +134,57 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
lodash
MIT
Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
Based on Underscore.js, copyright Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/lodash/lodash
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code displayed within the prose of the
documentation.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
Files located in the node_modules and vendor directories are externally
maintained libraries used by this software which have their own
licenses; we recommend you read them, as their terms may differ from the
terms above.
micromatch
MIT
The MIT License (MIT)
@@ -245,3 +296,20 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
yaml
ISC
Copyright Eemeli Aro <eemeli@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

View File

@@ -34,23 +34,26 @@
"dependencies": {
"@actions/core": "1.10.0",
"@actions/exec": "1.1.1",
"micromatch": "^4.0.5"
"lodash": "^4.17.15",
"micromatch": "^4.0.5",
"yaml": "^2.3.1"
},
"devDependencies": {
"@types/jest": "29.5.2",
"@types/lodash": "^4.14.195",
"@types/micromatch": "^4.0.2",
"@types/node": "20.2.1",
"@types/uuid": "9.0.1",
"@typescript-eslint/eslint-plugin": "5.59.8",
"@typescript-eslint/parser": "5.59.8",
"@types/uuid": "9.0.2",
"@typescript-eslint/eslint-plugin": "5.59.11",
"@typescript-eslint/parser": "5.59.11",
"@vercel/ncc": "0.36.1",
"eslint": "8.41.0",
"eslint-plugin-github": "4.7.0",
"eslint": "8.43.0",
"eslint-plugin-github": "4.8.0",
"eslint-plugin-jest": "27.2.1",
"eslint-plugin-prettier": "^4.2.1",
"jest": "29.5.0",
"prettier": "2.8.8",
"ts-jest": "29.1.0",
"typescript": "5.0.4"
"typescript": "5.1.3"
}
}

View File

@@ -4,11 +4,12 @@ import {DiffResult} from './commitSha'
import {Inputs} from './inputs'
import {
getDirnameMaxDepth,
gitDiff,
gitRenamedFiles,
gitSubmoduleDiffSHA,
jsonOutput
jsonOutput,
getAllChangedFiles
} from './utils'
import flatten from 'lodash/flatten'
export const getRenamedFiles = async ({
inputs,
@@ -22,7 +23,7 @@ export const getRenamedFiles = async ({
hasSubmodule: boolean
diffResult: DiffResult
submodulePaths: string[]
}): Promise<string> => {
}): Promise<{paths: string; count: string}> => {
const renamedFiles = await gitRenamedFiles({
cwd: workingDirectory,
sha1: diffResult.previousSha,
@@ -62,36 +63,52 @@ export const getRenamedFiles = async ({
}
if (inputs.json) {
return jsonOutput({value: renamedFiles, shouldEscape: inputs.escapeJson})
return {
paths: jsonOutput({value: renamedFiles, shouldEscape: inputs.escapeJson}),
count: renamedFiles.length.toString()
}
}
return renamedFiles.join(inputs.oldNewFilesSeparator)
return {
paths: renamedFiles.join(inputs.oldNewFilesSeparator),
count: renamedFiles.length.toString()
}
}
export const getDiffFiles = async ({
inputs,
export enum ChangeTypeEnum {
Added = 'A',
Copied = 'C',
Deleted = 'D',
Modified = 'M',
Renamed = 'R',
TypeChanged = 'T',
Unmerged = 'U',
Unknown = 'X'
}
export type ChangedFiles = {
[key in ChangeTypeEnum]: string[]
}
export const getAllDiffFiles = async ({
workingDirectory,
hasSubmodule,
diffResult,
diffFilter,
filePatterns = [],
submodulePaths
submodulePaths,
outputRenamedFilesAsDeletedAndAdded
}: {
inputs: Inputs
workingDirectory: string
hasSubmodule: boolean
diffResult: DiffResult
diffFilter: string
filePatterns?: string[]
submodulePaths: string[]
}): Promise<string> => {
let files = await gitDiff({
outputRenamedFilesAsDeletedAndAdded: boolean
}): Promise<ChangedFiles> => {
const files = await getAllChangedFiles({
cwd: workingDirectory,
sha1: diffResult.previousSha,
sha2: diffResult.currentSha,
diff: diffResult.diff,
diffFilter,
filePatterns
outputRenamedFilesAsDeletedAndAdded
})
if (hasSubmodule) {
@@ -110,35 +127,124 @@ export const getDiffFiles = async ({
)
if (submoduleShaResult.currentSha && submoduleShaResult.previousSha) {
const submoduleFiles = await gitDiff({
const submoduleFiles = await getAllChangedFiles({
cwd: submoduleWorkingDirectory,
sha1: submoduleShaResult.previousSha,
sha2: submoduleShaResult.currentSha,
diff: diffResult.diff,
diffFilter,
isSubmodule: true,
filePatterns,
parentDir: submodulePath
parentDir: submodulePath,
outputRenamedFilesAsDeletedAndAdded
})
files.push(...submoduleFiles)
for (const changeType of Object.keys(
submoduleFiles
) as ChangeTypeEnum[]) {
if (!files[changeType]) {
files[changeType] = []
}
files[changeType].push(...submoduleFiles[changeType])
}
}
}
}
if (inputs.dirNames) {
files = files.map(file =>
getDirnameMaxDepth({
pathStr: file,
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeRoot: inputs.dirNamesExcludeRoot
})
)
files = [...new Set(files)]
return files
}
function* getChangeTypeFilesGenerator({
inputs,
changedFiles,
changeTypes
}: {
inputs: Inputs
changedFiles: ChangedFiles
changeTypes: ChangeTypeEnum[]
}): Generator<string> {
for (const changeType of changeTypes) {
const files = changedFiles[changeType] || []
for (const file of files) {
if (inputs.dirNames) {
yield getDirnameMaxDepth({
pathStr: file,
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeCurrentDir:
inputs.dirNamesExcludeRoot || inputs.dirNamesExcludeCurrentDir
})
} else {
yield file
}
}
}
}
export const getChangeTypeFiles = async ({
inputs,
changedFiles,
changeTypes
}: {
inputs: Inputs
changedFiles: ChangedFiles
changeTypes: ChangeTypeEnum[]
}): Promise<{paths: string; count: string}> => {
const files = [
...new Set(getChangeTypeFilesGenerator({inputs, changedFiles, changeTypes}))
]
if (inputs.json) {
return jsonOutput({value: files, shouldEscape: inputs.escapeJson})
return {
paths: jsonOutput({value: files, shouldEscape: inputs.escapeJson}),
count: files.length.toString()
}
}
return files.join(inputs.separator)
return {
paths: files.join(inputs.separator),
count: files.length.toString()
}
}
function* getAllChangeTypeFilesGenerator({
inputs,
changedFiles
}: {
inputs: Inputs
changedFiles: ChangedFiles
}): Generator<string> {
for (const file of flatten(Object.values(changedFiles))) {
if (inputs.dirNames) {
yield getDirnameMaxDepth({
pathStr: file,
dirNamesMaxDepth: inputs.dirNamesMaxDepth,
excludeCurrentDir:
inputs.dirNamesExcludeRoot || inputs.dirNamesExcludeCurrentDir
})
} else {
yield file
}
}
}
export const getAllChangeTypeFiles = async ({
inputs,
changedFiles
}: {
inputs: Inputs
changedFiles: ChangedFiles
}): Promise<{paths: string; count: string}> => {
const files = [
...new Set(getAllChangeTypeFilesGenerator({inputs, changedFiles}))
]
if (inputs.json) {
return {
paths: jsonOutput({value: files, shouldEscape: inputs.escapeJson}),
count: files.length.toString()
}
}
return {
paths: files.join(inputs.separator),
count: files.length.toString()
}
}

387
src/changedFilesOutput.ts Normal file
View File

@@ -0,0 +1,387 @@
import * as core from '@actions/core'
import {
ChangedFiles,
ChangeTypeEnum,
getAllChangeTypeFiles,
getChangeTypeFiles
} from './changedFiles'
import {DiffResult} from './commitSha'
import {Inputs} from './inputs'
import {getFilteredChangedFiles, recoverDeletedFiles, setOutput} from './utils'
const getOutputKey = (key: string, outputPrefix: string): string => {
return outputPrefix ? `${outputPrefix}_${key}` : key
}
export const setChangedFilesOutput = async ({
allDiffFiles,
inputs,
workingDirectory,
diffResult,
filePatterns = [],
outputPrefix = ''
}: {
allDiffFiles: ChangedFiles
filePatterns?: string[]
inputs: Inputs
workingDirectory: string
diffResult: DiffResult
outputPrefix?: string
}): Promise<void> => {
const allFilteredDiffFiles = await getFilteredChangedFiles({
allDiffFiles,
filePatterns
})
core.debug(`All filtered diff files: ${JSON.stringify(allFilteredDiffFiles)}`)
await recoverDeletedFiles({
inputs,
workingDirectory,
deletedFiles: allFilteredDiffFiles[ChangeTypeEnum.Deleted],
sha: diffResult.previousSha
})
const addedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Added]
})
core.debug(`Added files: ${addedFiles}`)
await setOutput({
key: getOutputKey('added_files', outputPrefix),
value: addedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('added_files_count', outputPrefix),
value: addedFiles.count,
inputs
})
const copiedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Copied]
})
core.debug(`Copied files: ${copiedFiles}`)
await setOutput({
key: getOutputKey('copied_files', outputPrefix),
value: copiedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('copied_files_count', outputPrefix),
value: copiedFiles.count,
inputs
})
const modifiedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Modified]
})
core.debug(`Modified files: ${modifiedFiles}`)
await setOutput({
key: getOutputKey('modified_files', outputPrefix),
value: modifiedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('modified_files_count', outputPrefix),
value: modifiedFiles.count,
inputs
})
const renamedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Renamed]
})
core.debug(`Renamed files: ${renamedFiles}`)
await setOutput({
key: getOutputKey('renamed_files', outputPrefix),
value: renamedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('renamed_files_count', outputPrefix),
value: renamedFiles.count,
inputs
})
const typeChangedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.TypeChanged]
})
core.debug(`Type changed files: ${typeChangedFiles}`)
await setOutput({
key: getOutputKey('type_changed_files', outputPrefix),
value: typeChangedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('type_changed_files_count', outputPrefix),
value: typeChangedFiles.count,
inputs
})
const unmergedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Unmerged]
})
core.debug(`Unmerged files: ${unmergedFiles}`)
await setOutput({
key: getOutputKey('unmerged_files', outputPrefix),
value: unmergedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('unmerged_files_count', outputPrefix),
value: unmergedFiles.count,
inputs
})
const unknownFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Unknown]
})
core.debug(`Unknown files: ${unknownFiles}`)
await setOutput({
key: getOutputKey('unknown_files', outputPrefix),
value: unknownFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('unknown_files_count', outputPrefix),
value: unknownFiles.count,
inputs
})
const allChangedAndModifiedFiles = await getAllChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles
})
core.debug(`All changed and modified files: ${allChangedAndModifiedFiles}`)
await setOutput({
key: getOutputKey('all_changed_and_modified_files', outputPrefix),
value: allChangedAndModifiedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('all_changed_and_modified_files_count', outputPrefix),
value: allChangedAndModifiedFiles.count,
inputs
})
const allChangedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [
ChangeTypeEnum.Added,
ChangeTypeEnum.Copied,
ChangeTypeEnum.Modified,
ChangeTypeEnum.Renamed
]
})
core.debug(`All changed files: ${allChangedFiles}`)
await setOutput({
key: getOutputKey('all_changed_files', outputPrefix),
value: allChangedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('all_changed_files_count', outputPrefix),
value: allChangedFiles.count,
inputs
})
await setOutput({
key: getOutputKey('any_changed', outputPrefix),
value: allChangedFiles.paths.length > 0 && filePatterns.length > 0,
inputs
})
const allOtherChangedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allDiffFiles,
changeTypes: [
ChangeTypeEnum.Added,
ChangeTypeEnum.Copied,
ChangeTypeEnum.Modified,
ChangeTypeEnum.Renamed
]
})
core.debug(`All other changed files: ${allOtherChangedFiles}`)
const otherChangedFiles = allOtherChangedFiles.paths
.split(inputs.separator)
.filter(
(filePath: string) =>
!allChangedFiles.paths.split(inputs.separator).includes(filePath)
)
const onlyChanged =
otherChangedFiles.length === 0 &&
allChangedFiles.paths.length > 0 &&
filePatterns.length > 0
await setOutput({
key: getOutputKey('only_changed', outputPrefix),
value: onlyChanged,
inputs
})
await setOutput({
key: getOutputKey('other_changed_files', outputPrefix),
value: otherChangedFiles.join(inputs.separator),
inputs
})
await setOutput({
key: getOutputKey('other_changed_files_count', outputPrefix),
value: otherChangedFiles.length.toString(),
inputs
})
const allModifiedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [
ChangeTypeEnum.Added,
ChangeTypeEnum.Copied,
ChangeTypeEnum.Modified,
ChangeTypeEnum.Renamed,
ChangeTypeEnum.Deleted
]
})
core.debug(`All modified files: ${allModifiedFiles}`)
await setOutput({
key: getOutputKey('all_modified_files', outputPrefix),
value: allModifiedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('all_modified_files_count', outputPrefix),
value: allModifiedFiles.count,
inputs
})
await setOutput({
key: getOutputKey('any_modified', outputPrefix),
value: allModifiedFiles.paths.length > 0 && filePatterns.length > 0,
inputs
})
const allOtherModifiedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allDiffFiles,
changeTypes: [
ChangeTypeEnum.Added,
ChangeTypeEnum.Copied,
ChangeTypeEnum.Modified,
ChangeTypeEnum.Renamed,
ChangeTypeEnum.Deleted
]
})
const otherModifiedFiles = allOtherModifiedFiles.paths
.split(inputs.separator)
.filter(
(filePath: string) =>
!allModifiedFiles.paths.split(inputs.separator).includes(filePath)
)
const onlyModified =
otherModifiedFiles.length === 0 &&
allModifiedFiles.paths.length > 0 &&
filePatterns.length > 0
await setOutput({
key: getOutputKey('only_modified', outputPrefix),
value: onlyModified,
inputs
})
await setOutput({
key: getOutputKey('other_modified_files', outputPrefix),
value: otherModifiedFiles.join(inputs.separator),
inputs
})
await setOutput({
key: getOutputKey('other_modified_files_count', outputPrefix),
value: otherModifiedFiles.length.toString(),
inputs
})
const deletedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allFilteredDiffFiles,
changeTypes: [ChangeTypeEnum.Deleted]
})
core.debug(`Deleted files: ${deletedFiles}`)
await setOutput({
key: getOutputKey('deleted_files', outputPrefix),
value: deletedFiles.paths,
inputs
})
await setOutput({
key: getOutputKey('deleted_files_count', outputPrefix),
value: deletedFiles.count,
inputs
})
await setOutput({
key: getOutputKey('any_deleted', outputPrefix),
value: deletedFiles.paths.length > 0 && filePatterns.length > 0,
inputs
})
const allOtherDeletedFiles = await getChangeTypeFiles({
inputs,
changedFiles: allDiffFiles,
changeTypes: [ChangeTypeEnum.Deleted]
})
const otherDeletedFiles = allOtherDeletedFiles.paths
.split(inputs.separator)
.filter(
filePath => !deletedFiles.paths.split(inputs.separator).includes(filePath)
)
const onlyDeleted =
otherDeletedFiles.length === 0 &&
deletedFiles.paths.length > 0 &&
filePatterns.length > 0
await setOutput({
key: getOutputKey('only_deleted', outputPrefix),
value: onlyDeleted,
inputs
})
await setOutput({
key: getOutputKey('other_deleted_files', outputPrefix),
value: otherDeletedFiles.join(inputs.separator),
inputs
})
await setOutput({
key: getOutputKey('other_deleted_files_count', outputPrefix),
value: otherDeletedFiles.length.toString(),
inputs
})
}

View File

@@ -15,9 +15,11 @@ import {
} from './utils'
const getCurrentSHA = async ({
env,
inputs,
workingDirectory
}: {
env: Env
inputs: Inputs
workingDirectory: string
}): Promise<string> => {
@@ -47,7 +49,18 @@ const getCurrentSHA = async ({
}
} else {
if (!currentSha) {
currentSha = await getHeadSha({cwd: workingDirectory})
if (
env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA &&
(await verifyCommitSha({
sha: env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA,
cwd: workingDirectory,
showAsErrorMessage: false
})) === 0
) {
currentSha = env.GITHUB_EVENT_PULL_REQUEST_HEAD_SHA
} else {
currentSha = await getHeadSha({cwd: workingDirectory})
}
}
}
@@ -72,7 +85,7 @@ export const getSHAForPushEvent = async (
workingDirectory: string,
isShallow: boolean,
hasSubmodule: boolean,
gitExtraArgs: string[],
gitFetchExtraArgs: string[],
isTag: boolean
): Promise<DiffResult> => {
let targetBranch = env.GITHUB_REF_NAME
@@ -89,7 +102,7 @@ export const getSHAForPushEvent = async (
await gitFetch({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
@@ -101,7 +114,7 @@ export const getSHAForPushEvent = async (
await gitFetch({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
@@ -115,7 +128,7 @@ export const getSHAForPushEvent = async (
await gitFetchSubmodules({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`
@@ -124,7 +137,7 @@ export const getSHAForPushEvent = async (
}
}
const currentSha = await getCurrentSHA({inputs, workingDirectory})
const currentSha = await getCurrentSHA({env, inputs, workingDirectory})
let previousSha = inputs.baseSha
const diff = '..'
@@ -250,7 +263,7 @@ export const getSHAForPullRequestEvent = async (
workingDirectory: string,
isShallow: boolean,
hasSubmodule: boolean,
gitExtraArgs: string[]
gitFetchExtraArgs: string[]
): Promise<DiffResult> => {
let targetBranch = env.GITHUB_EVENT_PULL_REQUEST_BASE_REF
const currentBranch = env.GITHUB_EVENT_PULL_REQUEST_HEAD_REF
@@ -264,7 +277,7 @@ export const getSHAForPullRequestEvent = async (
let prFetchExitCode = await gitFetch({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
'origin',
@@ -276,7 +289,7 @@ export const getSHAForPullRequestEvent = async (
prFetchExitCode = await gitFetch({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
@@ -297,7 +310,7 @@ export const getSHAForPullRequestEvent = async (
await gitFetch({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
@@ -310,7 +323,7 @@ export const getSHAForPullRequestEvent = async (
await gitFetchSubmodules({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`
@@ -321,7 +334,7 @@ export const getSHAForPullRequestEvent = async (
core.info('Completed fetching more history.')
}
const currentSha = await getCurrentSHA({inputs, workingDirectory})
const currentSha = await getCurrentSHA({env, inputs, workingDirectory})
let previousSha = inputs.baseSha
let diff = '...'
@@ -336,7 +349,7 @@ export const getSHAForPullRequestEvent = async (
throw new Error('Similar commit hashes detected.')
}
await verifyCommitSha({sha: currentSha, cwd: workingDirectory})
await verifyCommitSha({sha: previousSha, cwd: workingDirectory})
core.debug(`Previous SHA: ${previousSha}`)
return {
@@ -359,12 +372,25 @@ export const getSHAForPullRequestEvent = async (
if (inputs.sinceLastRemoteCommit) {
previousSha = env.GITHUB_EVENT_BEFORE
if (!previousSha) {
previousSha = await getParentSha({cwd: workingDirectory})
}
if (
!previousSha ||
(previousSha &&
(await verifyCommitSha({sha: previousSha, cwd: workingDirectory})) !==
0)
) {
core.warning(
'Unable to locate the remote branch head sha. Falling back to the previous commit in the local history.'
)
previousSha = await getParentSha({
cwd: workingDirectory
})
if (!previousSha) {
previousSha = env.GITHUB_EVENT_PULL_REQUEST_BASE_SHA
if (!previousSha) {
core.warning(
'Unable to locate the previous commit in the local history. Falling back to the pull request base sha.'
)
previousSha = env.GITHUB_EVENT_PULL_REQUEST_BASE_SHA
}
}
} else {
previousSha = await getRemoteBranchHeadSha({
@@ -378,12 +404,12 @@ export const getSHAForPullRequestEvent = async (
if (isShallow) {
if (
await canDiffCommits({
!(await canDiffCommits({
cwd: workingDirectory,
sha1: previousSha,
sha2: currentSha,
diff
})
}))
) {
core.debug(
'Merge base is not in the local history, fetching remote target branch...'
@@ -393,7 +419,7 @@ export const getSHAForPullRequestEvent = async (
await gitFetch({
cwd: workingDirectory,
args: [
...gitExtraArgs,
...gitFetchExtraArgs,
'-u',
'--progress',
`--deepen=${inputs.fetchDepth}`,
@@ -458,9 +484,28 @@ export const getSHAForPullRequestEvent = async (
core.error(
`Similar commit hashes detected: previous sha: ${previousSha} is equivalent to the current sha: ${currentSha}.`
)
core.error(
`Please verify that both commits are valid, and increase the fetch_depth to a number higher than ${inputs.fetchDepth}.`
)
// This occurs if a PR is created from a forked repository and the event is pull_request_target.
// - name: Checkout to branch
// uses: actions/checkout@v3
// Without setting the repository to use the same repository as the pull request will cause the previousSha
// to be the same as the currentSha since the currentSha cannot be found in the local history.
// The solution is to use:
// - name: Checkout to branch
// uses: actions/checkout@v3
// with:
// repository: ${{ github.event.pull_request.head.repo.full_name }}
if (env.GITHUB_EVENT_NAME === 'pull_request_target') {
core.warning(
'If this pull request is from a forked repository, please set the checkout action `repository` input to the same repository as the pull request.'
)
core.warning(
'This can be done by setting actions/checkout `repository` to ${{ github.event.pull_request.head.repo.full_name }}'
)
} else {
core.error(
`Please verify that both commits are valid, and increase the fetch_depth to a number higher than ${inputs.fetchDepth}.`
)
}
throw new Error('Similar commit hashes detected.')
}

View File

@@ -2,25 +2,30 @@ import {promises as fs} from 'fs'
import * as core from '@actions/core'
export type Env = {
GITHUB_EVENT_PULL_REQUEST_HEAD_REF: string
GITHUB_EVENT_PULL_REQUEST_BASE_REF: string
GITHUB_EVENT_BEFORE: string
GITHUB_REF_NAME: string
GITHUB_REF: string
GITHUB_WORKSPACE: string
GITHUB_EVENT_ACTION: string
GITHUB_EVENT_NAME: string
GITHUB_EVENT_FORCED: string
GITHUB_EVENT_BEFORE: string
GITHUB_EVENT_BASE_REF: string
GITHUB_EVENT_RELEASE_TARGET_COMMITISH: string
GITHUB_EVENT_HEAD_REPO_FORK: string
GITHUB_WORKSPACE: string
GITHUB_EVENT_FORCED: string
GITHUB_EVENT_PULL_REQUEST_NUMBER: string
GITHUB_EVENT_PULL_REQUEST_BASE_SHA: string
GITHUB_EVENT_PULL_REQUEST_HEAD_SHA: string
GITHUB_EVENT_PULL_REQUEST_HEAD_REF: string
GITHUB_EVENT_PULL_REQUEST_BASE_REF: string
}
type GithubEvent = {
action?: string
forced?: string
pull_request?: {
head: {
ref: string
sha: string
}
base: {
ref: string
@@ -33,8 +38,10 @@ type GithubEvent = {
}
before?: string
base_ref?: string
head_repo?: {
fork: string
head?: {
repo?: {
fork: string
}
}
}
@@ -55,12 +62,15 @@ export const getEnv = async (): Promise<Env> => {
GITHUB_EVENT_BASE_REF: eventJson.base_ref || '',
GITHUB_EVENT_RELEASE_TARGET_COMMITISH:
eventJson.release?.target_commitish || '',
GITHUB_EVENT_HEAD_REPO_FORK: eventJson.head_repo?.fork || '',
GITHUB_EVENT_HEAD_REPO_FORK: eventJson.head?.repo?.fork || '',
GITHUB_EVENT_PULL_REQUEST_NUMBER: eventJson.pull_request?.number || '',
GITHUB_EVENT_PULL_REQUEST_BASE_SHA: eventJson.pull_request?.base?.sha || '',
GITHUB_EVENT_PULL_REQUEST_HEAD_SHA: eventJson.pull_request?.head?.sha || '',
GITHUB_EVENT_FORCED: eventJson.forced || '',
GITHUB_EVENT_ACTION: eventJson.action || '',
GITHUB_REF_NAME: process.env.GITHUB_REF_NAME || '',
GITHUB_REF: process.env.GITHUB_REF || '',
GITHUB_WORKSPACE: process.env.GITHUB_WORKSPACE || ''
GITHUB_WORKSPACE: process.env.GITHUB_WORKSPACE || '',
GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || ''
}
}

View File

@@ -5,10 +5,16 @@ export type Inputs = {
filesSeparator: string
filesFromSourceFile: string
filesFromSourceFileSeparator: string
filesYaml: string
filesYamlFromSourceFile: string
filesYamlFromSourceFileSeparator: string
filesIgnore: string
filesIgnoreSeparator: string
filesIgnoreFromSourceFile: string
filesIgnoreFromSourceFileSeparator: string
filesIgnoreYaml: string
filesIgnoreYamlFromSourceFile: string
filesIgnoreYamlFromSourceFileSeparator: string
separator: string
includeAllOldNewRenamedFiles: boolean
oldNewSeparator: string
@@ -23,12 +29,16 @@ export type Inputs = {
dirNames: boolean
dirNamesMaxDepth?: number
dirNamesExcludeRoot: boolean
dirNamesExcludeCurrentDir: boolean
json: boolean
escapeJson: boolean
fetchDepth?: number
sinceLastRemoteCommit: boolean
writeOutputFiles: boolean
outputDir: string
outputRenamedFilesAsDeletedAndAdded: boolean
recoverDeletedFiles: boolean
recoverDeletedFilesToDestination: string
}
export const getInputs = (): Inputs => {
@@ -52,6 +62,17 @@ export const getInputs = (): Inputs => {
trimWhitespace: false
}
)
const filesYaml = core.getInput('files_yaml', {required: false})
const filesYamlFromSourceFile = core.getInput('files_yaml_from_source_file', {
required: false
})
const filesYamlFromSourceFileSeparator = core.getInput(
'files_yaml_from_source_file_separator',
{
required: false,
trimWhitespace: false
}
)
const filesIgnoreFromSourceFile = core.getInput(
'files_ignore_from_source_file',
{required: false}
@@ -63,6 +84,18 @@ export const getInputs = (): Inputs => {
trimWhitespace: false
}
)
const filesIgnoreYaml = core.getInput('files_ignore_yaml', {required: false})
const filesIgnoreYamlFromSourceFile = core.getInput(
'files_ignore_yaml_from_source_file',
{required: false}
)
const filesIgnoreYamlFromSourceFileSeparator = core.getInput(
'files_ignore_yaml_from_source_file_separator',
{
required: false,
trimWhitespace: false
}
)
const separator = core.getInput('separator', {
required: true,
trimWhitespace: false
@@ -93,6 +126,12 @@ export const getInputs = (): Inputs => {
const dirNamesExcludeRoot = core.getBooleanInput('dir_names_exclude_root', {
required: false
})
const dirNamesExcludeCurrentDir = core.getBooleanInput(
'dir_names_exclude_current_dir',
{
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})
@@ -104,16 +143,33 @@ export const getInputs = (): Inputs => {
required: false
})
const outputDir = core.getInput('output_dir', {required: false})
const outputRenamedFilesAsDeletedAndAdded = core.getBooleanInput(
'output_renamed_files_as_deleted_and_added',
{required: false}
)
const recoverDeletedFiles = core.getBooleanInput('recover_deleted_files', {
required: false
})
const recoverDeletedFilesToDestination = core.getInput(
'recover_deleted_files_to_destination',
{required: false}
)
const inputs: Inputs = {
files,
filesSeparator,
filesFromSourceFile,
filesFromSourceFileSeparator,
filesYaml,
filesYamlFromSourceFile,
filesYamlFromSourceFileSeparator,
filesIgnore,
filesIgnoreSeparator,
filesIgnoreFromSourceFile,
filesIgnoreFromSourceFileSeparator,
filesIgnoreYaml,
filesIgnoreYamlFromSourceFile,
filesIgnoreYamlFromSourceFileSeparator,
separator,
includeAllOldNewRenamedFiles,
oldNewSeparator,
@@ -127,11 +183,15 @@ export const getInputs = (): Inputs => {
diffRelative,
dirNames,
dirNamesExcludeRoot,
dirNamesExcludeCurrentDir,
json,
escapeJson,
sinceLastRemoteCommit,
writeOutputFiles,
outputDir
outputDir,
outputRenamedFilesAsDeletedAndAdded,
recoverDeletedFiles,
recoverDeletedFilesToDestination
}
if (fetchDepth) {

View File

@@ -1,16 +1,18 @@
import * as core from '@actions/core'
import path from 'path'
import {getDiffFiles, getRenamedFiles} from './changedFiles'
import {getAllDiffFiles, getRenamedFiles} from './changedFiles'
import {setChangedFilesOutput} from './changedFilesOutput'
import {
DiffResult,
getSHAForPullRequestEvent,
getSHAForPushEvent,
DiffResult
getSHAForPushEvent
} from './commitSha'
import {getEnv} from './env'
import {getInputs} from './inputs'
import {
getFilePatterns,
getSubmodulePath,
getYamlFilePatterns,
isRepoShallow,
setOutput,
submoduleExists,
@@ -52,8 +54,10 @@ export async function run(): Promise<void> {
)
const isShallow = await isRepoShallow({cwd: workingDirectory})
const hasSubmodule = await submoduleExists({cwd: workingDirectory})
let gitExtraArgs = ['--no-tags', '--prune', '--recurse-submodules']
let gitFetchExtraArgs = ['--no-tags', '--prune', '--recurse-submodules']
const isTag = env.GITHUB_REF?.startsWith('refs/tags/')
const outputRenamedFilesAsDeletedAndAdded =
inputs.outputRenamedFilesAsDeletedAndAdded
let submodulePaths: string[] = []
if (hasSubmodule) {
@@ -61,31 +65,35 @@ export async function run(): Promise<void> {
}
if (isTag) {
gitExtraArgs = ['--prune', '--no-recurse-submodules']
gitFetchExtraArgs = ['--prune', '--no-recurse-submodules']
}
let diffResult: DiffResult
if (!env.GITHUB_EVENT_PULL_REQUEST_BASE_REF) {
core.info('Running on a push event...')
core.info(`Running on a ${env.GITHUB_EVENT_NAME || 'push'} event...`)
diffResult = await getSHAForPushEvent(
inputs,
env,
workingDirectory,
isShallow,
hasSubmodule,
gitExtraArgs,
gitFetchExtraArgs,
isTag
)
} else {
core.info('Running on a pull request event...')
core.info(
`Running on a ${env.GITHUB_EVENT_NAME || 'pull_request'} (${
env.GITHUB_EVENT_ACTION
}) event...`
)
diffResult = await getSHAForPullRequestEvent(
inputs,
env,
workingDirectory,
isShallow,
hasSubmodule,
gitExtraArgs
gitFetchExtraArgs
)
}
@@ -99,296 +107,72 @@ export async function run(): Promise<void> {
`Retrieving changes between ${diffResult.previousSha} (${diffResult.targetBranch}) → ${diffResult.currentSha} (${diffResult.currentBranch})`
)
const allDiffFiles = await getAllDiffFiles({
workingDirectory,
hasSubmodule,
diffResult,
submodulePaths,
outputRenamedFilesAsDeletedAndAdded
})
core.debug(`All diff files: ${JSON.stringify(allDiffFiles)}`)
core.info('All Done!')
core.endGroup()
const filePatterns = await getFilePatterns({
inputs,
workingDirectory
})
core.debug(`File patterns: ${filePatterns}`)
const addedFiles = await getDiffFiles({
if (filePatterns.length > 0) {
core.startGroup('changed-files-patterns')
await setChangedFilesOutput({
allDiffFiles,
filePatterns,
inputs,
workingDirectory,
diffResult
})
core.info('All Done!')
core.endGroup()
}
const yamlFilePatterns = await getYamlFilePatterns({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'A',
filePatterns,
submodulePaths
})
core.debug(`Added files: ${addedFiles}`)
await setOutput({
key: 'added_files',
value: addedFiles,
inputs
workingDirectory
})
core.debug(`Yaml file patterns: ${JSON.stringify(yamlFilePatterns)}`)
const copiedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'C',
filePatterns,
submodulePaths
})
core.debug(`Copied files: ${copiedFiles}`)
await setOutput({
key: 'copied_files',
value: copiedFiles,
inputs
})
if (Object.keys(yamlFilePatterns).length > 0) {
for (const key of Object.keys(yamlFilePatterns)) {
core.startGroup(`changed-files-yaml-${key}`)
await setChangedFilesOutput({
allDiffFiles,
filePatterns: yamlFilePatterns[key],
outputPrefix: key,
inputs,
workingDirectory,
diffResult
})
core.info('All Done!')
core.endGroup()
}
}
const modifiedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'M',
filePatterns,
submodulePaths
})
core.debug(`Modified files: ${modifiedFiles}`)
await setOutput({
key: 'modified_files',
value: modifiedFiles,
inputs
})
const renamedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'R',
filePatterns,
submodulePaths
})
core.debug(`Renamed files: ${renamedFiles}`)
await setOutput({
key: 'renamed_files',
value: renamedFiles,
inputs
})
const typeChangedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'T',
filePatterns,
submodulePaths
})
core.debug(`Type changed files: ${typeChangedFiles}`)
await setOutput({
key: 'type_changed_files',
value: typeChangedFiles,
inputs
})
const unmergedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'U',
filePatterns,
submodulePaths
})
core.debug(`Unmerged files: ${unmergedFiles}`)
await setOutput({
key: 'unmerged_files',
value: unmergedFiles,
inputs
})
const unknownFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'X',
filePatterns,
submodulePaths
})
core.debug(`Unknown files: ${unknownFiles}`)
await setOutput({
key: 'unknown_files',
value: unknownFiles,
inputs
})
const allChangedAndModifiedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'ACDMRTUX',
filePatterns,
submodulePaths
})
core.debug(`All changed and modified files: ${allChangedAndModifiedFiles}`)
await setOutput({
key: 'all_changed_and_modified_files',
value: allChangedAndModifiedFiles,
inputs
})
const allChangedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'ACMR',
filePatterns,
submodulePaths
})
core.debug(`All changed files: ${allChangedFiles}`)
await setOutput({
key: 'all_changed_files',
value: allChangedFiles,
inputs
})
await setOutput({
key: 'any_changed',
value: allChangedFiles.length > 0 && filePatterns.length > 0,
inputs
})
const allOtherChangedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'ACMR',
submodulePaths
})
core.debug(`All other changed files: ${allOtherChangedFiles}`)
const otherChangedFiles = allOtherChangedFiles
.split(inputs.separator)
.filter(
filePath => !allChangedFiles.split(inputs.separator).includes(filePath)
)
const onlyChanged =
otherChangedFiles.length === 0 && allChangedFiles.length > 0
await setOutput({
key: 'only_changed',
value: onlyChanged,
inputs
})
await setOutput({
key: 'other_changed_files',
value: otherChangedFiles.join(inputs.separator),
inputs
})
const allModifiedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'ACMRD',
filePatterns,
submodulePaths
})
core.debug(`All modified files: ${allModifiedFiles}`)
await setOutput({
key: 'all_modified_files',
value: allModifiedFiles,
inputs
})
await setOutput({
key: 'any_modified',
value: allModifiedFiles.length > 0 && filePatterns.length > 0,
inputs
})
const allOtherModifiedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'ACMRD',
submodulePaths
})
const otherModifiedFiles = allOtherModifiedFiles
.split(inputs.separator)
.filter(
filePath => !allModifiedFiles.split(inputs.separator).includes(filePath)
)
const onlyModified =
otherModifiedFiles.length === 0 && allModifiedFiles.length > 0
await setOutput({
key: 'only_modified',
value: onlyModified,
inputs
})
await setOutput({
key: 'other_modified_files',
value: otherModifiedFiles.join(inputs.separator),
inputs
})
const deletedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'D',
filePatterns,
submodulePaths
})
core.debug(`Deleted files: ${deletedFiles}`)
await setOutput({
key: 'deleted_files',
value: deletedFiles,
inputs
})
await setOutput({
key: 'any_deleted',
value: deletedFiles.length > 0 && filePatterns.length > 0,
inputs
})
const allOtherDeletedFiles = await getDiffFiles({
inputs,
workingDirectory,
hasSubmodule,
diffResult,
diffFilter: 'D',
submodulePaths
})
const otherDeletedFiles = allOtherDeletedFiles
.split(inputs.separator)
.filter(
filePath => !deletedFiles.split(inputs.separator).includes(filePath)
)
const onlyDeleted = otherDeletedFiles.length === 0 && deletedFiles.length > 0
await setOutput({
key: 'only_deleted',
value: onlyDeleted,
inputs
})
await setOutput({
key: 'other_deleted_files',
value: otherDeletedFiles.join(inputs.separator),
inputs
})
if (filePatterns.length === 0 && Object.keys(yamlFilePatterns).length === 0) {
core.startGroup('changed-files-all')
await setChangedFilesOutput({
allDiffFiles,
inputs,
workingDirectory,
diffResult
})
core.info('All Done!')
core.endGroup()
}
if (inputs.includeAllOldNewRenamedFiles) {
core.startGroup('changed-files-all-old-new-renamed-files')
const allOldNewRenamedFiles = await getRenamedFiles({
inputs,
workingDirectory,
@@ -399,14 +183,17 @@ export async function run(): Promise<void> {
core.debug(`All old new renamed files: ${allOldNewRenamedFiles}`)
await setOutput({
key: 'all_old_new_renamed_files',
value: allOldNewRenamedFiles,
value: allOldNewRenamedFiles.paths,
inputs
})
await setOutput({
key: 'all_old_new_renamed_files_count',
value: allOldNewRenamedFiles.count,
inputs
})
core.info('All Done!')
core.endGroup()
}
core.info('All Done!')
core.endGroup()
}
/* istanbul ignore if */

View File

@@ -2,9 +2,13 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import {createReadStream, promises as fs} from 'fs'
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 {Inputs} from './inputs'
@@ -156,7 +160,7 @@ const getFilesFromSourceFile = async ({
filePaths: string[]
excludedFiles?: boolean
}): Promise<string[]> => {
const lines = []
const lines: string[] = []
for (const filePath of filePaths) {
for await (const line of lineOfFileGenerator({filePath, excludedFiles})) {
lines.push(line)
@@ -288,7 +292,7 @@ export const getSubmodulePath = async ({
return stdout
.trim()
.split('\n')
.map(line => normalizePath(line.split(' ')[1]))
.map((line: string) => normalizePath(line.split(' ')[1]))
}
export const gitSubmoduleDiffSHA = async ({
@@ -389,7 +393,7 @@ export const gitRenamedFiles = async ({
.trim()
.split('\n')
.filter(Boolean)
.map(line => {
.map((line: string) => {
core.debug(`Renamed file: ${line}`)
const [, oldPath, newPath] = line.split('\t')
if (isSubmodule) {
@@ -403,32 +407,30 @@ export const gitRenamedFiles = async ({
})
}
export const gitDiff = async ({
export const getAllChangedFiles = async ({
cwd,
sha1,
sha2,
diff,
diffFilter,
filePatterns = [],
isSubmodule = false,
parentDir = ''
parentDir = '',
outputRenamedFilesAsDeletedAndAdded = false
}: {
cwd: string
sha1: string
sha2: string
diffFilter: string
diff: string
filePatterns?: string[]
isSubmodule?: boolean
parentDir?: string
}): Promise<string[]> => {
outputRenamedFilesAsDeletedAndAdded?: boolean
}): Promise<ChangedFiles> => {
const {exitCode, stdout, stderr} = await exec.getExecOutput(
'git',
[
'diff',
'--name-only',
'--name-status',
'--ignore-submodules=all',
`--diff-filter=${diffFilter}`,
`--diff-filter=ACDMRTUX`,
`${sha1}${diff}${sha2}`
],
{
@@ -437,6 +439,16 @@ export const gitDiff = async ({
silent: process.env.RUNNER_DEBUG !== '1'
}
)
const changedFiles: ChangedFiles = {
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
if (exitCode !== 0) {
if (isSubmodule) {
@@ -453,28 +465,67 @@ export const gitDiff = async ({
)
}
return []
return changedFiles
}
const files = stdout
.split('\n')
.filter(Boolean)
.map(p => {
if (isSubmodule) {
return normalizePath(path.join(parentDir, p))
const lines = stdout.split('\n').filter(Boolean)
for (const line of lines) {
const [changeType, filePath, newPath = ''] = line.split('\t')
const normalizedFilePath = isSubmodule
? normalizePath(path.join(parentDir, filePath))
: normalizePath(filePath)
const normalizedNewPath = isSubmodule
? normalizePath(path.join(parentDir, newPath))
: normalizePath(newPath)
if (changeType.startsWith('R')) {
if (outputRenamedFilesAsDeletedAndAdded) {
changedFiles[ChangeTypeEnum.Deleted].push(normalizedFilePath)
changedFiles[ChangeTypeEnum.Added].push(normalizedNewPath)
} else {
changedFiles[ChangeTypeEnum.Renamed].push(normalizedFilePath)
}
return normalizePath(p)
})
} else {
changedFiles[changeType as ChangeTypeEnum].push(normalizedFilePath)
}
}
return changedFiles
}
if (filePatterns.length === 0) {
return files
export const getFilteredChangedFiles = async ({
allDiffFiles,
filePatterns
}: {
allDiffFiles: ChangedFiles
filePatterns: string[]
}): Promise<ChangedFiles> => {
const changedFiles: ChangedFiles = {
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}
const hasFilePatterns = filePatterns.length > 0
for (const changeType of Object.keys(allDiffFiles)) {
const files = allDiffFiles[changeType as ChangeTypeEnum]
if (hasFilePatterns) {
changedFiles[changeType as ChangeTypeEnum] = mm(files, filePatterns, {
dot: true,
windows: IS_WINDOWS,
noext: true
})
} else {
changedFiles[changeType as ChangeTypeEnum] = files
}
}
return mm(files, filePatterns, {
dot: true,
windows: IS_WINDOWS,
noext: true
})
return changedFiles
}
export const gitLog = async ({
@@ -642,11 +693,11 @@ export const canDiffCommits = async ({
export const getDirnameMaxDepth = ({
pathStr,
dirNamesMaxDepth,
excludeRoot
excludeCurrentDir
}: {
pathStr: string
dirNamesMaxDepth?: number
excludeRoot?: boolean
excludeCurrentDir?: boolean
}): string => {
const pathArr = dirname(pathStr).split(path.sep)
const maxDepth = Math.min(dirNamesMaxDepth || pathArr.length, pathArr.length)
@@ -656,7 +707,7 @@ export const getDirnameMaxDepth = ({
output = path.join(output, pathArr[i])
}
if (excludeRoot && output === '.') {
if (excludeCurrentDir && output === '.') {
return ''
}
@@ -760,10 +811,10 @@ export const getFilePatterns = async ({
if (pattern.endsWith('/')) {
return `${pattern}**`
} else {
const pathParts = pattern.split('/')
const pathParts = pattern.split(path.sep)
const lastPart = pathParts[pathParts.length - 1]
if (!lastPart.includes('.')) {
return `${pattern}/**`
return `${pattern}${path.sep}**`
} else {
return pattern
}
@@ -771,6 +822,193 @@ export const getFilePatterns = async ({
})
}
// Example YAML input:
// filesYaml: |
// frontend:
// - frontend/**
// backend:
// - backend/**
// test: test/**
// shared: &shared
// - common/**
// lib:
// - *shared
// - lib/**
// Return an Object:
// {
// frontend: ['frontend/**'],
// backend: ['backend/**'],
// test: ['test/**'],
// shared: ['common/**'],
// lib: ['common/**', 'lib/**']
// }
type YamlObject = {
[key: string]: string | string[] | [string[], string]
}
const getYamlFilePatternsFromContents = async ({
content = '',
filePath = '',
excludedFiles = false
}: {
content?: string
filePath?: string
excludedFiles?: boolean
}): Promise<Record<string, string[]>> => {
const filePatterns: Record<string, string[]> = {}
let source = ''
if (filePath) {
if (!(await exists(filePath))) {
core.error(`File does not exist: ${filePath}`)
throw new Error(`File does not exist: ${filePath}`)
}
source = await readFile(filePath, 'utf8')
} else {
source = content
}
const doc = parseDocument(source, {merge: true, schema: 'failsafe'})
if (doc.errors.length > 0) {
if (filePath) {
core.warning(`YAML errors in ${filePath}: ${doc.errors}`)
} else {
core.warning(`YAML errors: ${doc.errors}`)
}
}
if (doc.warnings.length > 0) {
if (filePath) {
core.warning(`YAML warnings in ${filePath}: ${doc.warnings}`)
} else {
core.warning(`YAML warnings: ${doc.warnings}`)
}
}
const yamlObject = doc.toJS() as YamlObject
for (const key in yamlObject) {
let value = yamlObject[key]
if (typeof value === 'string' && value.includes('\n')) {
value = value.split('\n')
}
if (typeof value === 'string') {
value = value.trim()
if (value) {
filePatterns[key] = [
excludedFiles && !value.startsWith('!') ? `!${value}` : value
]
}
} else if (Array.isArray(value)) {
filePatterns[key] = flattenDeep(value)
.filter(v => v.trim() !== '')
.map(v => {
if (excludedFiles && !v.startsWith('!')) {
v = `!${v}`
}
return v
})
}
}
return filePatterns
}
export const getYamlFilePatterns = async ({
inputs,
workingDirectory
}: {
inputs: Inputs
workingDirectory: string
}): Promise<Record<string, string[]>> => {
let filePatterns: Record<string, string[]> = {}
if (inputs.filesYaml) {
filePatterns = {
...(await getYamlFilePatternsFromContents({content: inputs.filesYaml}))
}
}
if (inputs.filesYamlFromSourceFile) {
const inputFilesYamlFromSourceFile = inputs.filesYamlFromSourceFile
.split(inputs.filesYamlFromSourceFileSeparator)
.filter(p => p !== '')
.map(p => path.join(workingDirectory, p))
core.debug(`files yaml from source file: ${inputFilesYamlFromSourceFile}`)
for (const filePath of inputFilesYamlFromSourceFile) {
const newFilePatterns = await getYamlFilePatternsFromContents({filePath})
for (const key in newFilePatterns) {
if (key in filePatterns) {
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
}
}
}
if (inputs.filesIgnoreYaml) {
const newIgnoreFilePatterns = await getYamlFilePatternsFromContents({
content: inputs.filesIgnoreYaml,
excludedFiles: true
})
for (const key in newIgnoreFilePatterns) {
if (key in filePatterns) {
core.warning(
`files_ignore_yaml: Duplicated key ${key} detected, the ${filePatterns[key]} will be overwritten by ${newIgnoreFilePatterns[key]}.`
)
}
}
}
if (inputs.filesIgnoreYamlFromSourceFile) {
const inputFilesIgnoreYamlFromSourceFile =
inputs.filesIgnoreYamlFromSourceFile
.split(inputs.filesIgnoreYamlFromSourceFileSeparator)
.filter(p => p !== '')
.map(p => path.join(workingDirectory, p))
core.debug(
`files ignore yaml from source file: ${inputFilesIgnoreYamlFromSourceFile}`
)
for (const filePath of inputFilesIgnoreYamlFromSourceFile) {
const newIgnoreFilePatterns = await getYamlFilePatternsFromContents({
filePath,
excludedFiles: true
})
for (const key in newIgnoreFilePatterns) {
if (key in filePatterns) {
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
}
}
}
return filePatterns
}
export const setOutput = async ({
key,
value,
@@ -784,7 +1022,7 @@ export const setOutput = async ({
core.setOutput(key, cleanedValue)
if (inputs.writeOutputFiles) {
const outputDir = inputs.outputDir || '.github/outputs'
const outputDir = inputs.outputDir
const extension = inputs.json ? 'json' : 'txt'
const outputFilePath = path.join(outputDir, `${key}.${extension}`)
@@ -794,3 +1032,68 @@ export const setOutput = async ({
await fs.writeFile(outputFilePath, cleanedValue.replace(/\\"/g, '"'))
}
}
const getDeletedFileContents = async ({
cwd,
filePath,
sha
}: {
cwd: string
filePath: string
sha: string
}): Promise<string> => {
const {stdout, exitCode, stderr} = await exec.getExecOutput(
'git',
['show', `${sha}:${filePath}`],
{
cwd,
silent: process.env.RUNNER_DEBUG !== '1',
ignoreReturnCode: true
}
)
if (exitCode !== 0) {
throw new Error(
`Error getting file content from git history "${filePath}": ${stderr}`
)
}
return stdout
}
export const recoverDeletedFiles = async ({
inputs,
workingDirectory,
deletedFiles,
sha
}: {
inputs: Inputs
workingDirectory: string
deletedFiles: string[]
sha: string
}): Promise<void> => {
if (inputs.recoverDeletedFiles) {
for (const deletedFile of deletedFiles) {
let target = path.join(workingDirectory, deletedFile)
if (inputs.recoverDeletedFilesToDestination) {
target = path.join(
workingDirectory,
inputs.recoverDeletedFilesToDestination,
deletedFile
)
}
const deletedFileContents = await getDeletedFileContents({
cwd: workingDirectory,
filePath: deletedFile,
sha
})
if (!(await exists(path.dirname(target)))) {
await fs.mkdir(path.dirname(target), {recursive: true})
}
await fs.writeFile(target, deletedFileContents)
}
}
}

16
test/changed-files.yml Normal file
View File

@@ -0,0 +1,16 @@
test:
- test/**.txt
src:
- src/*.ts
- '!src/__tests__/**'
dist:
- dist/**
shared: &shared
- .github/**
common:
- *shared
- .gitignore
multiline: |
test/**
src/*.ts
.github/**

View File

@@ -1 +1 @@
This is a test file with non ascii character in the filename.
This is a test file with non ASCII character in the filename.

722
yarn.lock

File diff suppressed because it is too large Load Diff