Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/matrix-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,16 @@ jobs:
- name: Test
run: |
echo ${{ matrix.files }}

conditional-job:
name: Run Conditional Job
runs-on: ubuntu-latest
needs: [changed-files]
if: contains(needs.changed-files.outputs.matrix, 'README.md') # Conditional check for README
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Execute Conditional Logic
run: |
echo "README.md has been changed. Running conditional job."

11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ To access more examples, navigate to the [Examples](#examples-) section.
# Default: "false"
exclude_submodules: ''

# Exclude symlinks from changed files.
# Type: boolean
# Default: "false"
exclude_symlinks: ''

# Fail when the initial diff
# fails.
# Type: boolean
Expand Down Expand Up @@ -650,6 +655,12 @@ To access more examples, navigate to the [Examples](#examples-) section.
# Default: "false"
skip_initial_fetch: ''

# Do not fail when base
# and head SHAs are identical.
# Type: boolean
# Default: "false"
skip_same_sha: ''

# Tags pattern to ignore.
# Type: string
tags_ignore_pattern: ''
Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ inputs:
description: "Exclude changes to submodules."
required: false
default: "false"
exclude_symlinks:
description: "Exclude symlinks from changed files."
required: false
default: "false"
skip_same_sha:
description: "Do not fail when base and head SHAs are identical."
required: false
default: "false"
fetch_missing_history_max_retries:
description: "Maximum number of retries to fetch missing history."
required: false
Expand Down
358 changes: 316 additions & 42 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/__tests__/__snapshots__/inputs.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ exports[`getInputs should correctly parse boolean inputs 1`] = `
"dirNamesIncludeFilesSeparator": "",
"escapeJson": false,
"excludeSubmodules": "false",
"excludeSymlinks": "false",
"failOnInitialDiffError": "false",
"failOnSubmoduleDiffError": "false",
"fetchAdditionalSubmoduleHistory": "false",
Expand Down Expand Up @@ -53,6 +54,7 @@ exports[`getInputs should correctly parse boolean inputs 1`] = `
"since": "",
"sinceLastRemoteCommit": "false",
"skipInitialFetch": "true",
"skipSameSha": "false",
"tagsIgnorePattern": "",
"tagsPattern": "*",
"token": "",
Expand All @@ -76,6 +78,7 @@ exports[`getInputs should correctly parse numeric inputs 1`] = `
"dirNamesMaxDepth": 2,
"escapeJson": false,
"excludeSubmodules": false,
"excludeSymlinks": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
Expand Down Expand Up @@ -115,6 +118,7 @@ exports[`getInputs should correctly parse numeric inputs 1`] = `
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"skipSameSha": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "",
Expand All @@ -137,6 +141,7 @@ exports[`getInputs should correctly parse string inputs 1`] = `
"dirNamesIncludeFilesSeparator": "",
"escapeJson": false,
"excludeSubmodules": false,
"excludeSymlinks": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
Expand Down Expand Up @@ -175,6 +180,7 @@ exports[`getInputs should correctly parse string inputs 1`] = `
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"skipSameSha": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "token",
Expand All @@ -198,6 +204,7 @@ exports[`getInputs should handle invalid numeric inputs correctly 1`] = `
"dirNamesMaxDepth": 2,
"escapeJson": false,
"excludeSubmodules": false,
"excludeSymlinks": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
Expand Down Expand Up @@ -237,6 +244,7 @@ exports[`getInputs should handle invalid numeric inputs correctly 1`] = `
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"skipSameSha": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "",
Expand All @@ -260,6 +268,7 @@ exports[`getInputs should handle negative numeric inputs correctly 1`] = `
"dirNamesMaxDepth": -2,
"escapeJson": false,
"excludeSubmodules": false,
"excludeSymlinks": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
Expand Down Expand Up @@ -299,6 +308,7 @@ exports[`getInputs should handle negative numeric inputs correctly 1`] = `
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"skipSameSha": false,
"tagsIgnorePattern": "",
"tagsPattern": "",
"token": "",
Expand All @@ -321,6 +331,7 @@ exports[`getInputs should return default values when no inputs are provided 1`]
"dirNamesIncludeFilesSeparator": "",
"escapeJson": false,
"excludeSubmodules": false,
"excludeSymlinks": false,
"failOnInitialDiffError": false,
"failOnSubmoduleDiffError": false,
"fetchAdditionalSubmoduleHistory": false,
Expand Down Expand Up @@ -362,6 +373,7 @@ exports[`getInputs should return default values when no inputs are provided 1`]
"since": "",
"sinceLastRemoteCommit": false,
"skipInitialFetch": false,
"skipSameSha": false,
"tagsIgnorePattern": "",
"tagsPattern": "*",
"token": "",
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,8 @@ describe('utils test', () => {
negationPatternsFirst: false,
useRestApi: false,
excludeSubmodules: false,
excludeSymlinks: false,
skipSameSha: false,
fetchMissingHistoryMaxRetries: 20,
usePosixPathSeparator: false,
tagsPattern: '*',
Expand Down
142 changes: 141 additions & 1 deletion src/changedFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
getFilteredChangedFiles,
gitRenamedFiles,
gitSubmoduleDiffSHA,
isSymlinkInGitTree,
isSymlinkOnDisk,
isWindows,
jsonOutput,
setArrayOutput
Expand Down Expand Up @@ -220,7 +222,8 @@ export const getAllDiffFiles = async ({
outputRenamedFilesAsDeletedAndAdded,
fetchAdditionalSubmoduleHistory,
failOnInitialDiffError,
failOnSubmoduleDiffError
failOnSubmoduleDiffError,
submoduleShas
}: {
workingDirectory: string
diffSubmodule: boolean
Expand All @@ -230,6 +233,7 @@ export const getAllDiffFiles = async ({
fetchAdditionalSubmoduleHistory: boolean
failOnInitialDiffError: boolean
failOnSubmoduleDiffError: boolean
submoduleShas?: Record<string, {previousSha?: string; currentSha?: string}>
}): Promise<ChangedFiles> => {
const files = await getAllChangedFiles({
cwd: workingDirectory,
Expand All @@ -256,6 +260,9 @@ export const getAllDiffFiles = async ({
)

if (submoduleShaResult.currentSha && submoduleShaResult.previousSha) {
if (submoduleShas) {
submoduleShas[submodulePath] = submoduleShaResult
}
let diff = '...'

if (
Expand Down Expand Up @@ -300,6 +307,139 @@ export const getAllDiffFiles = async ({
return files
}

export const filterSymlinksFromChangedFiles = async ({
changedFiles,
workingDirectory,
diffResult,
submodulePaths,
submoduleShas
}: {
changedFiles: ChangedFiles
workingDirectory: string
diffResult: DiffResult
submodulePaths: string[]
submoduleShas?: Record<string, {previousSha?: string; currentSha?: string}>
}): Promise<ChangedFiles> => {
const filtered: ChangedFiles = {
[ChangeTypeEnum.Added]: [],
[ChangeTypeEnum.Copied]: [],
[ChangeTypeEnum.Deleted]: [],
[ChangeTypeEnum.Modified]: [],
[ChangeTypeEnum.Renamed]: [],
[ChangeTypeEnum.TypeChanged]: [],
[ChangeTypeEnum.Unmerged]: [],
[ChangeTypeEnum.Unknown]: []
}

const cache = new Map<string, boolean>()
const diskCache = new Map<string, boolean>()

const getSubmoduleContext = (
filePath: string
): {
cwd: string
relativePath: string
currentSha: string
previousSha: string
isSubmoduleRoot: boolean
} => {
const submodulePath = submodulePaths.find(p =>
filePath.startsWith(`${p}${path.sep}`)
)
if (!submodulePath) {
return {
cwd: workingDirectory,
relativePath: filePath,
currentSha: diffResult.currentSha,
previousSha: diffResult.previousSha,
isSubmoduleRoot: false
}
}

if (filePath === submodulePath) {
return {
cwd: workingDirectory,
relativePath: filePath,
currentSha: diffResult.currentSha,
previousSha: diffResult.previousSha,
isSubmoduleRoot: true
}
}

const submoduleWorkingDirectory = path.join(workingDirectory, submodulePath)
const relativePath = filePath.substring(submodulePath.length + 1)
const submoduleSha = submoduleShas?.[submodulePath]

return {
cwd: submoduleWorkingDirectory,
relativePath,
currentSha: submoduleSha?.currentSha || diffResult.currentSha,
previousSha: submoduleSha?.previousSha || diffResult.previousSha,
isSubmoduleRoot: false
}
}

const isSymlinkCached = async ({
cwd,
filePath,
sha,
preferDisk
}: {
cwd: string
filePath: string
sha: string
preferDisk: boolean
}): Promise<boolean> => {
if (preferDisk) {
const diskKey = `${cwd}|disk|${filePath}`
const cachedDisk = diskCache.get(diskKey)
if (cachedDisk !== undefined) {
return cachedDisk
}
const diskResult = await isSymlinkOnDisk({cwd, filePath})
diskCache.set(diskKey, diskResult)
if (diskResult) {
return true
}
}

const treeKey = `${cwd}|${sha}|${filePath}`
const cachedTree = cache.get(treeKey)
if (cachedTree !== undefined) {
return cachedTree
}
const treeResult = await isSymlinkInGitTree({cwd, sha, filePath})
cache.set(treeKey, treeResult)
return treeResult
}

for (const changeType of Object.keys(changedFiles) as ChangeTypeEnum[]) {
const files = changedFiles[changeType] || []
for (const filePath of files) {
const context = getSubmoduleContext(filePath)
if (context.isSubmoduleRoot) {
filtered[changeType].push(filePath)
continue
}

const isDeleted = changeType === ChangeTypeEnum.Deleted
const sha = isDeleted ? context.previousSha : context.currentSha
const isSymlink = await isSymlinkCached({
cwd: context.cwd,
filePath: context.relativePath,
sha,
preferDisk: !isDeleted
})

if (!isSymlink) {
filtered[changeType].push(filePath)
}
}
}

return filtered
}

function* getFilePaths({
inputs,
filePaths,
Expand Down
Loading
Loading