From 9ba76b44d659de171358a0dd5b57418541f014a4 Mon Sep 17 00:00:00 2001 From: Dependabot Standalone Date: Tue, 29 Jul 2025 09:28:28 -0400 Subject: [PATCH 1/5] Added example for azure devops --- .azuredevops/create-pull-requests.sh | 126 +++++++++++++++++++ .azuredevops/dependabot/nuget.yaml | 37 ++++++ .azuredevops/pipelines/example.yaml | 175 +++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 .azuredevops/create-pull-requests.sh create mode 100644 .azuredevops/dependabot/nuget.yaml create mode 100644 .azuredevops/pipelines/example.yaml diff --git a/.azuredevops/create-pull-requests.sh b/.azuredevops/create-pull-requests.sh new file mode 100644 index 0000000..cd44753 --- /dev/null +++ b/.azuredevops/create-pull-requests.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# Adapted from https://github.com/dependabot/example-cli-usage/blob/main/create.sh + +# Expected Environment Variables: +#### AZURE_DEVOPS_EXT_PAT: The PAT token for the Azure DevOps organization. +#### PROJECT_PATH: The path to the repository, relative to Azure DevOps. + +# This script takes a jsonl file as input which is the stdout of a Dependabot CLI run. +# It takes the `type: create_pull_request` events and creates a pull request for each of them +# by using git commands. + +# Note at this time there is minimal error handling. +set -euo pipefail + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +# This script takes the .jsonl file output from the Dependabout CLI as its only param. +INPUT="$1" + +# DEBUG +echo "AZURE_DEVOPS_EXT_PAT: $AZURE_DEVOPS_EXT_PAT" +echo "PROJECT_PATH: $PROJECT_PATH" + +# Function to check if a string is valid Base64 +is_base64() { + local input="$1" + # Remove any whitespace and newlines + input=$(echo "$input" | tr -d ' \t\n\r') + # Check if the string contains only Base64 characters and has proper length + if [[ "$input" =~ ^[A-Za-z0-9+/]*={0,2}$ ]] && [[ $(( ${#input} % 4 )) -eq 0 ]]; then + return 0 + else + return 1 + fi +} + +# Configure Git Credentials +git config --global user.email "azure@azuredevops.com" +git config --global user.name "Dependabot Standalone" +git config --global advice.detachedHead false + +# Configure the credential helper to store the PAT token in the git-credentials file. +git config --global credential.helper store + +# Configure the git-credentials to use the PAT token from ADO. +echo "https://azure:${AZURE_DEVOPS_EXT_PAT}@dev.azure.com" > ~/.git-credentials +git config --global url."https://azure:${AZURE_DEVOPS_EXT_PAT}@dev.azure.com/".insteadOf "https://dev.azure.com/" + +# Parse each create_pull_request event +jq -c 'select(.type == "create_pull_request")' "$INPUT" | while read -r event; do + # Extract fields + BASE_SHA=$(echo "$event" | jq -r '.data."base-commit-sha"') + PR_TITLE=$(echo "$event" | jq -r '.data."pr-title"') + PR_BODY=$(echo "$event" | jq -r '.data."pr-body"') + COMMIT_MSG=$(echo "$event" | jq -r '.data."commit-message"') + BRANCH_NAME="dependabot/$(echo -n "$COMMIT_MSG" | sha1sum | awk '{print $1}')" + + echo "Processing PR: $PR_TITLE" + echo " Base SHA: $BASE_SHA" + echo " Branch: $BRANCH_NAME" + + # Set the remote URL to the repository using the PAT. + git remote set-url origin https://${AZURE_DEVOPS_EXT_PAT}@dev.azure.com/${PROJECT_PATH} + + # Create and checkout new branch from base commit + git fetch origin + git checkout "$BASE_SHA" + git switch -c "$BRANCH_NAME" + + # Apply file changes + echo "$event" | jq -c '.data."updated-dependency-files"[]' | while read -r file; do + # Construct file path more safely to ensure it's relative + DIRECTORY=$(echo "$file" | jq -r '.directory // ""') + FILENAME=$(echo "$file" | jq -r '.name') + + # Build relative path, handling empty directory case + if [ -z "$DIRECTORY" ] || [ "$DIRECTORY" = "." ] || [ "$DIRECTORY" = "/" ]; then + FILE_PATH="$FILENAME" + else + # Remove leading slash if present and ensure relative path + DIRECTORY=$(echo "$DIRECTORY" | sed 's#^/##') + FILE_PATH="$DIRECTORY/$FILENAME" + fi + + DELETED=$(echo "$file" | jq -r '.deleted') + if [ "$DELETED" = "true" ]; then + git rm -f "$FILE_PATH" || true + else + mkdir -p "$(dirname "$FILE_PATH")" + + # Get the content + CONTENT=$(echo "$file" | jq -r '.content') + + # Check if content is Base64 encoded + # Note - this appears to be a necessary check - `Directory.Packages.props` are written out as a Base64 string. + # Other projects using `packages.config` are written out in their original format. + if is_base64 "$CONTENT"; then + # Decode Base64 content before writing to file + echo "$CONTENT" | base64 -d > "$FILE_PATH" + else + # Content is already in plain text, write directly + echo "$CONTENT" > "$FILE_PATH" + fi + + git add "$FILE_PATH" + fi + done + + git commit -m "$COMMIT_MSG" + git push origin "$BRANCH_NAME" + + # Create PR using Azure CLI (az) - adjust options as desired. + # https://learn.microsoft.com/en-us/cli/azure/repos/pr?view=azure-cli-latest#az-repos-pr-create + az repos pr create \ + --title "$PR_TITLE" --description "$PR_BODY" \ + --target-branch "main" --source-branch "$BRANCH_NAME" \ + --labels dependencies --auto-complete true \ + --delete-source-branch true --squash true || true + + # Return to main branch for next PR + git checkout main +done \ No newline at end of file diff --git a/.azuredevops/dependabot/nuget.yaml b/.azuredevops/dependabot/nuget.yaml new file mode 100644 index 0000000..a483059 --- /dev/null +++ b/.azuredevops/dependabot/nuget.yaml @@ -0,0 +1,37 @@ +job: + package-manager: "nuget" + allowed-updates: + - update-type: all + dependency-groups: + - name: MSNet + applies-to: all + rules: + patterns: + - "Microsoft.*" + - "System.*" + - name: Nuget + applies-to: all + rules: + patterns: + - "*" + experiments: + nuget_generate_simple_pr_body: true + nuget_native_updater: true + nuget_use_direct_discovery: true + nuget_use_new_file_updater: true + ignore-conditions: + - dependency-name: Newtonsoft.Json + commit-message-options: + prefix: "dependabot" + source: + provider: azure + repo: $PROJECT_PATH + directory: '/' +credentials: + - type: git_source + host: dev.azure.com + username: vsts + password: $LOCAL_GITHUB_ACCESS_TOKEN + - type: nuget-feed + url: https://pkgs.dev.azure.com/{MY_ORGANIZATION_NAME}/_packaging/{MY_NUGET_FEED_NAME}/nuget/v3/index.json + token: $LOCAL_AZURE_ACCESS_TOKEN \ No newline at end of file diff --git a/.azuredevops/pipelines/example.yaml b/.azuredevops/pipelines/example.yaml new file mode 100644 index 0000000..94b87c3 --- /dev/null +++ b/.azuredevops/pipelines/example.yaml @@ -0,0 +1,175 @@ +parameters: + # Note: The presence of the 3 parameters below provides a mechanism to centralize this pipeline such that it can be run for multiple repositories. + # Parallelization has not been tested using this approach - but it should be easy enough to do. + # See here for more information: https://learn.microsoft.com/en-us/azure/machine-learning/how-to-use-parallel-job-in-pipeline?view=azureml-api-2&tabs=cliv2 + + # By default, this pipeline is configured to run for a single repository. + + # OPTIONAL: Name of the repository. Automatically set to ADO repository name if not provided. + - name: repositoryName + type: string + default: $(Build.Repository.Name) + + # OPTIONAL: Name of the Azure DevOps project. Automatically set to ADO project name if not provided. + - name: azdoProjectName + type: string + default: $(System.TeamProject) + + # OPTIONAL: Path to the repository, relative to Azure DevOps. + # e.g. invoicecloud/Src/_git/Repository.Name + - name: projectPath + type: string + default: '' + + # OPTIONAL: Path to the Dependabot configuration file. Relative to the repository root. + - name: dependabotConfigFile + type: string + default: "$(Build.SourcesDirectory)/.azuredevops/dependabot-config.yaml" + + # OPTIONAL: Version of GoLang to install. + # See here for other versions: https://go.dev/dl/ + - name: goVersion + type: string + default: '1.24.5' + values: + - '1.24.5' + - '1.23.11' + - '1.25rc2' + + # OPTIONAL: Version of Dependabot CLI to install - defaults to latest. + # See here for other versions: https://github.com/dependabot/cli/releases + - name: dependabotCliVersion + type: string + default: 'latest' + + +trigger: none + +schedules: + - cron: "0 0 * * 0" # Weekly, Sunday Night, Midnight UTC + always: true # Run even if there have been no code changes. + branches: + include: + - main # The branch to run the schedule on. + batch: true + displayName: "Weekly Dependency Update" + +variables: + - name: System.Secrets + value: true + + # Azure DevOps Repository Path + - name: PROJECT_PATH + ${{ if eq(parameters.projectPath, '') }}: + value: 'MY_AZDO_ORGANIZATION_NAME/${{ parameters.azdoProjectName }}/_git/${{ parameters.repositoryName }}' + ${{ else }}: + value: ${{ parameters.projectPath }} + + + +stages: + - stage: BuildDependabot + jobs: + - job: RunDependabot + pool: + vmImage: 'ubuntu-latest' + steps: + - checkout: self + persistCredentials: true + + # Add .NET + # Parameterize version if desired. + - task: UseDotNet@2 + inputs: + version: '8.0.x' + + # Install GoLang + - script: | + # Install GoLang + wget https://go.dev/dl/go${{ parameters.goVersion }}.src.tar.gz + sudo tar -C /usr/local -xzf ${{ parameters.goVersion }}.src.tar.gz + + # Add GoLang to PATH + echo "export PATH=/usr/local/go/bin:${PATH}" | sudo tee -a $HOME/.profile + source $HOME/.profile + + go version + displayName: Install GoLang + + # Install Dependabot CLI + - script: | + # Install Dependabot CLI + go install github.com/dependabot/cli/cmd/dependabot@${{ parameters.dependabotCliVersion }} + displayName: Install Dependabot CLI + + # Run Dependabot + - script: | + set -euo pipefail + + # Substitute PROJECT_PATH var in the config. + # This doesn't appear to be automatically interpolated in Azure DevOps. + sed -i 's/\$PROJECT_PATH/${PROJECT_PATH}/g' ${{ parameters.dependabotConfigFile }} + + # Print the updated config file. + echo "Using Dependabot Configuration File:" + cat ${{ parameters.dependabotConfigFile }} + + # Set the GO /bin path & cd into it. + GO_PATH=$(go env | grep GOPATH | awk -F'=' '{print $2}' | tr -d "'") + cd $GO_PATH/bin + + echo "\n dependabot update \ + -f ${{ parameters.dependabotConfigFile }} \ + --timeout 20m >> $(Pipeline.Workspace)/dependabot_result.jsonl || true" + + ./dependabot update \ + -f ${{ parameters.dependabotConfigFile }} \ + --timeout 20m >> $(Pipeline.Workspace)/dependabot_result.jsonl || true + + echo "Result:" + cat $(Pipeline.Workspace)/dependabot_result.jsonl + displayName: Run Dependabot + env: + LOCAL_AZURE_ACCESS_TOKEN: $(System.AccessToken) + LOCAL_GITHUB_ACCESS_TOKEN: $(System.AccessToken) + + # Publish Dependabot Results + - task: PublishPipelineArtifact@1 + displayName: Publish Dependabot Results + inputs: + targetPath: '$(Pipeline.Workspace)/dependabot_result.jsonl' + publishLocation: 'pipeline' + artifactName: 'dependabot_result' + + - stage: CreatePullRequests + jobs: + - job: CreatePullRequests + pool: + vmImage: 'ubuntu-latest' + steps: + # Download Dependabot Results + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifactName: 'dependabot_result' + targetPath: $(Build.ArtifactStagingDirectory) + + # Install jq - for parsing JSON. + - script: | + # Install jq + sudo apt-get update + sudo apt-get install -y jq + displayName: Install 'jq' + + # Create Pull Requests + - task: Bash@3 + displayName: Create Pull Requests + inputs: + targetType: 'filePath' + filePath: "./create-pull-requests.sh" + arguments: > + $(Build.ArtifactStagingDirectory)/dependabot_result.jsonl + workingDirectory: $(Build.SourcesDirectory)/$(Build.Repository.Name) + env: + AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) + PROJECT_PATH: $(PROJECT_PATH) \ No newline at end of file From 2625b58207066196b84244d5aa5943f697d5d656 Mon Sep 17 00:00:00 2001 From: Matthew Alltop Date: Mon, 31 Aug 2026 16:14:30 -0400 Subject: [PATCH 2/5] Address content-encoding feedback and trim branch names Reads the CLI's content-encoding field instead of heuristically sniffing for base64, and drops the PAT debug echo. Also truncates the branch-name hash to keep generated branch names reasonably short. --- .azuredevops/create-pull-requests.sh | 33 ++++++++-------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/.azuredevops/create-pull-requests.sh b/.azuredevops/create-pull-requests.sh index cd44753..5882eab 100644 --- a/.azuredevops/create-pull-requests.sh +++ b/.azuredevops/create-pull-requests.sh @@ -21,23 +21,8 @@ fi # This script takes the .jsonl file output from the Dependabout CLI as its only param. INPUT="$1" -# DEBUG -echo "AZURE_DEVOPS_EXT_PAT: $AZURE_DEVOPS_EXT_PAT" echo "PROJECT_PATH: $PROJECT_PATH" -# Function to check if a string is valid Base64 -is_base64() { - local input="$1" - # Remove any whitespace and newlines - input=$(echo "$input" | tr -d ' \t\n\r') - # Check if the string contains only Base64 characters and has proper length - if [[ "$input" =~ ^[A-Za-z0-9+/]*={0,2}$ ]] && [[ $(( ${#input} % 4 )) -eq 0 ]]; then - return 0 - else - return 1 - fi -} - # Configure Git Credentials git config --global user.email "azure@azuredevops.com" git config --global user.name "Dependabot Standalone" @@ -57,7 +42,10 @@ jq -c 'select(.type == "create_pull_request")' "$INPUT" | while read -r event; d PR_TITLE=$(echo "$event" | jq -r '.data."pr-title"') PR_BODY=$(echo "$event" | jq -r '.data."pr-body"') COMMIT_MSG=$(echo "$event" | jq -r '.data."commit-message"') - BRANCH_NAME="dependabot/$(echo -n "$COMMIT_MSG" | sha1sum | awk '{print $1}')" + HASH=$(echo -n "$COMMIT_MSG" | sha1sum | awk '{print $1}') + + # Truncate the hash to keep branch names reasonably short. + BRANCH_NAME="dependabot/${HASH:0:12}" echo "Processing PR: $PR_TITLE" echo " Base SHA: $BASE_SHA" @@ -92,17 +80,14 @@ jq -c 'select(.type == "create_pull_request")' "$INPUT" | while read -r event; d else mkdir -p "$(dirname "$FILE_PATH")" - # Get the content + # Get the content and its encoding. Absence of `content-encoding` means `utf-8`; + # only decode when the CLI explicitly says the content is `base64`. CONTENT=$(echo "$file" | jq -r '.content') - - # Check if content is Base64 encoded - # Note - this appears to be a necessary check - `Directory.Packages.props` are written out as a Base64 string. - # Other projects using `packages.config` are written out in their original format. - if is_base64 "$CONTENT"; then - # Decode Base64 content before writing to file + CONTENT_ENCODING=$(echo "$file" | jq -r '."content-encoding" // "utf-8"') + + if [ "$CONTENT_ENCODING" = "base64" ]; then echo "$CONTENT" | base64 -d > "$FILE_PATH" else - # Content is already in plain text, write directly echo "$CONTENT" > "$FILE_PATH" fi From 2062d1bf0853e30d527d6832a8c86241329b77e3 Mon Sep 17 00:00:00 2001 From: Matthew Alltop Date: Wed, 2 Sep 2026 13:16:16 -0400 Subject: [PATCH 3/5] Updated example files & script. --- .azuredevops/create-pull-requests.sh | 43 ++++++++++++----- .azuredevops/dependabot/nuget.yaml | 19 +++++++- .azuredevops/pipelines/example.yaml | 69 +++++++++++++++------------- 3 files changed, 84 insertions(+), 47 deletions(-) diff --git a/.azuredevops/create-pull-requests.sh b/.azuredevops/create-pull-requests.sh index 5882eab..45b2237 100644 --- a/.azuredevops/create-pull-requests.sh +++ b/.azuredevops/create-pull-requests.sh @@ -21,17 +21,33 @@ fi # This script takes the .jsonl file output from the Dependabout CLI as its only param. INPUT="$1" +# DEBUG OUTPUT +echo "AZURE_DEVOPS_EXT_PAT: $AZURE_DEVOPS_EXT_PAT" echo "PROJECT_PATH: $PROJECT_PATH" +# Function to check if a string is valid Base64 +is_base64() { + local input="$1" + # Remove any whitespace and newlines + input=$(echo "$input" | tr -d ' \t\n\r') + # Check if the string contains only Base64 characters and has proper length + if [[ "$input" =~ ^[A-Za-z0-9+/]*={0,2}$ ]] && [[ $(( ${#input} % 4 )) -eq 0 ]]; then + return 0 + else + return 1 + fi +} + +echo "INPUT: $INPUT" + # Configure Git Credentials git config --global user.email "azure@azuredevops.com" -git config --global user.name "Dependabot Standalone" +git config --global user.name "Dependabot" git config --global advice.detachedHead false -# Configure the credential helper to store the PAT token in the git-credentials file. +# Set the credential helper to store the PAT token in the git-credentials file. git config --global credential.helper store -# Configure the git-credentials to use the PAT token from ADO. echo "https://azure:${AZURE_DEVOPS_EXT_PAT}@dev.azure.com" > ~/.git-credentials git config --global url."https://azure:${AZURE_DEVOPS_EXT_PAT}@dev.azure.com/".insteadOf "https://dev.azure.com/" @@ -44,14 +60,15 @@ jq -c 'select(.type == "create_pull_request")' "$INPUT" | while read -r event; d COMMIT_MSG=$(echo "$event" | jq -r '.data."commit-message"') HASH=$(echo -n "$COMMIT_MSG" | sha1sum | awk '{print $1}') - # Truncate the hash to keep branch names reasonably short. + # OPTIONAL: Truncate the SHA to the short-form to avoid long branch names. + # This ensures that branches are deployable without exceeding the 63 char limit in k8s. + # e.g. `dependabot/123456789012` vs `dependabot/12345678901234567890123456789012` BRANCH_NAME="dependabot/${HASH:0:12}" echo "Processing PR: $PR_TITLE" echo " Base SHA: $BASE_SHA" echo " Branch: $BRANCH_NAME" - # Set the remote URL to the repository using the PAT. git remote set-url origin https://${AZURE_DEVOPS_EXT_PAT}@dev.azure.com/${PROJECT_PATH} # Create and checkout new branch from base commit @@ -80,14 +97,17 @@ jq -c 'select(.type == "create_pull_request")' "$INPUT" | while read -r event; d else mkdir -p "$(dirname "$FILE_PATH")" - # Get the content and its encoding. Absence of `content-encoding` means `utf-8`; - # only decode when the CLI explicitly says the content is `base64`. + # Get the content CONTENT=$(echo "$file" | jq -r '.content') - CONTENT_ENCODING=$(echo "$file" | jq -r '."content-encoding" // "utf-8"') - - if [ "$CONTENT_ENCODING" = "base64" ]; then + + # Check if content is Base64 encoded + # Note - this is a necessary check - Directory.Packages.props are written out as a Base64 string. + # Other projects using `packages.config` are written out in their original format. + if is_base64 "$CONTENT"; then + # Decode Base64 content before writing to file echo "$CONTENT" | base64 -d > "$FILE_PATH" else + # Content is already in plain text, write directly echo "$CONTENT" > "$FILE_PATH" fi @@ -98,8 +118,7 @@ jq -c 'select(.type == "create_pull_request")' "$INPUT" | while read -r event; d git commit -m "$COMMIT_MSG" git push origin "$BRANCH_NAME" - # Create PR using Azure CLI (az) - adjust options as desired. - # https://learn.microsoft.com/en-us/cli/azure/repos/pr?view=azure-cli-latest#az-repos-pr-create + # Create PR using Azure CLI (az) az repos pr create \ --title "$PR_TITLE" --description "$PR_BODY" \ --target-branch "main" --source-branch "$BRANCH_NAME" \ diff --git a/.azuredevops/dependabot/nuget.yaml b/.azuredevops/dependabot/nuget.yaml index a483059..0b74aeb 100644 --- a/.azuredevops/dependabot/nuget.yaml +++ b/.azuredevops/dependabot/nuget.yaml @@ -1,7 +1,10 @@ job: package-manager: "nuget" allowed-updates: - - update-type: all + - dependency-type: direct + update-type: all + - dependency-type: indirect + update-type: security dependency-groups: - name: MSNet applies-to: all @@ -14,15 +17,27 @@ job: rules: patterns: - "*" + exclude-patterns: + - "Microsoft.*" + - "System.*" experiments: nuget_generate_simple_pr_body: true nuget_native_updater: true nuget_use_direct_discovery: true + nuget_install_dotnet_sdks: true nuget_use_new_file_updater: true ignore-conditions: - - dependency-name: Newtonsoft.Json + - dependency-name: "*" + update-types: + - "version-update:semver-major" commit-message-options: prefix: "dependabot" + # Provides feed authentication context to the updater, in addition to the + # `nuget-feed` entry under `credentials` below. + credentials-metadata: + - type: nuget_feed + url: https://pkgs.dev.azure.com/{MY_ORGANIZATION_NAME}/_packaging/{MY_NUGET_FEED_NAME}/nuget/v3/index.json + token: $LOCAL_AZURE_ACCESS_TOKEN source: provider: azure repo: $PROJECT_PATH diff --git a/.azuredevops/pipelines/example.yaml b/.azuredevops/pipelines/example.yaml index 94b87c3..3c75640 100644 --- a/.azuredevops/pipelines/example.yaml +++ b/.azuredevops/pipelines/example.yaml @@ -16,7 +16,7 @@ parameters: default: $(System.TeamProject) # OPTIONAL: Path to the repository, relative to Azure DevOps. - # e.g. invoicecloud/Src/_git/Repository.Name + # e.g. {AzureDevOpsOrganization}/${ parameters.azdoProjectName }/_git/{Repository.Name} - name: projectPath type: string default: '' @@ -65,10 +65,8 @@ variables: ${{ else }}: value: ${{ parameters.projectPath }} - - stages: - - stage: BuildDependabot + - stage: DependabotDependencyUpdate jobs: - job: RunDependabot pool: @@ -81,36 +79,34 @@ stages: # Parameterize version if desired. - task: UseDotNet@2 inputs: - version: '8.0.x' - - # Install GoLang - - script: | - # Install GoLang - wget https://go.dev/dl/go${{ parameters.goVersion }}.src.tar.gz - sudo tar -C /usr/local -xzf ${{ parameters.goVersion }}.src.tar.gz + version: '10.0.x' - # Add GoLang to PATH - echo "export PATH=/usr/local/go/bin:${PATH}" | sudo tee -a $HOME/.profile - source $HOME/.profile - - go version + - task: GoTool@0 displayName: Install GoLang - - # Install Dependabot CLI - - script: | - # Install Dependabot CLI - go install github.com/dependabot/cli/cmd/dependabot@${{ parameters.dependabotCliVersion }} + inputs: + version: ${{ parameters.goVersion }} + + - task: Go@0 # Install Dependabot CLI displayName: Install Dependabot CLI + inputs: + command: 'install' + arguments: 'github.com/dependabot/cli/cmd/dependabot@${{ parameters.dependabotCliVersion }}' # Run Dependabot - script: | - set -euo pipefail - - # Substitute PROJECT_PATH var in the config. - # This doesn't appear to be automatically interpolated in Azure DevOps. - sed -i 's/\$PROJECT_PATH/${PROJECT_PATH}/g' ${{ parameters.dependabotConfigFile }} - - # Print the updated config file. + # Exit if any step fails. + set -e + + # DEBUG OUTPUT: Print the values. + echo "LOCAL_AZURE_ACCESS_TOKEN: $LOCAL_AZURE_ACCESS_TOKEN" + echo "LOCAL_GITHUB_ACCESS_TOKEN: $LOCAL_GITHUB_ACCESS_TOKEN" + echo "PROJECT_PATH: $PROJECT_PATH" + + # Substitute the PROJECT_PATH value in the config file. + # This one does not appear to update automatically when running in Azure DevOps + sed -i "s|\$PROJECT_PATH|${{ parameters.projectPath }}|g" ${{ parameters.dependabotConfigFile }} + + # DEBUG OUTPUT: Print the config file. echo "Using Dependabot Configuration File:" cat ${{ parameters.dependabotConfigFile }} @@ -121,7 +117,8 @@ stages: echo "\n dependabot update \ -f ${{ parameters.dependabotConfigFile }} \ --timeout 20m >> $(Pipeline.Workspace)/dependabot_result.jsonl || true" - + + # Timeout value optional ./dependabot update \ -f ${{ parameters.dependabotConfigFile }} \ --timeout 20m >> $(Pipeline.Workspace)/dependabot_result.jsonl || true @@ -133,13 +130,12 @@ stages: LOCAL_AZURE_ACCESS_TOKEN: $(System.AccessToken) LOCAL_GITHUB_ACCESS_TOKEN: $(System.AccessToken) - # Publish Dependabot Results - task: PublishPipelineArtifact@1 displayName: Publish Dependabot Results inputs: targetPath: '$(Pipeline.Workspace)/dependabot_result.jsonl' publishLocation: 'pipeline' - artifactName: 'dependabot_result' + artifact: 'dependabot_result' - stage: CreatePullRequests jobs: @@ -147,8 +143,15 @@ stages: pool: vmImage: 'ubuntu-latest' steps: - # Download Dependabot Results + - checkout: self + persistCredentials: true + clean: true + + # You could also publish the script as an artifact - this just makes it easier to self-contain. + - checkout: templates + - task: DownloadPipelineArtifact@2 + displayName: Download Dependabot Results File inputs: buildType: 'current' artifactName: 'dependabot_result' @@ -166,7 +169,7 @@ stages: displayName: Create Pull Requests inputs: targetType: 'filePath' - filePath: "./create-pull-requests.sh" + filePath: "../create-pull-requests.sh" arguments: > $(Build.ArtifactStagingDirectory)/dependabot_result.jsonl workingDirectory: $(Build.SourcesDirectory)/$(Build.Repository.Name) From 254ae0ec5db5bb8541b2a0202f025fc19d7170b0 Mon Sep 17 00:00:00 2001 From: Matthew Alltop Date: Wed, 2 Sep 2026 13:39:44 -0400 Subject: [PATCH 4/5] Added examples for npm and yarn + pip. Marked up config files --- .azuredevops/dependabot/npm-and-yarn.yaml | 73 +++++++++++++++++++++++ .azuredevops/dependabot/nuget.yaml | 28 ++++++--- .azuredevops/dependabot/pip.yaml | 30 ++++++++++ 3 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 .azuredevops/dependabot/npm-and-yarn.yaml create mode 100644 .azuredevops/dependabot/pip.yaml diff --git a/.azuredevops/dependabot/npm-and-yarn.yaml b/.azuredevops/dependabot/npm-and-yarn.yaml new file mode 100644 index 0000000..dfb4a1f --- /dev/null +++ b/.azuredevops/dependabot/npm-and-yarn.yaml @@ -0,0 +1,73 @@ +job: + package-manager: "npm_and_yarn" + allowed-updates: + - dependency-type: direct + update-type: all + - dependency-type: indirect + update-type: security + dependency-groups: + - name: rsbuild + applies-to: all + rules: + patterns: + - "@rsbuild/*" + - name: module-federation + applies-to: all + rules: + patterns: + - "@module-federation/*" + - name: testing + applies-to: all + rules: + patterns: + - "@testing-library/*" + - "jest" + - "jest-*" + - "ts-jest" + - name: biome + applies-to: all + rules: + patterns: + - "@biomejs/biome" + - name: types + applies-to: all + rules: + patterns: + - "@types/*" + - name: npm + applies-to: all + rules: + patterns: + - "*" + exclude-patterns: + - "@rsbuild/*" + - "@module-federation/*" + - "@testing-library/*" + - "jest" + - "jest-*" + - "ts-jest" + - "@biomejs/biome" + - "@types/*" + ignore-conditions: + - dependency-name: "*" + update-types: + - "version-update:semver-major" + commit-message-options: + prefix: "dependabot" + # Provides feed authentication context to the *updater* + credentials-metadata: + - type: nuget_feed + url: https://pkgs.dev.azure.com/{AZURE_DEVOPS_ORGANIZATION}/_packaging/{AZURE_ARTIFACT_FEED_NAME}/nuget/v3/index.json + token: $LOCAL_AZURE_ACCESS_TOKEN + source: + provider: azure + repo: AZURE_DEVOPS_ORGANIZATION/{{AZURE_DEVOPS_PROJECT}}/_git/{{{GIT_REPO_NAME}}} + directory: '/' +credentials: # Provides git & artifact feed authentication context to the *proxy*. + - type: git_source + host: dev.azure.com + username: vsts + password: $LOCAL_GITHUB_ACCESS_TOKEN # Note - this has to be `LOCAL_GITHUB_ACCESS_TOKEN`. + - type: nuget-feed + url: https://pkgs.dev.azure.com/{AZURE_DEVOPS_ORGANIZATION}/_packaging/{AZURE_ARTIFACT_FEED_NAME}/nuget/v3/index.json + token: $LOCAL_AZURE_ACCESS_TOKEN \ No newline at end of file diff --git a/.azuredevops/dependabot/nuget.yaml b/.azuredevops/dependabot/nuget.yaml index 0b74aeb..4b47f55 100644 --- a/.azuredevops/dependabot/nuget.yaml +++ b/.azuredevops/dependabot/nuget.yaml @@ -1,3 +1,4 @@ +# This is an example Dependabot configuration file for a .NET project that demonstrates using a private AzDo Artifacts feed. job: package-manager: "nuget" allowed-updates: @@ -22,31 +23,42 @@ job: - "System.*" experiments: nuget_generate_simple_pr_body: true + # If running against older .NET Framework projects, you may need to set all of the below to 'false' + # When these are enabled, the updater installs a newer version of .NET SDK and runs an SDK-based MSBuild task, which crawls the XML in the .csproj/.vbproj files. + # This can cause issues with older .NET Framework projects. nuget_native_updater: true nuget_use_direct_discovery: true nuget_install_dotnet_sdks: true nuget_use_new_file_updater: true ignore-conditions: - - dependency-name: "*" + # Ignores routine version updates, but allows security updates. + - dependency-name: "System.*" update-types: - "version-update:semver-major" + - "version-update:semver-minor" + - "version-update:semver-patch" + # Ignore an entire package. + - dependency-name: "Newtonsoft.Json" + # Constrain all updates to minor or patch version increments + - dependency-name: "*" + update-types: + - "version-update:semver-major" commit-message-options: prefix: "dependabot" - # Provides feed authentication context to the updater, in addition to the - # `nuget-feed` entry under `credentials` below. + # Provides feed authentication context to the *updater* credentials-metadata: - type: nuget_feed - url: https://pkgs.dev.azure.com/{MY_ORGANIZATION_NAME}/_packaging/{MY_NUGET_FEED_NAME}/nuget/v3/index.json + url: https://pkgs.dev.azure.com/{AZURE_DEVOPS_ORGANIZATION}/_packaging/{AZURE_ARTIFACT_FEED_NAME}/nuget/v3/index.json token: $LOCAL_AZURE_ACCESS_TOKEN source: provider: azure - repo: $PROJECT_PATH + repo: AZURE_DEVOPS_ORGANIZATION/{{AZURE_DEVOPS_PROJECT}}/_git/{{{GIT_REPO_NAME}}} directory: '/' -credentials: +credentials: # Provides git & artifact feed authentication context to the *proxy*. - type: git_source host: dev.azure.com username: vsts - password: $LOCAL_GITHUB_ACCESS_TOKEN + password: $LOCAL_GITHUB_ACCESS_TOKEN # Note - this has to be `LOCAL_GITHUB_ACCESS_TOKEN`. - type: nuget-feed - url: https://pkgs.dev.azure.com/{MY_ORGANIZATION_NAME}/_packaging/{MY_NUGET_FEED_NAME}/nuget/v3/index.json + url: https://pkgs.dev.azure.com/{AZURE_DEVOPS_ORGANIZATION}/_packaging/{AZURE_ARTIFACT_FEED_NAME}/nuget/v3/index.json token: $LOCAL_AZURE_ACCESS_TOKEN \ No newline at end of file diff --git a/.azuredevops/dependabot/pip.yaml b/.azuredevops/dependabot/pip.yaml new file mode 100644 index 0000000..09c5df1 --- /dev/null +++ b/.azuredevops/dependabot/pip.yaml @@ -0,0 +1,30 @@ +job: + package-manager: "pip" + allowed-updates: + - dependency-type: direct + update-type: all + - dependency-type: indirect + update-type: security + ignore-conditions: + - dependency-name: "*" + update-types: + - "version-update:semver-major" + commit-message-options: + prefix: "dependabot" + # Provides feed authentication context to the *updater* + credentials-metadata: + - type: nuget_feed + url: https://pkgs.dev.azure.com/{AZURE_DEVOPS_ORGANIZATION}/_packaging/{AZURE_ARTIFACT_FEED_NAME}/nuget/v3/index.json + token: $LOCAL_AZURE_ACCESS_TOKEN + source: + provider: azure + repo: AZURE_DEVOPS_ORGANIZATION/{{AZURE_DEVOPS_PROJECT}}/_git/{{{GIT_REPO_NAME}}} + directory: '/' +credentials: # Provides git & artifact feed authentication context to the *proxy*. + - type: git_source + host: dev.azure.com + username: vsts + password: $LOCAL_GITHUB_ACCESS_TOKEN # Note - this has to be `LOCAL_GITHUB_ACCESS_TOKEN`. + - type: nuget-feed + url: https://pkgs.dev.azure.com/{AZURE_DEVOPS_ORGANIZATION}/_packaging/{AZURE_ARTIFACT_FEED_NAME}/nuget/v3/index.json + token: $LOCAL_AZURE_ACCESS_TOKEN \ No newline at end of file From d3f9a24e6c84c734b9cec86267d7428733f139b0 Mon Sep 17 00:00:00 2001 From: Matthew Alltop Date: Wed, 2 Sep 2026 13:43:51 -0400 Subject: [PATCH 5/5] Updated example pipeline with other installer task examples. --- .azuredevops/pipelines/example.yaml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.azuredevops/pipelines/example.yaml b/.azuredevops/pipelines/example.yaml index 3c75640..cf23515 100644 --- a/.azuredevops/pipelines/example.yaml +++ b/.azuredevops/pipelines/example.yaml @@ -81,6 +81,34 @@ stages: inputs: version: '10.0.x' + # For Legacy .NET Framework Projects - use these steps instead. + + # - task: NuGetToolInstaller@1 + # inputs: + # versionSpec: + # checkLatest: true + + # - task: NuGetAuthenticate@1 + # displayName: "NuGet Authenticate" + + # - task: DotNetCoreCLI@2 + # inputs: + # command: 'restore' + # feedsToUse: config + # nugetConfigPath: ${{ parameters.nugetConfigPath }} + # projects: '**/*.sln' + + # For NPM and Yarn + # - task: UseNode@1 + # inputs: + # version: ${{ parameters.nodeVersion }} + + # For Python + # - task: UsePythonVersion@0 + # inputs: + # versionSpec: ${{ parameters.pythonVersion }} + # architecture: 'x64' + - task: GoTool@0 displayName: Install GoLang inputs: