Skip to content
Open
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
130 changes: 130 additions & 0 deletions .azuredevops/create-pull-requests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/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 <result.jsonl>"
exit 1
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"
git config --global advice.detachedHead false

# Set the credential helper to store the PAT token in the git-credentials file.
git config --global credential.helper store

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"')
HASH=$(echo -n "$COMMIT_MSG" | sha1sum | awk '{print $1}')

# 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"

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 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

git add "$FILE_PATH"
fi
done

git commit -m "$COMMIT_MSG"
git push origin "$BRANCH_NAME"

# Create PR using Azure CLI (az)
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
73 changes: 73 additions & 0 deletions .azuredevops/dependabot/npm-and-yarn.yaml
Original file line number Diff line number Diff line change
@@ -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
64 changes: 64 additions & 0 deletions .azuredevops/dependabot/nuget.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 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:
- dependency-type: direct
update-type: all
- dependency-type: indirect
update-type: security
dependency-groups:
- name: MSNet
applies-to: all
rules:
patterns:
- "Microsoft.*"
- "System.*"
- name: Nuget
applies-to: all
rules:
patterns:
- "*"
exclude-patterns:
- "Microsoft.*"
- "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:
# 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*
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
30 changes: 30 additions & 0 deletions .azuredevops/dependabot/pip.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading