### Check out job creating a git bundle and publishing it
### into an Azure artifact for reuse by the subsequent build and test execution phases.
+### If paths is specified, we will create a job using evaluate-changed-paths.yml template
+### for each path specified.
+
+parameters:
+ # Object containing subset include and exclude paths in an array form.
+ # Scenarios:
+ # 1. exclude paths are specified
+ # Will include all paths except the ones in the exclude list.
+ # 2. include paths are specified
+ # Will only include paths specified in the list.
+ # 3. exclude + include:
+ # 1st we evaluate changes for all paths except ones in excluded list. If we can't find
+ # any applicable changes like that, then we evaluate changes for incldued paths
+ # if any of these two finds changes, then a variable will be set to true.
+ # In order to consume this variable you need to reference it via: $[ dependencies.checkout.outputs['SetPathVars_<subset>.containschange'] ]
+ #
+ # Array form example
+ # paths:
+ # - subset: coreclr
+ # include:
+ # - src/libraries/System.Private.CoreLib/*
+ # exclude:
+ # - src/libraries/*
+ #
+ # This example will include ALL path changes except the ones under src/libraries/*!System.Private.CoreLib/*
+ paths: []
+
jobs:
- job: checkout
displayName: Checkout
${{ if ne(variables['System.TeamProject'], 'public') }}:
name: Hosted Mac Internal
-
+
steps:
- checkout: self
clean: true
- publish: $(Build.StagingDirectory)/Checkout.bundle
artifact: Checkout_bundle
displayName: Upload Checkout.bundle
+
+ - ${{ if and(ne(parameters.paths[0], ''), eq(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ each path in parameters.paths }}:
+ - template: evaluate-changed-paths.yml
+ parameters:
+ subsetName: ${{ path.subset }}
+ arguments:
+ - --difftarget origin/$(System.PullRequest.TargetBranch)
+ - --subset ${{ path.subset }}
+ - ${{ if ne(path.include[0], '') }}:
+ - --includepaths '${{ join('+', path.include) }}'
+ - ${{ if ne(path.exclude[0], '') }}:
+ - --excludepaths '${{ join('+', path.exclude) }}'
--- /dev/null
+# This step template evaluates git changes using git based on a include/exclude path filter.
+# For more information on how the path evaluation works look at evaluate-changed-paths.sh docs
+# at the beginning of that file.
+
+parameters:
+ # Name for the subset that we're evaluating changes for.
+ # It is required to name the step correctly and so the variable created can be consumable.
+ subsetName: ''
+ # Array containing the arguments that are to be passed down to evaluate-changed-paths.sh
+ # Note that --azurevariable is always set to containschange, no need to pass it down.
+ arguments: []
+
+steps:
+ - ${{ if ne(parameters.arguments[0], '') }}:
+ - script: eng/pipelines/evaluate-changed-paths.sh
+ --azurevariable containsChange
+ ${{ join(' ', parameters.arguments) }}
+ displayName: Evaluate paths for ${{ parameters.subsetName }}
+ name: ${{ format('SetPathVars_{0}', parameters.subsetName) }} # need a name to access output variable
--- /dev/null
+#!/usr/bin/env bash
+: '
+Scenarios:
+ 1. exclude paths are specified
+ Will include all paths except the ones in the exclude list.
+ 2. include paths are specified
+ Will only include paths specified in the list.
+ 3. exclude + include:
+ 1st we evaluate changes for all paths except ones in excluded list. If we can not find
+ any applicable changes like that, then we evaluate changes for incldued paths
+ if any of these two finds changes, then a variable will be set to true.
+ In order to consume this variable in a yaml pipeline, reference it via: $[ dependencies.<JobName>.outputs["<StepName>_<subset>.containschange"] ]
+
+ Example:
+ -difftarget ''HEAD^1'' -subset coreclr -includepaths ''src/libraries/System.Private.CoreLib/*'' -excludepaths ''src/libraries/*+src/installer/*''
+
+ This example will include ALL path changes except the ones under src/libraries/*!System.Private.CoreLib/*
+'
+
+# Disable globbing in this bash script since we iterate over path patterns
+set -f
+
+# Stop script if unbound variable found (use ${var:-} if intentional)
+set -u
+
+# Stop script if command returns non-zero exit code.
+# Prevents hidden errors caused by missing error code propagation.
+set -e
+
+usage()
+{
+ echo "Script that evaluates changed paths and emits an azure devops variable if the changes contained in the current HEAD against the difftarget meet the includepahts/excludepaths filters:"
+ echo " --difftarget <value> SHA or branch to diff against. (i.e: HEAD^1, origin/master, 0f4hd36, etc.)"
+ echo " --excludepaths <value> Escaped list of paths to exclude from diff separated by '+'. (i.e: 'src/libraries/*+'src/installer/*')"
+ echo " --includepaths <value> Escaped list of paths to include on diff separated by '+'. (i.e: 'src/libraries/System.Private.CoreLib/*')"
+ echo " --subset Subset name for which we're evaluating in order to include it in logs"
+ echo " --azurevariable Name of azure devops variable to create if change meets filter criteria"
+ echo ""
+
+ echo "Arguments can also be passed in with a single hyphen."
+}
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+eng_root=`cd -P "$scriptroot/.." && pwd`
+
+exclude_paths=()
+include_paths=()
+subset_name=''
+azure_variable=''
+diff_target=''
+
+while [[ $# > 0 ]]; do
+ opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')"
+ case "$opt" in
+ -help|-h)
+ usage
+ exit 0
+ ;;
+ -difftarget)
+ diff_target=$2
+ shift
+ ;;
+ -excludepaths)
+ IFS='+' read -r -a tmp <<< $2
+ exclude_paths+=($tmp)
+ shift
+ ;;
+ -includepaths)
+ IFS='+' read -r -a tmp <<< $2
+ include_paths+=($tmp)
+ shift
+ ;;
+ -subset)
+ subset_name=$2
+ shift
+ ;;
+ -azurevariable)
+ azure_variable=$2
+ shift
+ ;;
+ esac
+
+ shift
+done
+
+ci=true # Needed in order to use pipeline-logging-functions.sh
+. "$eng_root/common/pipeline-logging-functions.sh"
+
+# -- expected args --
+# $@: git diff arguments
+customGitDiff() {
+ (
+ set -x
+ git diff -M -C -b --ignore-cr-at-eol --ignore-space-at-eol "$@"
+ )
+}
+
+# runs git diff with supplied filter.
+# -- exit codes --
+# 0: No match was found
+# 1: At least 1 match was found
+#
+# -- expected args --
+# $@: filter string
+probePathsWithExitCode() {
+ local _filter=$@
+ echo ""
+ customGitDiff --exit-code --quiet $diff_target -- $_filter
+}
+
+# -- expected args --
+# $@: filter string
+printMatchedPaths() {
+ local _subset=$subset_name
+ local _filter=$@
+ echo ""
+ echo "----- Matching files for $_subset -----"
+ customGitDiff --name-only $diff_target -- $_filter
+}
+
+probePaths() {
+ local _subset=$subset_name
+ local _azure_devops_var_name=$azure_variable
+ local exclude_path_string=""
+ local include_path_string=""
+ local found_applying_changes=false
+
+ if [[ ${#exclude_paths[@]} -gt 0 ]]; then
+ echo ""
+ echo "******* Probing $_subset exclude paths *******";
+ for _path in "${exclude_paths[@]}"; do
+ echo "$_path"
+ if [[ "$exclude_path_string" == "" ]]; then
+ exclude_path_string=":!$_path"
+ else
+ exclude_path_string="$exclude_path_string :!$_path"
+ fi
+ done
+
+ if ! probePathsWithExitCode $exclude_path_string; then
+ found_applying_changes=true
+ printMatchedPaths $exclude_path_string
+ fi
+ fi
+
+ if [[ $found_applying_changes != true && ${#include_paths[@]} -gt 0 ]]; then
+ echo ""
+ echo "******* Probing $_subset include paths *******";
+ for _path in "${include_paths[@]}"; do
+ echo "$_path"
+ if [[ "$include_path_string" == "" ]]; then
+ include_path_string=":$_path"
+ else
+ include_path_string="$exclude_path_string :$_path"
+ fi
+ done
+
+ if ! probePathsWithExitCode $include_path_string; then
+ found_applying_changes=true
+ printMatchedPaths $include_path_string
+ fi
+ fi
+
+ if [[ $found_applying_changes == true ]]; then
+ echo ""
+ echo "Setting pipeline variable $_azure_devops_var_name=true"
+ Write-PipelineSetVariable -name $_azure_devops_var_name -value true
+ else
+ echo ""
+ echo "No changed files for $_subset"
+ fi
+}
+
+probePaths