public/syncRepoAccess.ps1
<# .SYNOPSIS Synchronize the access of a list of users to a repository. #> function Sync-RepoAccess{ [CmdletBinding(SupportsShouldProcess)] [OutputType([hashtable])] param( [Parameter(Mandatory,Position=0)][ValidateSet("read", "triage", "write", "maintain", "admin")] [string]$role, [Parameter(Mandatory,Position=1)] [string]$FilePath, [Parameter()] [string]$Owner, [Parameter()] [string]$Repo ) # Resolve repor form parameters and environment $Owner,$Repo = Get-Environment $Owner $Repo # Error if parameters not set. No need to check repo too. if([string]::IsNullOrEmpty($Owner) -or [string]::IsNullOrEmpty($Repo)){ "[Sync-RepoAccess] Owner and Repo parameters are required" | Write-Error return $null } "Syncing access $role to $Owner/$Repo from $FilePath" | Write-Verbose $ret = @{} # Read users from file $users = Get-UsersFromFile -Path $FilePath if($null -eq $users){ "Error reading user file $FilePath" | Write-Error return $null } "Found $($users.Count) users" | Write-Verbose # Get current permissions and invitations $permissions = Get-UserAccess -Owner $Owner -Repo $Repo $invitations = Get-RepoAccessInvitations -Owner $Owner -Repo $Repo "Found $($permissions.Count) permissions granted" | Write-Verbose "Found $($invitations.Count) invitations pending" | Write-Verbose # Update or add existing users foreach($user in $users){ "Processing $user for role $role" | Write-Verbose # Already invited to this role if($invitations.$user -eq $role){ "User $user has an invitation pending" | Write-Verbose $ret.$user = "?" continue } # Already granted to this role if($permissions.$user -eq $role){ "User $user already has this role" | Write-Verbose $ret.$user = "=" continue } # Check if it has granted a different role "User $user needs to be granted $role" | Write-Verbose if($permissions.ContainsKey($user)){ "User $user has already granted role $($permissions.$user)" | Write-Verbose $status = "+ ($($permissions.$user))" } elseif ($invitations.ContainsKey($user)){ "User $user has already an invitation pending for role $($invitations.$user)" | Write-Verbose $status = "+ ($($invitations.$user))" } else { $status = "+" } # Force to avoid the call to check if the access is already set if ($PSCmdlet.ShouldProcess("User $user", "Grant-RepoAccess -Owner $Owner -Repo $Repo -User $user -Role $role -Force")) { $result = Grant-RepoAccess -Owner $Owner -Repo $Repo -User $user -Role $role -Force if($result.$user -eq $role.ToLower()){ "User $user granted $role" | Write-Verbose $ret.$user = $status } else { "Error granting $role to $user" | Write-Verbose $ret.$user = "X" } } else { $ret.$user = $status } } # Delete non existing users "Deleting users that are granted but not in the list" | Write-Verbose # Just remove the users that where set to $role $usersToDelete = $Permissions.Keys | Where-Object { $users -notcontains $_ } $usersToDelete = $usersToDelete | Where-Object { $Permissions.$_ -eq $role} "Found $($usersToDelete.Count) users to delete" | Write-Verbose foreach($userToDelete in $usersToDelete){ "Deleting $userToDelete access $role to $Owner/$Repo" | Write-Verbose if ($PSCmdlet.ShouldProcess("User $userToDelete", "Remove-RepoAccess -Owner $owner -Repo $repo -User $userToDelete")) { $result = Remove-RepoAccess -Owner $owner -Repo $repo -User $userToDelete if($null -eq $result){ "Deleted $role grant for $userToDelete" | Write-Verbose $ret.$userToDelete += "-" } else { "Error deleting $role grant for $userToDelete" | Write-Verbose $ret.$userToDelete += 'X -' } } else { $ret.$userToDelete += "-" } } return $ret } Export-ModuleMember -Function Sync-RepoAccess function Get-UsersFromFile{ [CmdletBinding()] [OutputType([string[]])] param( [Parameter(Mandatory)] [string]$Path ) $users = @() $content = Get-Content -Path $Path if(-not $?){ return $null } foreach($line in $content){ $line = $line.Trim() if($line -eq ""){ continue } if($line.StartsWith("#")){ continue } $users += $line } return $users } |