mirror of
https://github.com/ScoopInstaller/Scoop.git
synced 2025-10-30 06:07:56 +00:00
feat(chore): Improve git.exe execution and add parallel bucket updates (#5122)
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
## [Unreleased](https://github.com/ScoopInstaller/Scoop/compare/master...develop)
|
||||
|
||||
### Features
|
||||
- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/pull/5122))
|
||||
|
||||
### Code Refactoring
|
||||
- **git:** Use Invoke-Git() with direct path to git.exe to prevent spawning shim subprocesses ([#5122](https://github.com/ScoopInstaller/Scoop/pull/5122))
|
||||
|
||||
## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15
|
||||
|
||||
### Features
|
||||
|
||||
@@ -20,8 +20,8 @@ switch ($subCommand) {
|
||||
}
|
||||
({ $subCommand -in @('-v', '--version') }) {
|
||||
Write-Host 'Current Scoop version:'
|
||||
if ((Test-CommandAvailable git) -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
|
||||
git -C "$PSScriptRoot\.." --no-pager log --oneline HEAD -n 1
|
||||
if (Test-GitAvailable -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
|
||||
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('log', 'HEAD', '-1', '--oneline')
|
||||
} else {
|
||||
$version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
|
||||
Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
|
||||
@@ -31,9 +31,9 @@ switch ($subCommand) {
|
||||
|
||||
Get-LocalBucket | ForEach-Object {
|
||||
$bucketLoc = Find-BucketDirectory $_ -Root
|
||||
if ((Test-Path "$bucketLoc\.git") -and (Test-CommandAvailable git)) {
|
||||
if (Test-GitAvailable -and (Test-Path "$bucketLoc\.git")) {
|
||||
Write-Host "'$_' bucket:"
|
||||
git -C "$bucketLoc" --no-pager log --oneline HEAD -n 1
|
||||
Invoke-Git -Path $bucketLoc -ArgumentList @('log', 'HEAD', '-1', '--oneline')
|
||||
Write-Host ''
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ function list_buckets {
|
||||
$bucket = [Ordered]@{ Name = $_ }
|
||||
$path = Find-BucketDirectory $_ -Root
|
||||
if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||
$bucket.Source = git -C $path config remote.origin.url
|
||||
$bucket.Updated = git -C $path log --format='%aD' -n 1 | Get-Date
|
||||
$bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
|
||||
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', "--format='%aD'", '-n', '1')
|
||||
} else {
|
||||
$bucket.Source = friendly_path $path
|
||||
$bucket.Updated = (Get-Item "$path\bucket").LastWriteTime
|
||||
@@ -113,7 +113,7 @@ function list_buckets {
|
||||
}
|
||||
|
||||
function add_bucket($name, $repo) {
|
||||
if (!(Test-CommandAvailable git)) {
|
||||
if (!(Test-GitAvailable)) {
|
||||
error "Git is required for buckets. Run 'scoop install git' and try again."
|
||||
return 1
|
||||
}
|
||||
@@ -130,7 +130,7 @@ function add_bucket($name, $repo) {
|
||||
}
|
||||
foreach ($bucket in Get-LocalBucket) {
|
||||
if (Test-Path -Path "$bucketsdir\$bucket\.git") {
|
||||
$remote = git -C "$bucketsdir\$bucket" config --get remote.origin.url
|
||||
$remote = Invoke-Git -Path "$bucketsdir\$bucket" -ArgumentList @('config', '--get', 'remote.origin.url')
|
||||
if ((Convert-RepositoryUri -Uri $remote) -eq $uni_repo) {
|
||||
warn "Bucket $bucket already exists for $repo"
|
||||
return 2
|
||||
@@ -139,14 +139,14 @@ function add_bucket($name, $repo) {
|
||||
}
|
||||
|
||||
Write-Host 'Checking repo... ' -NoNewline
|
||||
$out = git_cmd ls-remote $repo 2>&1
|
||||
$out = Invoke-Git -ArgumentList @('ls-remote', $repo) 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
error "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
|
||||
return 1
|
||||
}
|
||||
ensure $bucketsdir | Out-Null
|
||||
$dir = ensure $dir
|
||||
git_cmd clone "$repo" "`"$dir`"" -q
|
||||
Invoke-Git -ArgumentList @('clone', $repo, $dir, '-q')
|
||||
Write-Host 'OK'
|
||||
success "The $name bucket was added successfully."
|
||||
return 0
|
||||
@@ -169,7 +169,7 @@ function new_issue_msg($app, $bucket, $title, $body) {
|
||||
$bucket_path = "$bucketsdir\$bucket"
|
||||
|
||||
if (Test-Path $bucket_path) {
|
||||
$remote = git -C "$bucket_path" config --get remote.origin.url
|
||||
$remote = Invoke-Git -Path $bucket_path -ArgumentList @('config', '--get', 'remote.origin.url')
|
||||
# Support ssh and http syntax
|
||||
# git@PROVIDER:USER/REPO.git
|
||||
# https://PROVIDER/USER/REPO.git
|
||||
|
||||
89
lib/core.ps1
89
lib/core.ps1
@@ -128,13 +128,78 @@ function setup_proxy() {
|
||||
}
|
||||
}
|
||||
|
||||
function git_cmd {
|
||||
function Invoke-Git {
|
||||
[CmdletBinding()]
|
||||
[OutputType([String])]
|
||||
param(
|
||||
[Parameter(Mandatory = $false, Position = 0)]
|
||||
[Alias('PSPath', 'Path')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$WorkingDirectory,
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[Alias('Args')]
|
||||
[String[]]
|
||||
$ArgumentList
|
||||
)
|
||||
|
||||
$proxy = get_config PROXY
|
||||
$cmd = "git $($args | ForEach-Object { "$_ " })"
|
||||
if ($proxy -and $proxy -ne 'none') {
|
||||
$cmd = "SET HTTPS_PROXY=$proxy&&SET HTTP_PROXY=$proxy&&$cmd"
|
||||
$git = Get-HelperPath -Helper Git
|
||||
$arguments = $ArgumentList -join ' '
|
||||
$cmd = "`"$git`" $arguments"
|
||||
|
||||
if ($WorkingDirectory) {
|
||||
$cmd = "`"$git`" -C `"$WorkingDirectory`" $arguments"
|
||||
}
|
||||
$sb = [scriptblock]::Create("& $cmd")
|
||||
|
||||
if([String]::IsNullOrEmpty($proxy) -or $proxy -eq 'none') {
|
||||
return Invoke-Command $sb
|
||||
}
|
||||
|
||||
if($arguments -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
|
||||
$old_https = $env:HTTPS_PROXY
|
||||
$old_http = $env:HTTP_PROXY
|
||||
try {
|
||||
# convert proxy setting for git
|
||||
if ($proxy.StartsWith('currentuser@')) {
|
||||
$proxy = $proxy.Replace('currentuser@', ':@')
|
||||
}
|
||||
$env:HTTPS_PROXY = $proxy
|
||||
$env:HTTP_PROXY = $proxy
|
||||
return Invoke-Command $sb
|
||||
}
|
||||
catch {
|
||||
error $_
|
||||
return
|
||||
}
|
||||
finally {
|
||||
$env:HTTPS_PROXY = $old_https
|
||||
$env:HTTP_PROXY = $old_http
|
||||
}
|
||||
}
|
||||
|
||||
return Invoke-Command $sb
|
||||
}
|
||||
|
||||
function Invoke-GitLog {
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[String]$Path,
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[String]$CommitHash,
|
||||
[String]$Name = ''
|
||||
)
|
||||
Process {
|
||||
if ($Name) {
|
||||
if ($Name.Length -gt 12) {
|
||||
$Name = "$($Name.Substring(0, 10)).."
|
||||
}
|
||||
$Name = "%Cgreen$($Name.PadRight(12, ' ').Substring(0, 12))%Creset "
|
||||
}
|
||||
Invoke-Git -Path $Path -ArgumentList @('--no-pager', 'log', '--color', '--no-decorate', "--grep='^(chore)'", '--invert-grep', '--abbrev=12', "--format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s $Name%C(cyan)%cr%Creset'", "$CommitHash..HEAD")
|
||||
}
|
||||
cmd.exe /d /c $cmd
|
||||
}
|
||||
|
||||
# helper functions
|
||||
@@ -293,12 +358,16 @@ Function Test-CommandAvailable {
|
||||
Return [Boolean](Get-Command $Name -ErrorAction Ignore)
|
||||
}
|
||||
|
||||
Function Test-GitAvailable {
|
||||
Return [Boolean](Test-Path (Get-HelperPath -Helper Git) -ErrorAction Ignore)
|
||||
}
|
||||
|
||||
function Get-HelperPath {
|
||||
[CmdletBinding()]
|
||||
[OutputType([String])]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
|
||||
[ValidateSet('7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2', 'Zstd')]
|
||||
[ValidateSet('Git', '7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2', 'Zstd')]
|
||||
[String]
|
||||
$Helper
|
||||
)
|
||||
@@ -307,6 +376,14 @@ function Get-HelperPath {
|
||||
}
|
||||
process {
|
||||
switch ($Helper) {
|
||||
'Git' {
|
||||
$internalgit = "$(versiondir 'git' 'current')\mingw64\bin\git.exe"
|
||||
if (Test-Path $internalgit) {
|
||||
$HelperPath = $internalgit
|
||||
} else {
|
||||
$HelperPath = (Get-Command git -ErrorAction Ignore).Source
|
||||
}
|
||||
}
|
||||
'7zip' {
|
||||
$HelperPath = Get-AppFilePath '7zip' '7z.exe'
|
||||
if ([String]::IsNullOrEmpty($HelperPath)) {
|
||||
|
||||
@@ -84,7 +84,7 @@ if ($manifest.depends) {
|
||||
|
||||
if (Test-Path $manifest_file) {
|
||||
if (Get-Command git -ErrorAction Ignore) {
|
||||
$gitinfo = (git -C (Split-Path $manifest_file) log -1 -s --format='%aD#%an' $manifest_file 2> $null) -Split '#'
|
||||
$gitinfo = (Invoke-Git -Path (Split-Path $manifest_file) -ArgumentList @('log', '-1', '-s', "--format='%aD#%an'", $manifest_file) 2> $null) -Split '#'
|
||||
}
|
||||
if ($gitinfo) {
|
||||
$item.'Updated at' = $gitinfo[0] | Get-Date
|
||||
|
||||
@@ -21,10 +21,10 @@ if (!(Get-FormatData ScoopStatus)) {
|
||||
|
||||
function Test-UpdateStatus($repopath) {
|
||||
if (Test-Path "$repopath\.git") {
|
||||
git_cmd -C "`"$repopath`"" fetch -q origin
|
||||
Invoke-Git -Path $repopath -ArgumentList @('fetch', '-q', 'origin')
|
||||
$script:network_failure = 128 -eq $LASTEXITCODE
|
||||
$branch = git -C $repopath branch --show-current
|
||||
$commits = git -C $repopath log "HEAD..origin/$branch" --oneline
|
||||
$branch = Invoke-Git -Path $repopath -ArgumentList @('branch', '--show-current')
|
||||
$commits = Invoke-Git -Path $repopath -ArgumentList @('log', "HEAD..origin/$branch", '--oneline')
|
||||
if ($commits) { return $true }
|
||||
else { return $false }
|
||||
} else {
|
||||
|
||||
@@ -56,14 +56,18 @@ if(($PSVersionTable.PSVersion.Major) -lt 5) {
|
||||
}
|
||||
$show_update_log = get_config SHOW_UPDATE_LOG $true
|
||||
|
||||
function update_scoop($show_update_log) {
|
||||
function Sync-Scoop {
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Switch]$Log
|
||||
)
|
||||
# Test if Scoop Core is hold
|
||||
if(Test-ScoopCoreOnHold) {
|
||||
return
|
||||
}
|
||||
|
||||
# check for git
|
||||
if (!(Test-CommandAvailable git)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
|
||||
if (!(Test-GitAvailable)) { abort "Scoop uses Git to update itself. Run 'scoop install git' and try again." }
|
||||
|
||||
Write-Host "Updating Scoop..."
|
||||
$currentdir = fullpath $(versiondir 'scoop' 'current')
|
||||
@@ -72,7 +76,7 @@ function update_scoop($show_update_log) {
|
||||
$olddir = "$currentdir\..\old"
|
||||
|
||||
# get git scoop
|
||||
git_cmd clone -q $configRepo --branch $configBranch --single-branch "`"$newdir`""
|
||||
Invoke-Git -ArgumentList @('clone', '-q', $configRepo, '--branch', $configBranch, '--single-branch', $newdir)
|
||||
|
||||
# check if scoop was successful downloaded
|
||||
if (!(Test-Path "$newdir\bin\scoop.ps1")) {
|
||||
@@ -93,18 +97,18 @@ function update_scoop($show_update_log) {
|
||||
Remove-Item "$currentdir\..\old" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$previousCommit = git -C "$currentdir" rev-parse HEAD
|
||||
$currentRepo = git -C "$currentdir" config remote.origin.url
|
||||
$currentBranch = git -C "$currentdir" branch
|
||||
$previousCommit = Invoke-Git -Path $currentdir -ArgumentList @('rev-parse', 'HEAD')
|
||||
$currentRepo = Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url')
|
||||
$currentBranch = Invoke-Git -Path $currentdir -ArgumentList @('branch')
|
||||
|
||||
$isRepoChanged = !($currentRepo -match $configRepo)
|
||||
$isBranchChanged = !($currentBranch -match "\*\s+$configBranch")
|
||||
|
||||
# Stash uncommitted changes
|
||||
if (git -C "$currentdir" diff HEAD --name-only) {
|
||||
if (Invoke-Git -Path $currentdir -ArgumentList @('diff', 'HEAD', '--name-only')) {
|
||||
if (get_config AUTOSTASH_ON_CONFLICT) {
|
||||
warn "Uncommitted changes detected. Stashing..."
|
||||
git -C "$currentdir" stash push -m "WIP at $([System.DateTime]::Now.ToString('o'))" -u -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('stash', 'push', '-m', "WIP at $([System.DateTime]::Now.ToString('o'))", '-u', '-q')
|
||||
} else {
|
||||
warn "Uncommitted changes detected. Update aborted."
|
||||
return
|
||||
@@ -113,26 +117,26 @@ function update_scoop($show_update_log) {
|
||||
|
||||
# Change remote url if the repo is changed
|
||||
if ($isRepoChanged) {
|
||||
git -C "$currentdir" config remote.origin.url "$configRepo"
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.url', $configRepo)
|
||||
}
|
||||
|
||||
# Fetch and reset local repo if the repo or the branch is changed
|
||||
if ($isRepoChanged -or $isBranchChanged) {
|
||||
# Reset git fetch refs, so that it can fetch all branches (GH-3368)
|
||||
git -C "$currentdir" config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('config', 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*')
|
||||
# fetch remote branch
|
||||
git_cmd -C "`"$currentdir`"" fetch --force origin "refs/heads/`"$configBranch`":refs/remotes/origin/$configBranch" -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('fetch', '--force', 'origin', "refs/heads/$configBranch`:refs/remotes/origin/$configBranch", '-q')
|
||||
# checkout and track the branch
|
||||
git_cmd -C "`"$currentdir`"" checkout -B $configBranch -t origin/$configBranch -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('checkout', '-B', $configBranch, '-t', "origin/$configBranch", '-q')
|
||||
# reset branch HEAD
|
||||
git -C "$currentdir" reset --hard origin/$configBranch -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('reset', '--hard', "origin/$configBranch", '-q')
|
||||
} else {
|
||||
git_cmd -C "`"$currentdir`"" pull -q
|
||||
Invoke-Git -Path $currentdir -ArgumentList @('pull', '-q')
|
||||
}
|
||||
|
||||
$res = $lastexitcode
|
||||
if ($show_update_log) {
|
||||
git -C "$currentdir" --no-pager log --no-decorate --grep='^(chore)' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' "$previousCommit..HEAD"
|
||||
if ($Log) {
|
||||
Invoke-GitLog -Path $currentdir -CommitHash $previousCommit
|
||||
}
|
||||
|
||||
if ($res -ne 0) {
|
||||
@@ -140,29 +144,17 @@ function update_scoop($show_update_log) {
|
||||
}
|
||||
}
|
||||
|
||||
# This should have been deprecated after 2019-05-12
|
||||
# if ((Get-LocalBucket) -notcontains 'main') {
|
||||
# info "The main bucket of Scoop has been separated to 'https://github.com/ScoopInstaller/Main'"
|
||||
# info "Adding main bucket..."
|
||||
# add_bucket 'main'
|
||||
# }
|
||||
|
||||
shim "$currentdir\bin\scoop.ps1" $false
|
||||
}
|
||||
|
||||
function update_bucket($show_update_log) {
|
||||
# check for git
|
||||
if (!(Test-CommandAvailable git)) { abort "Scoop uses Git to update main bucket and others. Run 'scoop install git' and try again." }
|
||||
function Sync-Bucket {
|
||||
Param (
|
||||
[Switch]$Log
|
||||
)
|
||||
Write-Host "Updating Buckets..."
|
||||
|
||||
foreach ($bucket in Get-LocalBucket) {
|
||||
Write-Host "Updating '$bucket' bucket..."
|
||||
|
||||
$bucketLoc = Find-BucketDirectory $bucket -Root
|
||||
|
||||
if (!(Test-Path (Join-Path $bucketLoc '.git'))) {
|
||||
if ($bucket -eq 'main') {
|
||||
# Make sure main bucket, which was downloaded as zip, will be properly "converted" into git
|
||||
Write-Host " Converting 'main' bucket to git repo..."
|
||||
if (!(Test-Path (Join-Path (Find-BucketDirectory 'main' -Root) '.git'))) {
|
||||
info "Converting 'main' bucket to git repo..."
|
||||
$status = rm_bucket 'main'
|
||||
if ($status -ne 0) {
|
||||
abort "Failed to remove local 'main' bucket."
|
||||
@@ -171,16 +163,44 @@ function update_bucket($show_update_log) {
|
||||
if ($status -ne 0) {
|
||||
abort "Failed to add remote 'main' bucket."
|
||||
}
|
||||
} else {
|
||||
Write-Host "'$bucket' is not a git repository. Skipped."
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
$previousCommit = git -C "$bucketLoc" rev-parse HEAD
|
||||
git_cmd -C "`"$bucketLoc`"" pull -q
|
||||
if ($show_update_log) {
|
||||
git -C "$bucketLoc" --no-pager log --no-decorate --grep='^(chore)' --invert-grep --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' "$previousCommit..HEAD"
|
||||
|
||||
$buckets = Get-LocalBucket | ForEach-Object {
|
||||
$path = Find-BucketDirectory $_ -Root
|
||||
return @{
|
||||
name = $_
|
||||
valid = Test-Path (Join-Path $path '.git')
|
||||
path = $path
|
||||
}
|
||||
}
|
||||
|
||||
$buckets | Where-Object { !$_.valid } | ForEach-Object { Write-Host "'$($_.name)' is not a git repository. Skipped." }
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
# Parallel parameter is available since PowerShell 7
|
||||
$buckets | Where-Object { $_.valid } | ForEach-Object -ThrottleLimit 5 -Parallel {
|
||||
. "$using:PSScriptRoot\..\lib\core.ps1"
|
||||
|
||||
$bucketLoc = $_.path
|
||||
$name = $_.name
|
||||
|
||||
$previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
|
||||
Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
|
||||
if ($using:Log) {
|
||||
Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$buckets | Where-Object { $_.valid } | ForEach-Object {
|
||||
$bucketLoc = $_.path
|
||||
$name = $_.name
|
||||
|
||||
$previousCommit = Invoke-Git -Path $bucketLoc -ArgumentList @('rev-parse', 'HEAD')
|
||||
Invoke-Git -Path $bucketLoc -ArgumentList @('pull', '-q')
|
||||
if ($Log) {
|
||||
Invoke-GitLog -Path $bucketLoc -Name $name -CommitHash $previousCommit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,8 +341,8 @@ if (-not ($apps -or $all)) {
|
||||
error 'scoop update: --no-cache is invalid when <app> is not specified.'
|
||||
exit 1
|
||||
}
|
||||
update_scoop $show_update_log
|
||||
update_bucket $show_update_log
|
||||
Sync-Scoop -Log:$show_update_log
|
||||
Sync-Bucket -Log:$show_update_log
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
} else {
|
||||
@@ -336,8 +356,8 @@ if (-not ($apps -or $all)) {
|
||||
$apps_param = $apps
|
||||
|
||||
if ($updateScoop) {
|
||||
update_scoop $show_update_log
|
||||
update_bucket $show_update_log
|
||||
Sync-Scoop -Log:$show_update_log
|
||||
Sync-Bucket -Log:$show_update_log
|
||||
set_config LAST_UPDATE ([System.DateTime]::Now.ToString('o')) | Out-Null
|
||||
success 'Scoop was updated successfully!'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user