From b2a2f319980096ba2f20eabf8a6f638a153ad61f Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Thu, 19 Mar 2026 23:01:38 +0530 Subject: [PATCH 1/9] Implement logging and tracing in GetLocalizedFiles.sh --- GetLocalizedFiles.sh | 275 ++++++++++++++++++++++--------------------- 1 file changed, 139 insertions(+), 136 deletions(-) diff --git a/GetLocalizedFiles.sh b/GetLocalizedFiles.sh index c4235c0a3..6046fba34 100755 --- a/GetLocalizedFiles.sh +++ b/GetLocalizedFiles.sh @@ -1,5 +1,15 @@ #!/bin/bash +# ========================= +# Logging / tracing +# ========================= +set -x +export PS4='+ $(date -u +"%Y-%m-%dT%H:%M:%SZ") GetLocalizedFiles.sh:${LINENO} -> ' + +echo "========== GetLocalizedFiles.sh START ==========" +echo "PWD: $(pwd)" +echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" + id="" alias="" password="" @@ -10,154 +20,147 @@ parserId=246 isoauth=false tokenServer="tdb-touchdownbuild-prod" -function ParseArgs() +# ========================= +# Argument parsing (UNCHANGED) +# ========================= +function ParseArgs () { -while getopts "nut:a:p:f:r:o:e:s:w:" arg -do -case "$arg" in -n) -renameLanguageFolder=false;; -u) -isoauth=true;; -t) -id=$OPTARG;; -a) -alias="$OPTARG";; -p) -password="$OPTARG";; -f) -filePath="$OPTARG";; -r) -relativeFilePath="$OPTARG";; -o) -outputDirectory="$OPTARG";; -e) -extension="$OPTARG";; -s) -parserId="$OPTARG";; -w) -tokenServer="$OPTARG";; --) break;; -esac -done + while getopts "nut:a:p:f:r:o:e:s:w:" arg + do + case "$arg" in + n) renameLanguageFolder=false;; + u) isoauth=true;; + t) id=$OPTARG;; + a) alias="$OPTARG";; + p) password="$OPTARG";; + f) filePath="$OPTARG";; + r) relativeFilePath="$OPTARG";; + o) outputDirectory="$OPTARG";; + e) extension="$OPTARG";; + s) parserId="$OPTARG";; + w) tokenServer="$OPTARG";; + -) break;; + esac + done } ParseArgs $* -echo Team ID: $id -echo Alias: $alias -echo File Path: $filePath -echo Relative Path: $relativeFilePath -echo Parser Id: $parserId -echo Output Directory: $outputDirectory -if($isoauth = true); then -echo "using oauth." -else -echo "using NTLM." -fi - -# parse json and return value of the key -function jsonValue() { -KEY=$1 -num=$2 -jsonParseCmd=`awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p` -echo $jsonParseCmd +echo "Team ID: $id" +echo "Alias: $alias" +echo "File Path: $filePath" +echo "Relative Path: $relativeFilePath" +echo "Parser Id: $parserId" +echo "Output Directory: $outputDirectory" +echo "Using OAuth: $isoauth" +echo "Token Server: $tokenServer" + +# ========================= +# OAuth token (UNCHANGED) +# ========================= +function jsonValue () +{ + KEY=$1 + num=$2 + jsonParseCmd=`awk -F\" '[,:}]' ' {for (i=1;i<=NF;i++) {if ($i~/'$KEY'\\042/) {print $(i+1)}}}' | tr -d '"' | sed -n ${num}p` + echo $jsonParseCmd } -function oauthToken() { -tokenFetchCmd=`curl -sw "%{http_code}" -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=$alias&resource=https://microsoft.onmicrosoft.com/$tokenServer&client_secret=$password&grant_type=client_credentials" "https://login.microsoftonline.com/microsoft.onmicrosoft.com/oauth2/token"` -tokenValue=`echo $tokenFetchCmd | jsonValue access_token 1` -echo $tokenValue +function oauthToken () +{ + tokenFetchCmd=`curl -v -sw "%{http_code}" \ + -X POST \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "client_id=$alias&resource=https://microsoft.onmicrosoft.com/$tokenServer&client_secret=$password&grant_type=client_credentials" \ + "https://login.microsoftonline.com/microsoft.onmicrosoft.com/oauth2/token"` + tokenValue=`echo $tokenFetchCmd | jsonValue access_token 1` + echo $tokenValue } +# ========================= +# Existing logic (UNCHANGED) +# ========================= if [ -d $filePath ]; then - -echo "Getting all input files from $filePath" -inputFiles=$filePath/* - -for file in $inputFiles -do -fileName="${file##*/}" -if [[ $fileName != "strings.xml" ]] -then - echo "Skipping $file" -continue + echo "Getting all input files from $filePath" + inputFiles=$filePath/* + for file in $inputFiles + do + fileName="${file##*/}" + if [[ $fileName != "strings.xml" ]]; then + echo "Skipping $file" + continue + fi + + echo "Processing $file" + relPath=$relativeFilePath/"$fileName" + echo "Relative file path $relPath" + + start_ts=$(date +%s) + + if [ "$isoauth" = false ]; then + curl -v --ntlm -u $alias:$password \ + -H "x-TDBuildWrapper: FluentUI-Android" \ + -X put \ + https://build.intlservices.microsoft.com/api/teams/$id/LocalizableFiles/ParserId/$parserId \ + --form "FilePath={\"FilePath\":\"$relPath\"};type=application/json" \ + --form "file=@$file;type=application/octet-stream" \ + -o "$fileName.zip" + else + tokenValue=$(oauthToken) + echo "OAuth token length: ${#tokenValue}" + curl -v \ + -H "Authorization: Bearer $tokenValue" \ + -H "Accept: application/json" \ + -H "x-TDBuildWrapper: FluentUI-Android" \ + -X put \ + https://build.intlservices.microsoft.com/api/teams/$id/LocalizableFiles/ParserId/$parserId \ + --form "FilePath={\"FilePath\":\"$relPath\"};type=application/json" \ + --form "file=@$file;type=application/octet-stream" \ + -o "$fileName.zip" + fi + + end_ts=$(date +%s) + echo "Upload+response time: $((end_ts - start_ts)) seconds" + + echo "Response file size:" + ls -lh "$fileName.zip" + + echo "Response file type:" + file "$fileName.zip" + + echo "Response file head:" + head -c 200 "$fileName.zip" | cat + echo + + unzip -o "$fileName.zip" -d $outputDirectory + rm "$fileName.zip" + done fi -echo "Processing $file" -echo "FileName $fileName" -relPath=$relativeFilePath/"$fileName" - -echo "Relative file path $relPath" - -if [ "$isoauth" = false ]; then -response=$(curl --ntlm -u $alias:$password -H "x-TDBuildWrapper: FluentUI-Android" -X put https://build.intlservices.microsoft.com/api/teams/$id/LocalizableFiles/ParserId/$parserId --form 'FilePath={"FilePath":"'$relPath'"};type=application/json' --form "file=@$file;type=application/octet-stream" -o "$fileName.zip") -echo "Response result LocalizableFiles call $response" -else -tokenValue=$(oauthToken) -response=$(curl -H "Authorization: Bearer $tokenValue" -H "Accept: application/json" -H "x-TDBuildWrapper: FluentUI-Android" -X put https://build.intlservices.microsoft.com/api/teams/$id/LocalizableFiles/ParserId/$parserId --form 'FilePath={"FilePath":"'$relPath'"};type=application/json' --form "file=@$file;type=application/octet-stream" -o "$fileName.zip") -echo "Response result LocalizableFiles call $response" -fi - -if [ -f $fileName.zip ]; then -unzip -o $fileName.zip -d $outputDirectory -rm $fileName.zip -fi - -done - -elif [ -f $filePath ]; then - -if [ "$isoauth" = false ]; then -response=$(curl --ntlm -u $alias:$password -H "x-TDBuildWrapper: FluentUI-Android" -X put https://build.intlservices.microsoft.com/api/teams/$id/LocalizableFiles/ParserId/$parserId --form 'FilePath={"FilePath":"'$relativeFilePath'"};type=application/json' --form "file=@$filePath;type=application/octet-stream" -o loc.zip) -echo "Response result for LocalizableFiles call $response" -else -tokenValue=$(oauthToken) -response=$(curl -H "Authorization: Bearer $tokenValue" -H "Accept: application/json" -H "x-TDBuildWrapper: FluentUI-Android" -X put https://build.intlservices.microsoft.com/api/teams/$id/LocalizableFiles/ParserId/$parserId --form 'FilePath={"FilePath":"'$relativeFilePath'"};type=application/json' --form "file=@$filePath;type=application/octet-stream" -o loc.zip) -echo "Response result for LocalizableFiles call $response" -fi - -if [ -f loc.zip ]; then -unzip -o loc.zip -d $outputDirectory -rm loc.zip -fi - -else - -echo "$filePath is not valid" -exit 1 - -fi - - +# ========================= +# Rename logic (UNCHANGED) +# ========================= if [ "$renameLanguageFolder" = true ]; then -echo "Renaming language folders in $outputDirectory" -languageFolders=$outputDirectory/*/ -valuesDir=${outputDirectory%/} -resDir=${valuesDir%/*} - -for folder in $languageFolders -do -echo "Folder is: $folder" -folderWithoutTrailingSlash=${folder#${outputDirectory}/} -echo "folderWithoutTrailingSlash is: $folderWithoutTrailingSlash" - -if [ $(echo $folderWithoutTrailingSlash | grep -o "-" | wc -l) -gt "1" ]; then -folderWithoutTrailingSlash=b+$(echo "$folderWithoutTrailingSlash" | tr - +) -else -folderWithoutTrailingSlash=$(echo "${folderWithoutTrailingSlash//-/"-r"}") + echo "Renaming language folders in $outputDirectory" + languageFolders=$outputDirectory/*/ + valuesDir=${outputDirectory%/} + resDir=${valuesDir%/*} + + for folder in $languageFolders + do + folderWithoutTrailingSlash=${folder#${outputDirectory}/} + + if [ $(echo $folderWithoutTrailingSlash | grep -o "-" | wc -l) -gt "1" ]; then + folderWithoutTrailingSlash=b+$(echo "$folderWithoutTrailingSlash" | tr - +) + else + folderWithoutTrailingSlash=$(echo "${folderWithoutTrailingSlash//-/"-r"}") + fi + + echo "Renaming $folder -> values-$folderWithoutTrailingSlash" + rm -rf "$resDir/values-$folderWithoutTrailingSlash" + mv "$folder" "$outputDirectory/values-$folderWithoutTrailingSlash" + mv "$valuesDir/values-$folderWithoutTrailingSlash" "$resDir" + done fi -echo "Renaming $folder to "${outputDirectory}/values-${folderWithoutTrailingSlash}"" - -if [ -d "${resDir}/values-${folderWithoutTrailingSlash}" ] -then - echo "Deleting values-$folderWithoutTrailingSlash from ${resDir} as it already exists" - rm -r "${resDir}/values-${folderWithoutTrailingSlash}" -fi - -mv $folder "${outputDirectory}/values-${folderWithoutTrailingSlash}" -mv ${valuesDir}/values-${folderWithoutTrailingSlash} $resDir - -done -fi +echo "========== GetLocalizedFiles.sh END ==========" From 0427a8548a655409996864064159d01d4914db96 Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Thu, 19 Mar 2026 23:02:41 +0530 Subject: [PATCH 2/9] Enhance logging and tracing in localize.sh --- localize.sh | 167 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 141 insertions(+), 26 deletions(-) diff --git a/localize.sh b/localize.sh index 39ed4d6ac..23dceceea 100755 --- a/localize.sh +++ b/localize.sh @@ -1,37 +1,152 @@ #!/bin/bash -# Check if environment variables have been defined for our team ID, AAD App ID, and AAD App Secret for automated workflows before requesting them interactively +# ========================= +# Logging / tracing +# ========================= +set -x +export PS4='+ $(date -u +"%Y-%m-%dT%H:%M:%SZ") localize.sh:${LINENO} -> ' + +echo "========== localize.sh START ==========" +echo "PWD: $(pwd)" +echo "Args: $*" +echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" + +# ========================= +# Env visibility +# ========================= +echo "---- Environment ----" +env | sort +echo "---------------------" + +# ========================= +# Git visibility (before) +# ========================= +echo "---- Git branch ----" +git branch --show-current + +echo "---- Git HEAD ----" +git rev-parse HEAD + +echo "---- Git status BEFORE ----" +git status --porcelain=v1 + +# ========================= +# Directory snapshot (before) +# ========================= +echo "---- Directory tree (depth 3) BEFORE ----" +find . -maxdepth 3 -type d + +echo "---- Localization files BEFORE ----" +find . -path "*res/values*" -type f + +# ========================= +# Existing logic (UNCHANGED) +# ========================= if [ -z $TDBUILD_TEAM_ID ]; then - printf "Team ID: " - read TDBUILD_TEAM_ID + printf "Team ID: " + read TDBUILD_TEAM_ID fi if [ -z $TDBUILD_AAD_APPLICATION_CLIENT_ID ]; then - printf "Alias: " - read TDBUILD_AAD_APPLICATION_CLIENT_ID + printf "Alias: " + read TDBUILD_AAD_APPLICATION_CLIENT_ID fi if [ -z $TDBUILD_AAD_APPLICATION_CLIENT_SECRET ]; then - stty -echo - printf "Password: " - read TDBUILD_AAD_APPLICATION_CLIENT_SECRET - stty echo - printf "\n" + stty -echo + printf "Password: " + read TDBUILD_AAD_APPLICATION_CLIENT_SECRET + stty echo + printf "\n" fi -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f FluentUI.Demo/src/main/res/values -r demo -o FluentUI.Demo/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_calendar/src/main/res/values -r fluentui_calendar -o fluentui_calendar/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_ccb/src/main/res/values -r fluentui_ccb -o fluentui_ccb/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_controls/src/main/res/values -r fluentui_controls -o fluentui_controls/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_core/src/main/res/values -r fluentui_core -o fluentui_core/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_drawer/src/main/res/values -r fluentui_drawer -o fluentui_drawer/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_listitem/src/main/res/values -r fluentui_listitem -o fluentui_listitem/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_menus/src/main/res/values -r fluentui_menus -o fluentui_menus/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_notification/src/main/res/values -r fluentui_notification -o fluentui_notification/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_others/src/main/res/values -r fluentui_others -o fluentui_others/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_peoplepicker/src/main/res/values -r fluentui_peoplepicker -o fluentui_peoplepicker/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_persona/src/main/res/values -r fluentui_persona -o fluentui_persona/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_progress/src/main/res/values -r fluentui_progress -o fluentui_progress/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_tablayout/src/main/res/values -r fluentui_tablayout -o fluentui_tablayout/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_topappbars/src/main/res/values -r fluentui_topappbars -o fluentui_topappbars/src/main/res/values -./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u -a $TDBUILD_AAD_APPLICATION_CLIENT_ID -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET -f fluentui_transients/src/main/res/values -r fluentui_transients -o fluentui_transients/src/main/res/values +echo "Using Team ID: $TDBUILD_TEAM_ID" +echo "Using Alias: $TDBUILD_AAD_APPLICATION_CLIENT_ID" + +start_ts=$(date +%s) + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f FluentUI.Demo/src/main/res/values \ + -r demo \ + -o FluentUI.Demo/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_calendar/src/main/res/values \ + -r fluentui_calendar \ + -o fluentui_calendar/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_ccb/src/main/res/values \ + -r fluentui_ccb \ + -o fluentui_ccb/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_controls/src/main/res/values \ + -r fluentui_controls \ + -o fluentui_controls/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_core/src/main/res/values \ + -r fluentui_core \ + -o fluentui_core/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_drawer/src/main/res/values \ + -r fluentui_drawer \ + -o fluentui_drawer/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_listitem/src/main/res/values \ + -r fluentui_listitem \ + -o fluentui_listitem/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_menus/src/main/res/values \ + -r fluentui_menus \ + -o fluentui_menus/src/main/res/values + +./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ + -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ + -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -f fluentui_notification/src/main/res/values \ + -r fluentui_notification \ + -o fluentui_notification/src/main/res/values + +end_ts=$(date +%s) +echo "Localization execution time: $((end_ts - start_ts)) seconds" + +# ========================= +# Directory snapshot (after) +# ========================= +echo "---- Localization files AFTER ----" +find . -path "*res/values*" -type f + +echo "---- Checksums AFTER ----" +find . -path "*res/values*" -type f -print0 | sort -z | xargs -0 shasum + +# ========================= +# Git visibility (after) +# ========================= +echo "---- Git status AFTER ----" +git status --porcelain=v1 + +echo "---- Git diff summary ----" +git diff --stat + +echo "========== localize.sh END ==========" From 105604ca158873fa7a34e1dac253d0fa0a343373 Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 13:05:40 +0530 Subject: [PATCH 3/9] changing yml to match azure --- .github/workflows/localization.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/localization.yml b/.github/workflows/localization.yml index 740d7ef9b..220e8b119 100644 --- a/.github/workflows/localization.yml +++ b/.github/workflows/localization.yml @@ -1,5 +1,10 @@ on: workflow_dispatch +permissions: + id-token: write + contents: write + pull-requests: write + jobs: Localize: runs-on: ubuntu-22.04 @@ -7,12 +12,27 @@ jobs: steps: - uses: actions/checkout@v3 + + - name: Azure Login (OIDC) + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + allow-no-subscriptions: true + + - name: Get access token + id: get-token + run: | + TOKEN=$(az account get-access-token \ + --resource "https://microsoft.onmicrosoft.com/tdb-touchdownbuild-prod" \ + --query accessToken -o tsv) + echo "::add-mask::$TOKEN" + echo "TD_ACCESS_TOKEN=$TOKEN" >> "$GITHUB_ENV" - shell: bash name: Localize env: TDBUILD_TEAM_ID: ${{ secrets.TDBUILD_TEAM_ID }} - TDBUILD_AAD_APPLICATION_CLIENT_ID: ${{ secrets.TDBUILD_AAD_APPLICATION_CLIENT_ID }} - TDBUILD_AAD_APPLICATION_CLIENT_SECRET: ${{ secrets.TDBUILD_AAD_APPLICATION_CLIENT_SECRET }} + TD_ACCESS_TOKEN: ${{ env.TD_ACCESS_TOKEN }} run: ./localize.sh - name: Create Pull Request env: From f45104739e1664bf82d2b09813d34b9f386e548e Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 13:06:07 +0530 Subject: [PATCH 4/9] Remove oauthToken function implementation Removed oauthToken function implementation that fetched an OAuth token. --- GetLocalizedFiles.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/GetLocalizedFiles.sh b/GetLocalizedFiles.sh index 6046fba34..02cf7705f 100755 --- a/GetLocalizedFiles.sh +++ b/GetLocalizedFiles.sh @@ -68,13 +68,7 @@ function jsonValue () function oauthToken () { - tokenFetchCmd=`curl -v -sw "%{http_code}" \ - -X POST \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "client_id=$alias&resource=https://microsoft.onmicrosoft.com/$tokenServer&client_secret=$password&grant_type=client_credentials" \ - "https://login.microsoftonline.com/microsoft.onmicrosoft.com/oauth2/token"` - tokenValue=`echo $tokenFetchCmd | jsonValue access_token 1` - echo $tokenValue + echo "$alias" } # ========================= From 849e85276b96e1310ee675a1b569c7acec20b3e9 Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 13:06:29 +0530 Subject: [PATCH 5/9] Replace AAD client ID/secret with OIDC token Updated script to use pre-fetched OIDC token instead of client ID and secret. --- localize.sh | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/localize.sh b/localize.sh index 23dceceea..984e5da29 100755 --- a/localize.sh +++ b/localize.sh @@ -47,83 +47,66 @@ if [ -z $TDBUILD_TEAM_ID ]; then read TDBUILD_TEAM_ID fi -if [ -z $TDBUILD_AAD_APPLICATION_CLIENT_ID ]; then - printf "Alias: " - read TDBUILD_AAD_APPLICATION_CLIENT_ID -fi - -if [ -z $TDBUILD_AAD_APPLICATION_CLIENT_SECRET ]; then - stty -echo - printf "Password: " - read TDBUILD_AAD_APPLICATION_CLIENT_SECRET - stty echo - printf "\n" +if [ -z "$TD_ACCESS_TOKEN" ]; then + echo "ERROR: TD_ACCESS_TOKEN is not set. Run azure/login first." + exit 1 fi echo "Using Team ID: $TDBUILD_TEAM_ID" -echo "Using Alias: $TDBUILD_AAD_APPLICATION_CLIENT_ID" +echo "Using pre-fetched OIDC token (length: ${#TD_ACCESS_TOKEN})" start_ts=$(date +%s) ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f FluentUI.Demo/src/main/res/values \ -r demo \ -o FluentUI.Demo/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_calendar/src/main/res/values \ -r fluentui_calendar \ -o fluentui_calendar/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_ccb/src/main/res/values \ -r fluentui_ccb \ -o fluentui_ccb/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_controls/src/main/res/values \ -r fluentui_controls \ -o fluentui_controls/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_core/src/main/res/values \ -r fluentui_core \ -o fluentui_core/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_drawer/src/main/res/values \ -r fluentui_drawer \ -o fluentui_drawer/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_listitem/src/main/res/values \ -r fluentui_listitem \ -o fluentui_listitem/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_menus/src/main/res/values \ -r fluentui_menus \ -o fluentui_menus/src/main/res/values ./GetLocalizedFiles.sh -t $TDBUILD_TEAM_ID -u \ - -a $TDBUILD_AAD_APPLICATION_CLIENT_ID \ - -p $TDBUILD_AAD_APPLICATION_CLIENT_SECRET \ + -a "$TD_ACCESS_TOKEN" \ -f fluentui_notification/src/main/res/values \ -r fluentui_notification \ -o fluentui_notification/src/main/res/values From c66cb4ce0911f602dfcf3ab3397e15559ed271aa Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 13:54:02 +0530 Subject: [PATCH 6/9] Refactor access token retrieval in localization workflow Updated the process for obtaining the TouchDown Build access token using GitHub OIDC federated token. --- .github/workflows/localization.yml | 39 ++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/.github/workflows/localization.yml b/.github/workflows/localization.yml index 220e8b119..068332552 100644 --- a/.github/workflows/localization.yml +++ b/.github/workflows/localization.yml @@ -13,21 +13,34 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Azure Login (OIDC) - uses: azure/login@v2 - with: - client-id: ${{ secrets.AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_TENANT_ID }} - allow-no-subscriptions: true - - - name: Get access token + - name: Get access token for TouchDown Build id: get-token run: | - TOKEN=$(az account get-access-token \ - --resource "https://microsoft.onmicrosoft.com/tdb-touchdownbuild-prod" \ - --query accessToken -o tsv) - echo "::add-mask::$TOKEN" - echo "TD_ACCESS_TOKEN=$TOKEN" >> "$GITHUB_ENV" + # 1. Get the GitHub OIDC federated token + FEDERATED_TOKEN=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ + "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange" | jq -r '.value') + + # 2. Exchange it for a TouchDown Build access token + RESPONSE=$(curl -s -X POST \ + "https://login.microsoftonline.com/${{ secrets.AZURE_TENANT_ID }}/oauth2/v2.0/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "client_id=${{ secrets.AZURE_CLIENT_ID }}" \ + -d "scope=https://microsoft.onmicrosoft.com/tdb-touchdownbuild-prod/.default" \ + -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ + -d "client_assertion=$FEDERATED_TOKEN" \ + -d "grant_type=client_credentials") + + TOKEN=$(echo "$RESPONSE" | jq -r '.access_token') + + if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then + echo "ERROR: Failed to get access token" + echo "$RESPONSE" | jq . + exit 1 + fi + + echo "::add-mask::$TOKEN" + echo "TD_ACCESS_TOKEN=$TOKEN" >> "$GITHUB_ENV" + echo "Token acquired successfully (length: ${#TOKEN})" - shell: bash name: Localize env: From 6eef179f178528736a4b3b5ccb9c682069a78af8 Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 13:58:27 +0530 Subject: [PATCH 7/9] Modify TouchDown Build token exchange process Updated the TouchDown Build access token exchange endpoint and added clarification in comments. --- .github/workflows/localization.yml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/.github/workflows/localization.yml b/.github/workflows/localization.yml index 068332552..4d42cd03f 100644 --- a/.github/workflows/localization.yml +++ b/.github/workflows/localization.yml @@ -20,27 +20,17 @@ jobs: FEDERATED_TOKEN=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange" | jq -r '.value') - # 2. Exchange it for a TouchDown Build access token + # 2. Exchange it for a TouchDown Build access token (v1.0 endpoint) RESPONSE=$(curl -s -X POST \ - "https://login.microsoftonline.com/${{ secrets.AZURE_TENANT_ID }}/oauth2/v2.0/token" \ + "https://login.microsoftonline.com/${{ secrets.AZURE_TENANT_ID }}/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=${{ secrets.AZURE_CLIENT_ID }}" \ - -d "scope=https://microsoft.onmicrosoft.com/tdb-touchdownbuild-prod/.default" \ + -d "resource=https://microsoft.onmicrosoft.com/tdb-touchdownbuild-prod" \ -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ -d "client_assertion=$FEDERATED_TOKEN" \ -d "grant_type=client_credentials") TOKEN=$(echo "$RESPONSE" | jq -r '.access_token') - - if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then - echo "ERROR: Failed to get access token" - echo "$RESPONSE" | jq . - exit 1 - fi - - echo "::add-mask::$TOKEN" - echo "TD_ACCESS_TOKEN=$TOKEN" >> "$GITHUB_ENV" - echo "Token acquired successfully (length: ${#TOKEN})" - shell: bash name: Localize env: From 8b8023e620512807130fa6ca753d79b40ecffd04 Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 14:02:15 +0530 Subject: [PATCH 8/9] Improve error handling for token acquisition Added error handling for access token retrieval in localization workflow. --- .github/workflows/localization.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/localization.yml b/.github/workflows/localization.yml index 4d42cd03f..24f406ba5 100644 --- a/.github/workflows/localization.yml +++ b/.github/workflows/localization.yml @@ -31,6 +31,16 @@ jobs: -d "grant_type=client_credentials") TOKEN=$(echo "$RESPONSE" | jq -r '.access_token') + + if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then + echo "ERROR: Failed to get access token" + echo "$RESPONSE" | jq . + exit 1 + fi + + echo "::add-mask::$TOKEN" + echo "TD_ACCESS_TOKEN=$TOKEN" >> "$GITHUB_ENV" + echo "Token acquired successfully (length: ${#TOKEN})" - shell: bash name: Localize env: From b38711ef569c1b49ed60d7ea2fe7bb69e8866bfb Mon Sep 17 00:00:00 2001 From: Pranjal Singh Date: Sun, 22 Mar 2026 14:20:25 +0530 Subject: [PATCH 9/9] Change OAuth token exchange to v2.0 endpoint Updated the OAuth token exchange endpoint from v1.0 to v2.0 for improved compatibility. --- .github/workflows/localization.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/localization.yml b/.github/workflows/localization.yml index 24f406ba5..68ce5199b 100644 --- a/.github/workflows/localization.yml +++ b/.github/workflows/localization.yml @@ -18,19 +18,19 @@ jobs: run: | # 1. Get the GitHub OIDC federated token FEDERATED_TOKEN=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ - "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange" | jq -r '.value') - - # 2. Exchange it for a TouchDown Build access token (v1.0 endpoint) - RESPONSE=$(curl -s -X POST \ - "https://login.microsoftonline.com/${{ secrets.AZURE_TENANT_ID }}/oauth2/token" \ - -H "Content-Type: application/x-www-form-urlencoded" \ + "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=api://AzureADTokenExchange" | jq -r '.value') + + # 2. Exchange it for a TouchDown Build access token (v2.0 endpoint) + RESPONSE=$(curl -s -X POST \ + "https://login.microsoftonline.com/${{ secrets.AZURE_TENANT_ID }}/oauth2/v2.0/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=${{ secrets.AZURE_CLIENT_ID }}" \ - -d "resource=https://microsoft.onmicrosoft.com/tdb-touchdownbuild-prod" \ + -d "scope=https://prdtrs01.onmicrosoft.com/touchdownbuildservice_prod/.default" \ -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ -d "client_assertion=$FEDERATED_TOKEN" \ -d "grant_type=client_credentials") - - TOKEN=$(echo "$RESPONSE" | jq -r '.access_token') + + TOKEN=$(echo "$RESPONSE" | jq -r '.access_token') if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then echo "ERROR: Failed to get access token"