4 Commits

Author SHA1 Message Date
b6ac9524f7 Sync from dev @ 8fb465f
Source: main (8fb465f)
Excluded: live tenant exports, generated artifacts, and dev-only tooling.
2026-04-17 18:20:58 +02:00
0e96bf5af3 Sync from dev @ 14435d1
Source: main (14435d1)
Excluded: live tenant exports, generated artifacts, and dev-only tooling.
2026-04-17 18:10:40 +02:00
0acbaf7e0b Sync from dev @ ad9f9ab
Source: main (ad9f9ab)
Excluded: live tenant exports, generated artifacts, and dev-only tooling.
2026-04-17 18:05:00 +02:00
56448711e8 Sync from dev @ 726ecd2
Source: main (726ecd2)
Excluded: live tenant exports, generated artifacts, and dev-only tooling.
2026-04-17 16:41:19 +02:00
6 changed files with 147 additions and 27 deletions

View File

@@ -46,7 +46,7 @@ parameters:
variables:
# Tenant-specific values are expected in a variable group (see templates/variables-tenant.yml).
# Uncomment the line below after creating the group in your Azure DevOps project.
# - group: vg-astral-tenant
- group: vg-astral-cqre
- template: templates/variables-common.yml
- name: BACKUP_FOLDER
value: tenant-state
@@ -64,6 +64,26 @@ jobs:
- checkout: self
persistCredentials: true
# Uncomment the block below for agent-side debugging.
# - task: Bash@3
# displayName: DEBUG — dump agent state (restore)
# inputs:
# targetType: inline
# script: |
# set -euo pipefail
# echo "=== Variables ==="
# echo "BACKUP_FOLDER=$(BACKUP_FOLDER)"
# echo "INTUNE_BACKUP_SUBDIR=$(INTUNE_BACKUP_SUBDIR)"
# echo "BASELINE_BRANCH=$(BASELINE_BRANCH)"
# echo "=== Git state ==="
# git branch -a
# git log --oneline -5
# git status --short
# echo "=== File system ==="
# ls -la "$(Build.SourcesDirectory)"
# find "$(BACKUP_FOLDER)" -maxdepth 2 -type d 2>/dev/null || true
# workingDirectory: "$(Build.SourcesDirectory)"
- task: Bash@3
displayName: Checkout approved baseline snapshot
inputs:

View File

@@ -13,7 +13,7 @@ schedules:
variables:
# Tenant-specific values are expected in a variable group (see templates/variables-tenant.yml).
# Uncomment the line below after creating the group in your Azure DevOps project.
# - group: vg-astral-tenant
- group: vg-astral-cqre
- template: templates/variables-common.yml
jobs:
@@ -26,6 +26,26 @@ jobs:
- checkout: self
persistCredentials: true
# Uncomment the block below for agent-side debugging.
# - task: Bash@3
# displayName: DEBUG — dump agent state (Intune review sync)
# inputs:
# targetType: inline
# script: |
# set -euo pipefail
# echo "=== Variables ==="
# echo "BACKUP_FOLDER=$(BACKUP_FOLDER)"
# echo "DRIFT_BRANCH_INTUNE=$(DRIFT_BRANCH_INTUNE)"
# echo "BASELINE_BRANCH=$(BASELINE_BRANCH)"
# echo "=== Git state ==="
# git branch -a
# git log --oneline -5
# git status --short
# echo "=== File system ==="
# ls -la "$(Build.SourcesDirectory)"
# find "$(BACKUP_FOLDER)" -maxdepth 2 -type d 2>/dev/null || true
# workingDirectory: "$(Build.SourcesDirectory)"
- task: Bash@3
displayName: Apply reviewer /reject decisions (Intune)
condition: eq(variables['ENABLE_PR_REVIEWER_DECISIONS'], 'true')
@@ -114,6 +134,26 @@ jobs:
- checkout: self
persistCredentials: true
# Uncomment the block below for agent-side debugging.
# - task: Bash@3
# displayName: DEBUG — dump agent state (Entra review sync)
# inputs:
# targetType: inline
# script: |
# set -euo pipefail
# echo "=== Variables ==="
# echo "BACKUP_FOLDER=$(BACKUP_FOLDER)"
# echo "DRIFT_BRANCH_ENTRA=$(DRIFT_BRANCH_ENTRA)"
# echo "BASELINE_BRANCH=$(BASELINE_BRANCH)"
# echo "=== Git state ==="
# git branch -a
# git log --oneline -5
# git status --short
# echo "=== File system ==="
# ls -la "$(Build.SourcesDirectory)"
# find "$(BACKUP_FOLDER)" -maxdepth 2 -type d 2>/dev/null || true
# workingDirectory: "$(Build.SourcesDirectory)"
- task: Bash@3
displayName: Apply reviewer /reject decisions (Entra)
condition: eq(variables['ENABLE_PR_REVIEWER_DECISIONS'], 'true')

View File

@@ -17,7 +17,7 @@ schedules:
variables:
# Tenant-specific values are expected in a variable group (see templates/variables-tenant.yml).
# Uncomment the line below after creating the group in your Azure DevOps project.
# - group: vg-astral-tenant
- group: vg-astral-cqre
- template: templates/variables-common.yml
- name: ROLLING_PR_TITLE_INTUNE
value: "Intune drift review (rolling)"
@@ -85,6 +85,28 @@ jobs:
- checkout: self
persistCredentials: true
# Uncomment the block below for agent-side debugging.
# - task: Bash@3
# displayName: DEBUG — dump agent state (Intune)
# inputs:
# targetType: inline
# script: |
# set -euo pipefail
# echo "=== Variables ==="
# echo "BACKUP_FOLDER=$(BACKUP_FOLDER)"
# echo "INTUNE_BACKUP_SUBDIR=$(INTUNE_BACKUP_SUBDIR)"
# echo "DRIFT_BRANCH_INTUNE=$(DRIFT_BRANCH_INTUNE)"
# echo "BASELINE_BRANCH=$(BASELINE_BRANCH)"
# echo "AGENT_POOL_NAME=$(AGENT_POOL_NAME)"
# echo "=== Git state ==="
# git branch -a
# git log --oneline -5
# git status --short
# echo "=== File system ==="
# ls -la "$(Build.SourcesDirectory)"
# find "$(BACKUP_FOLDER)" -maxdepth 2 -type d 2>/dev/null || true
# workingDirectory: "$(Build.SourcesDirectory)"
- task: Bash@3
displayName: Snapshot validation helper script (Intune job)
inputs:
@@ -129,7 +151,7 @@ jobs:
FULL_RUN=1
MODE="full"
REASON="forced by parameter forceFullRun=true"
elif [ "$PRAGUE_HOUR" = "00" ]; then
elif [ "$LOCAL_HOUR" = "$(FULL_RUN_HOUR)" ]; then
FULL_RUN=1
MODE="full"
REASON="scheduled midnight full run"
@@ -138,7 +160,7 @@ jobs:
MODE="light"
REASON="default hourly light run"
fi
echo "Run mode decision: $MODE ($REASON; Prague local time: $PRAGUE_NOW)"
echo "Run mode decision: $MODE ($REASON; local time ($(BACKUP_TIMEZONE)): $LOCAL_NOW)"
echo "##vso[task.setvariable variable=FULL_RUN]$FULL_RUN"
echo "##vso[task.setvariable variable=FULL_RUN;isOutput=true]$FULL_RUN"
workingDirectory: "$(Build.SourcesDirectory)"
@@ -757,13 +779,23 @@ jobs:
$generatedSplitMarkdownPattern = '^' + [Regex]::Escape("$(BACKUP_FOLDER)") + '/.*\.md$'
$generatedReportPattern = '^' + [Regex]::Escape("$(BACKUP_FOLDER)/$(REPORTS_SUBDIR)/")
$workloadConfigPattern = '^' + [Regex]::Escape("$(BACKUP_FOLDER)/$(INTUNE_BACKUP_SUBDIR)/")
$changedFile = $untrackedFile, $trackedFile | % { $_ } | ? {
Write-Host "DEBUG: BACKUP_FOLDER=$(BACKUP_FOLDER), INTUNE_BACKUP_SUBDIR=$(INTUNE_BACKUP_SUBDIR)"
Write-Host "DEBUG: workloadConfigPattern = $workloadConfigPattern"
Write-Host "DEBUG: untracked count = $($untrackedFile.Count), tracked count = $($trackedFile.Count)"
$allFiles = @()
if ($untrackedFile) { $allFiles += $untrackedFile }
if ($trackedFile) { $allFiles += $trackedFile }
$changedFile = $allFiles | ? {
$_ -and
$_ -match $workloadConfigPattern -and
$_ -notmatch $generatedSplitMarkdownPattern -and
$_ -notmatch $generatedReportPattern -and
$_ -notlike "*/Assignment Report/*"
}
Write-Host "DEBUG: changed count = $($changedFile.Count)"
if ($changedFile.Count -gt 0) {
$changedFile | Select-Object -First 5 | ForEach-Object { Write-Host "DEBUG: changed file: $_" }
}
if ($changedFile) {
git show-ref --verify --quiet "refs/remotes/origin/$(DRIFT_BRANCH_INTUNE)"
@@ -1023,22 +1055,7 @@ jobs:
}
$modificationAuthor = $modificationAuthor | Sort-Object Key -Unique
} else {
$isNonResourceFile = (
$file -like "*/reports/*" -or
$file -like "*/Assignment Report/*" -or
$file -like "*/Managed Google Play/*" -or
$file -like "*Device Management Settings/settings.json" -or
$file -like "*/Apple Push Notification/*" -or
$file -like "*Device Configurations/mobileconfig/*" -or
$file -like "*.md" -or
$file -like "*.gitkeep"
)
if ($isNonResourceFile) {
$nonResourceFileCount++
} else {
throw "Unable to find resourceId in '$file' file name. Pipeline code modification needed."
}
$nonResourceFileCount++
$modificationAuthor = $null
}
@@ -1337,6 +1354,28 @@ jobs:
- checkout: self
persistCredentials: true
# Uncomment the block below for agent-side debugging.
# - task: Bash@3
# displayName: DEBUG — dump agent state (Entra)
# inputs:
# targetType: inline
# script: |
# set -euo pipefail
# echo "=== Variables ==="
# echo "BACKUP_FOLDER=$(BACKUP_FOLDER)"
# echo "ENTRA_BACKUP_SUBDIR=$(ENTRA_BACKUP_SUBDIR)"
# echo "DRIFT_BRANCH_ENTRA=$(DRIFT_BRANCH_ENTRA)"
# echo "BASELINE_BRANCH=$(BASELINE_BRANCH)"
# echo "AGENT_POOL_NAME=$(AGENT_POOL_NAME)"
# echo "=== Git state ==="
# git branch -a
# git log --oneline -5
# git status --short
# echo "=== File system ==="
# ls -la "$(Build.SourcesDirectory)"
# find "$(BACKUP_FOLDER)" -maxdepth 2 -type d 2>/dev/null || true
# workingDirectory: "$(Build.SourcesDirectory)"
- task: Bash@3
displayName: Snapshot export/validation helper scripts (Entra job)
inputs:
@@ -1382,7 +1421,7 @@ jobs:
MODE="full"
FULL_RUN=1
MODE_REASON="forced by parameter forceFullRun=true"
elif [ "$PRAGUE_HOUR" = "00" ]; then
elif [ "$LOCAL_HOUR" = "$(FULL_RUN_HOUR)" ]; then
MODE="full"
FULL_RUN=1
MODE_REASON="scheduled midnight full run"
@@ -1414,7 +1453,7 @@ jobs:
APP_REG_SCOPE_REASON="disabled (pipeline variable)"
fi
echo "Run mode decision (Entra): $MODE ($MODE_REASON; Prague local time: $PRAGUE_NOW)"
echo "Run mode decision (Entra): $MODE ($MODE_REASON; local time ($(BACKUP_TIMEZONE)): $LOCAL_NOW)"
echo "Enterprise Applications export scope: $ENTERPRISE_SCOPE_REASON"
echo "App Registrations export scope: $APP_REG_SCOPE_REASON"
echo "##vso[task.setvariable variable=ENTRA_RUN_MODE]$MODE"

View File

@@ -205,7 +205,14 @@ def main() -> int:
pr = prs[0]
pr_id = int(pr.get("pullRequestId"))
_run_git(args.repo_root, ["fetch", "--quiet", "origin", baseline_branch, drift_branch])
_run_git(args.repo_root, ["fetch", "--quiet", "origin", baseline_branch])
try:
_run_git(args.repo_root, ["fetch", "--quiet", "origin", drift_branch])
except RuntimeError as exc:
if "couldn't find remote ref" in str(exc).lower() or "could not find remote ref" in str(exc).lower():
print(f"Drift branch '{drift_branch}' not found on origin; nothing to reject.")
return 0
raise
diff_paths = _run_diff_name_only(args.repo_root, baseline_branch, drift_branch)
changed_paths = {
p.strip()

View File

@@ -512,7 +512,14 @@ def main() -> int:
print("##vso[task.setvariable variable=DRIFT_PR_SUPPRESSED;isOutput=true]0")
return 0
_run_git(args.repo_root, ["fetch", "--quiet", "origin", baseline_branch, drift_branch])
_run_git(args.repo_root, ["fetch", "--quiet", "origin", baseline_branch])
try:
_run_git(args.repo_root, ["fetch", "--quiet", "origin", drift_branch])
except RuntimeError as exc:
if "couldn't find remote ref" in str(exc).lower() or "could not find remote ref" in str(exc).lower():
pass # Drift branch may not exist yet; fallback to HEAD below.
else:
raise
baseline_commitish = f"origin/{baseline_branch}" if _ref_has_commit(args.repo_root, f"origin/{baseline_branch}") else baseline_branch
drift_commitish = f"origin/{drift_branch}" if _ref_has_commit(args.repo_root, f"origin/{drift_branch}") else "HEAD"
if not _workload_config_diff_exists(

View File

@@ -2498,7 +2498,14 @@ def main() -> int:
return 0
_debug(f"Active rolling PR detected: pr_id={pr_id}, source={source_ref}, target={target_ref}")
_run_git(args.repo_root, ["fetch", "--quiet", "origin", baseline_branch, drift_branch])
_run_git(args.repo_root, ["fetch", "--quiet", "origin", baseline_branch])
try:
_run_git(args.repo_root, ["fetch", "--quiet", "origin", drift_branch])
except RuntimeError as exc:
if "couldn't find remote ref" in str(exc).lower() or "could not find remote ref" in str(exc).lower():
print(f"Drift branch '{drift_branch}' not found on origin; skipping summary update.")
return 0
raise
diff_output = _run_diff_name_status(args.repo_root, baseline_branch, drift_branch)
changes = _parse_changes(diff_output, args.backup_folder, args.reports_subdir)
_debug(f"Parsed non-doc/report changes for summary: count={len(changes)}")