Skip to content
Closed

workflow #28417

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
51 changes: 51 additions & 0 deletions .github/workflows/README-auto-azp-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Auto ADO Pipeline Trigger for Azure Members

This GitHub Action automatically triggers Azure DevOps (ADO) pipelines for pull requests created by Azure organization members.

## How it works

1. **Trigger**: The workflow runs when a PR is opened or updated (push to PR branch)
2. **Membership Check**: Uses the existing script in `tools/GitHubOrgMember/Check-AzureOrgMembership.ps1` to verify if the PR author is an Azure organization member
3. **Authentication**: Uses the built-in `GITHUB_TOKEN` secret for authentication
4. **Pipeline Trigger**: Comments "/azp run" on the PR to trigger the ADO pipeline

## Required Permissions

The workflow uses the built-in `GITHUB_TOKEN` with the following permissions:
- `pull-requests: write` - To comment on PRs
- `contents: read` - To checkout the repository

No additional secrets need to be configured.

## Workflow Behavior

- ✅ **Azure Members**: ADO pipeline is triggered automatically with "/azp run" comment
- ❌ **Non-Azure Members**: Workflow silently completes without action
- 🔴 **Errors**: Workflow fails with error details in logs

## Troubleshooting

### Common Issues

1. **GitHub CLI Authentication Failed**
- This should not happen as we use the built-in `GITHUB_TOKEN`
- Check if the token permissions are sufficient

2. **Membership Check Failed**
- GitHub API rate limits may cause temporary failures
- User might have private membership in Azure organization
- Check the GitHub CLI authentication

3. **Comment Creation Failed**
- Verify the workflow has `pull-requests: write` permission
- Check if the PR number is correct

### Logs

Check the GitHub Actions logs for detailed error messages and troubleshooting information.

## Security Notes

- Uses `pull_request` trigger (safe for public repositories)
- Only uses built-in `GITHUB_TOKEN` - no external secrets required
- Membership verification happens before any ADO pipeline trigger
85 changes: 85 additions & 0 deletions .github/workflows/auto-azp-run.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Auto Trigger ADO Pipeline for Azure Members
run-name: Auto trigger ADO pipeline for PR by Azure member

on:
pull_request:
types: [opened, synchronize]

jobs:
check-and-trigger:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
sparse-checkout: |
tools/GitHubOrgMember

- name: Set up GitHub CLI
shell: pwsh
run: |
# Install GitHub CLI if not present
if (-not (Get-Command gh -ErrorAction SilentlyContinue)) {
Write-Host "Installing GitHub CLI..."
# GitHub CLI is typically pre-installed on GitHub runners
gh --version
}

- name: Authenticate with GitHub CLI using token
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Write-Host "Authenticating GitHub CLI..."
echo $env:GH_TOKEN | gh auth login --with-token
gh auth status

- name: Get PR author and check Azure org membership
shell: pwsh
env:
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
Write-Host "Checking if PR author '$env:PR_AUTHOR' is an Azure organization member..."

# Use the existing script to check membership
$membershipResult = & "./tools/GitHubOrgMember/Check-AzureOrgMembership.ps1" -Username $env:PR_AUTHOR -Quiet

Write-Host "Membership check result:"
Write-Host "Username: $($membershipResult.Username)"
Write-Host "Organization: $($membershipResult.Organization)"
Write-Host "IsMember: $($membershipResult.IsMember)"
Write-Host "Status: $($membershipResult.Status)"

if ($membershipResult.ErrorMessage) {
Write-Host "Error: $($membershipResult.ErrorMessage)"
}

# Set output for next step
echo "IS_AZURE_MEMBER=$($membershipResult.IsMember)" >> $env:GITHUB_ENV
echo "MEMBERSHIP_STATUS=$($membershipResult.Status)" >> $env:GITHUB_ENV

- name: Trigger ADO pipeline for Azure member
if: env.IS_AZURE_MEMBER == 'True'
shell: pwsh
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
try {
Write-Host "PR author is an Azure member. Proceeding to trigger ADO pipeline..."

# Comment "/azp run" on the PR to trigger ADO pipeline
Write-Host "Commenting '/azp run' on PR #$env:PR_NUMBER to trigger ADO pipeline..."
gh pr comment $env:PR_NUMBER --body "/azp run"

Write-Host "✅ Successfully triggered ADO pipeline for PR #$env:PR_NUMBER"
}
catch {
Write-Error "❌ Failed to trigger ADO pipeline: $($_.Exception.Message)"
exit 1
}
37 changes: 37 additions & 0 deletions requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Automatically Trigger ADO Pipelines for PR by Azure Members

## Background

The `Azure/azure-powershell` repository is an open-source repository with lots of community contributions, whose quality is ensured through CI - Azure DevOps pipelines. The pipelines are currently not triggered automatically for pull requests (PRs) made by anyone except for repository owners, which can slow down the development process and make it harder to catch issues early. The purpose of this document is to automatically trigger ADO pipelines for PRs made by Azure members.

## Concepts

- **Azure member**: An Azure member is a GitHub user who is part of the Azure organization.
- **Azure organization**: The Azure organization is the GitHub organization that contains the Azure-related repositories, as well as GitHub users who are members of the Azure team.

## Goal & Scope

Set up a GitHub Action that listens to any change in pull requests and triggers the ADO pipeline for Azure members by commenting "/azp run".

Scope is all pull requests to the `Azure/azure-powershell` repository.

## Requirements

1. **Trigger by push**: The system must trigger the ADO pipelines when a push is made to the PR branch.
- This includes both the initial creation of the PR and any subsequent updates to the PR.
2. **Azure Member Verification**: The system must verify that the PR is **created** by an Azure member.
- The system should not trigger the pipeline for PRs created by non-Azure members.
- Whether it's *updated* by an Azure member doesn't matter because non-members cannot push changes to the PR.
3. **Authenticate with GitHub token**: The system must authenticate using the GitHub token provided by the `GITHUB_TOKEN` secret.

## Resources

- There is an existing PowerShell script in `tools/GitHubOrgMember` that can be used to verify Azure organization membership.
- The script depends on `GitHub CLI` for querying GitHub API and authentication.
- Commenting "/azp run" on the PR should trigger the ADO pipeline if the account has the right permission.

## Notes

- In case anything unexpected happens, the system should log the error and simply fail the GitHub Action.
- Duplicating "/azp run" comments isn't a problem to the system and can be safely ignored.
- Do not use `pull_request_target` event for this workflow.
125 changes: 125 additions & 0 deletions tools/GitHubOrgMember/Check-AzureOrgMembership.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Check if a GitHub user is a member of the Azure organization.

.DESCRIPTION
This script uses the GitHub CLI to check if a specified user is a member of the Azure GitHub organization.
Returns a structured PowerShell object with membership details.

.PARAMETER Username
The GitHub username to check.

.PARAMETER Organization
The GitHub organization to check membership for. Defaults to "Azure".

.PARAMETER Quiet
Suppress console output and only return the object.

.OUTPUTS
PSCustomObject with the following properties:
- Username: The checked username
- Organization: The organization that was checked
- IsMember: Boolean indicating if user is a public member
- Status: Detailed status (PublicMember, NotMember, PrivateMember, UserNotFound, Error)
- ErrorMessage: Error details if Status is Error
- CheckedAt: Timestamp of when the check was performed

.EXAMPLE
$result = .\Check-AzureOrgMembership.ps1 "octocat"
if ($result.IsMember) { Write-Host "User is a member!" }

.EXAMPLE
.\Check-AzureOrgMembership.ps1 "octocat" -Quiet | ConvertTo-Json
#>

[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateNotNullOrEmpty()]
[string]$Username,

[Parameter()]
[string]$Organization = "Azure",

[Parameter()]
[switch]$Quiet
)

function Write-ConditionalOutput {
param([string]$Message, [string]$ForegroundColor = "White")
if (-not $Quiet) {
Write-Host $Message -ForegroundColor $ForegroundColor
}
}

# Initialize result object
$result = [PSCustomObject]@{
Username = $Username
Organization = $Organization
IsMember = $false
Status = "Unknown"
ErrorMessage = $null
CheckedAt = Get-Date
}

try {
# Check if GitHub CLI is available
if (-not (Get-Command gh -ErrorAction SilentlyContinue)) {
$result.Status = "Error"
$result.ErrorMessage = "GitHub CLI (gh) is not installed. Install from: https://cli.github.com/"
Write-ConditionalOutput "❌ GitHub CLI not found" "Red"
return $result
}

# Check if authenticated
$null = gh auth status 2>&1
if ($LASTEXITCODE -ne 0) {
$result.Status = "Error"
$result.ErrorMessage = "GitHub CLI is not authenticated. Run 'gh auth login' first."
Write-ConditionalOutput "❌ GitHub CLI not authenticated" "Red"
return $result
}

Write-ConditionalOutput "🔍 Checking if '$Username' is a member of '$Organization' organization..." "Yellow"

# Check organization membership using GitHub API
gh api "orgs/$Organization/members/$Username" --silent 2>$null
$apiExitCode = $LASTEXITCODE

if ($apiExitCode -eq 0) {
# User is a public member
$result.IsMember = $true
$result.Status = "PublicMember"
Write-ConditionalOutput "✅ $Username is a PUBLIC member of the $Organization organization!" "Green"
}
elseif ($apiExitCode -eq 1) {
# Exit code 1 typically means 404 - could be not a member or private membership
# Check if user exists
gh api "users/$Username" --silent 2>$null
if ($LASTEXITCODE -eq 0) {
$result.IsMember = $false
$result.Status = "NotMemberOrPrivate"
Write-ConditionalOutput "❌ $Username is either not a member of $Organization organization or has private membership." "Red"
}
else {
$result.Status = "UserNotFound"
$result.ErrorMessage = "User '$Username' was not found on GitHub."
Write-ConditionalOutput "❌ User '$Username' was not found on GitHub." "Red"
}
}
else {
# Unexpected error
$result.Status = "Error"
$result.ErrorMessage = "Unexpected error occurred (GitHub API exit code: $apiExitCode)"
Write-ConditionalOutput "❌ Unexpected error checking membership (exit code: $apiExitCode)" "Red"
}
}
catch {
$result.Status = "Error"
$result.ErrorMessage = "Exception occurred: $($_.Exception.Message)"
Write-ConditionalOutput "❌ Error: $($_.Exception.Message)" "Red"
}

# Return the result object
return $result
59 changes: 59 additions & 0 deletions tools/GitHubOrgMember/Demo-ObjectBased.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Demonstration of Object-Based GitHub Organization Membership Checker

Write-Host "🚀 Object-Based Azure Membership Checker Demo" -ForegroundColor Cyan
Write-Host "=" * 50 -ForegroundColor Cyan

# Example 1: Simple membership check
Write-Host "`n📋 Example 1: Simple Check" -ForegroundColor Yellow
$result = .\Check-AzureOrgMembership.ps1 "vidai-msft" -Quiet 2>$null
Write-Host "User: $($result.Username)"
Write-Host "Is Member: $($result.IsMember)"
Write-Host "Status: $($result.Status)"

# Example 2: Batch processing with objects
Write-Host "`n📋 Example 2: Batch Processing" -ForegroundColor Yellow
$users = @("vidai-msft", "isra-fel", "msJinLei", "NickCandy")
$results = $users | ForEach-Object {
.\Check-AzureOrgMembership.ps1 $_ -Quiet 2>$null
}

Write-Host "Batch Results:"
$results | Format-Table Username, IsMember, Status -AutoSize

# Example 3: Filtering and processing
Write-Host "`n📋 Example 3: Filter Members Only" -ForegroundColor Yellow
$members = $results | Where-Object { $_.IsMember }
Write-Host "Azure Members Found: $($members.Count)"
$members | ForEach-Object { Write-Host " - $($_.Username)" -ForegroundColor Green }

# Example 4: JSON export
Write-Host "`n📋 Example 4: JSON Export" -ForegroundColor Yellow
$jsonResult = $results | ConvertTo-Json -Depth 2
Write-Host "Sample JSON (first result):"
$results[0] | ConvertTo-Json | Write-Host

# Example 5: Error handling
Write-Host "`n📋 Example 5: Error Handling" -ForegroundColor Yellow
$errorResult = $results | Where-Object { $_.Status -eq "Error" }
if ($errorResult.Count -gt 0) {
Write-Host "Errors found:"
$errorResult | ForEach-Object { Write-Host " - $($_.Username): $($_.ErrorMessage)" -ForegroundColor Red }
} else {
Write-Host "No errors detected" -ForegroundColor Green
}

# Example 6: Different organization
Write-Host "`n📋 Example 6: Different Organization" -ForegroundColor Yellow
$microsoftResult = .\Check-AzureOrgMembership.ps1 "vidai-msft" -Organization "microsoft" -Quiet 2>$null
Write-Host "Checking Microsoft org membership for vidai-msft:"
Write-Host " Organization: $($microsoftResult.Organization)"
Write-Host " Is Member: $($microsoftResult.IsMember)"
Write-Host " Status: $($microsoftResult.Status)"

Write-Host "`n✨ Object-Based Advantages Demonstrated:" -ForegroundColor Cyan
Write-Host " ✅ Type-safe property access" -ForegroundColor Green
Write-Host " ✅ Easy filtering and processing" -ForegroundColor Green
Write-Host " ✅ Pipeline-friendly operations" -ForegroundColor Green
Write-Host " ✅ JSON serialization support" -ForegroundColor Green
Write-Host " ✅ Structured error information" -ForegroundColor Green
Write-Host " ✅ No exit code dependencies" -ForegroundColor Green
Loading
Loading