Skip to content

Update License PowerShell scripts for customers to update LT to PAYG or other LTs in bulk - #1501

Merged
Umachandar Jayachandran (uc-msft) merged 37 commits into
microsoft:masterfrom
pochiraju:rajpo_payg_updates
Aug 31, 2026
Merged

Umachandar Jayachandran (uc-msft) merged 37 commits into
microsoft:masterfrom
pochiraju:rajpo_payg_updates

Conversation

@pochiraju

Copy link
Copy Markdown
Contributor

All the changes for the license update scripts.

…sql-license-type.ps1

- Connect-Azure now reuses an existing valid Az/CLI session matching the
  target tenant instead of always forcing re-login, preventing hangs in
  non-interactive contexts.
- Module presence check now verifies Az.Accounts >= 4.2.0 directly instead
  of checking for the Az meta-package, avoiding false negatives and
  unnecessary/conflicting reinstalls.
- Includes pre-existing manage-payg-transition.ps1 fixes: removed unused
  Force_Start_On_Resources param usage, corrected Arc script download URL
  path, and cleaned up wrapper argument line-continuation formatting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… but never fetched)

Live end-to-end testing of RunMode Single revealed the Arc/Azure sub-scripts
were never downloaded before being invoked via the generated wrapper,
causing 'term not recognized' errors. Invoke-RestMethod download calls
(matching Invoke-RemoteScript's Scheduled-mode logic) are now added before
building the wrapper lines for both Arc and Azure targets.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e parameter

- Embedded the full logic of modify-azure-sql-license-type.ps1,
  modify-arc-sql-license-type.ps1, and set-azurerunbook.ps1 directly in this
  script. No external downloads (raw.githubusercontent.com) are required to
  run it anymore; the embedded content is materialized to local files at
  runtime (required for local invocation and Azure Automation runbook
  import), replacing the old Invoke-RestMethod download step.
- Added -TargetLicenseType parameter (PAYG [default] or AHUB) to control
  which license model resources are transitioned to. Internally translated
  to the vocabulary each embedded script expects:
    - Azure SQL resources: LicenseIncluded (PAYG) / BasePrice (AHUB)
    - Arc SQL Server: PAYG / LicenseOnly (AHUB-equivalent)
  Previously the Arc transition target was hardcoded to PAYG only.
- Updated README to describe the self-contained behavior and the new
  parameter.

Verified via live end-to-end testing against rajpoTest (SQL VM):
  - Default (-TargetLicenseType PAYG): AHUB -> PAYG succeeded, no downloads.
  - -TargetLicenseType AHUB: PAYG -> AHUB succeeded, no downloads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…est results

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The embedded/standalone set-azurerunbook.ps1 hardcoded './PayTransitionDownloads/'
as the folder prefix for -RunbookPath during Import-AzAutomationRunbook, but the
outer manage-payg-transition.ps1 materializes embedded scripts to
'./manage-payg-transition/'. This mismatch caused every -RunMode Scheduled
invocation to fail because the runbook file could never be found at the
computed path.

Found via rubber-duck agent review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- -Target now defaults to 'Both' instead of being mandatory.
- -RunMode now defaults to 'Single' instead of being mandatory.
- Updated docstring/examples to reflect the new defaults.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These parameters are only actually used by the Azure Automation account setup
path (RunMode Scheduled). They were previously mandatory unconditionally, which
forced -RunMode Single (one-time run) callers to supply unused values. Made
both optional in the param block and added a runtime check that requires them
only when -RunMode is 'Scheduled', failing fast with a clear error otherwise.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…apper

The Single-mode command-line generator emitted boolean arg values (e.g. the
hardcoded Force = $true for Arc) as a separate quoted token: '-Force 'True''.
Since -Force is a [switch] parameter in the embedded script, PowerShell does
not bind that trailing 'True' token to the switch; instead it gets consumed as
an unbound positional argument, which binds to the script's first positional
parameter (-SubId). This caused failures such as:
  'Subscription True was not found in tenant ... Please verify that the
  subscription exists in this tenant.'

Fixed by detecting boolean-valued args and emitting them as a bare switch
(e.g. '-Force') with no value when true, and omitting them entirely when
false, instead of always emitting '-ArgName ''<value>'''.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The manage-payg-transition.ps1 wrapper exposed no -TenantId or -ReportOnly
parameters, so operators could not target a specific tenant explicitly or
perform a safe dry run. The embedded scripts already accept both; only the
wrapper pass-through was missing. Wired through for Single and Scheduled modes.

Also fixed a genuine bug in modify-arc-sql-license-type.ps1: the
'Found N resource(s) to update' message read $resources.Count before
$resources was populated by the paging loop, so it always reported 0 even
when resources were found. Moved the message after the loop and switched it
to $allResults.Count. Applied to both the standalone script and the copy
embedded in manage-payg-transition.ps1.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Set-AzConnectedMachineExtension is called with -NoWait and previously had no
-ErrorAction, so service-side failures (e.g. 'An extension of type ... is still
processing. Only one instance of an extension may be in progress at a time')
surfaced as non-terminating errors. The catch block was never entered, and the
script printed 'Updated -- ...' for resources that had in fact failed.

Add -ErrorAction Stop so those errors are caught, and record the real outcome
per resource in the CSV via new UpdateResult/UpdateError columns
(NotAttempted / RequestSubmitted / Failed). The error text is now included in
the console message as well.

Applied to both the standalone modify-arc-sql-license-type.ps1 and the copy
embedded in manage-payg-transition.ps1; verified the two blocks are identical.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The parameter table and all three examples documented parameters that do not
exist on manage-payg-transition.ps1 (-SubId, -ResourceGroup, -RunAt,
-AutomationAccount, -ExclusionTag). Every documented example would have failed
if a user copied it. Replaced with the real parameter names (-targetSubscription,
-targetResourceGroup, -RunMode, -AutomationAccResourceGroupName,
-AutomationAccountName) and documented the previously undocumented -Target,
-TenantId, -ReportOnly, -cleanDownloads.

Also:
- Added a dry-run example and documented -ReportOnly as the recommended first step.
- Documented implicit tenant selection and the new UpdateResult/UpdateError CSV columns.
- Noted that already-converged resources are excluded by design (idempotent re-runs)
  and that Disconnected/Expired Arc agents cannot be updated.
- Fixed Cloud Shell auth step to use Connect-AzAccount instead of Connect-AzureAD.

Verified every parameter appearing in a README example resolves against the
script's AST parameter block.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each run materializes the embedded dependency scripts into
./manage-payg-transition/, writes a generated invocation wrapper to runnow.ps1,
and emits a ModifiedResources_<timestamp>.csv report plus a transcript log.
These were previously left untracked in the sample folder and could easily be
committed by accident.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolves the previously blocked Arc test case (microsoft#6) - Single/Arc has now been
executed end-to-end against real Arc-enabled machines. Adds cases microsoft#12-microsoft#19
covering the -Force switch-binding fix, -TenantId/-ReportOnly pass-through,
the always-zero resource count fix, isolated-folder self-containment, embedded
vs standalone sync, truthful Arc update outcomes, idempotent re-runs, and the
README parameter cross-check.

Refreshes Known gaps: Scheduled mode still never executed end-to-end;
Disconnected/Expired Arc agents cannot be updated; arcdata SqlServerInstances
with hostType 'Azure Virtual Machine' are read-only mirrors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both license scripts called Start-Transcript unconditionally and matched it with
an unguarded Stop-Transcript. If transcription never started -- because the log
path is not writable, or because the host does not support transcription (Azure
Automation runbooks do not) -- the script ended with:

  Stop-Transcript: An error occurred stopping transcription: The host is not
  currently transcribing.

The run itself had already succeeded, so this surfaced a spurious failure at the
very end of an otherwise clean execution.

Track whether transcription actually started and only stop it in that case,
warning instead of throwing if the start fails. Applied to modify-arc-sql-license-type.ps1,
modify-azure-sql-license-type.ps1, and both copies embedded in manage-payg-transition.ps1.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
If the SQL server query returned nothing, the script fell back to scanning every
server in the subscription whenever -ResourceName was absent -- even when
-ResourceGroup had been supplied. The elastic pool query is not resource-group
filtered (it only filters on licenseType and tags), so a real run could have
modified elastic pools on servers entirely outside the requested resource group.
Observed live: a run scoped to 'rajpobuddy' went on to scan three servers in
PT_Bugbash_Databases, BinujRg and TestServersSi6ci1WestEuropeRG. No pools existed
there, so nothing was wrongly modified, but the exposure was real.

Only fall back to all servers when neither -ResourceName nor -ResourceGroup was
specified; otherwise skip database/elastic pool processing and say so.

Also fix two misleading messages that made a successful dry run look like a
no-op:
- The SQL VM path printed nothing in ReportOnly mode, so a resource found and
  recorded in the CSV appeared to be silently ignored. It now reports the
  transition it would have made.
- 'No SQL VMs found to start that require a license update' printed on every run
  because  is never populated. Reworded to describe what it
  actually means.

Applied to the standalone script and re-synced the embedded copy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… verified end-to-end PAYG run

Case microsoft#21 records the scope-escape regression test: with -targetResourceGroup set
but no SQL Servers in that group, the script no longer falls back to scanning
every server in the subscription (which could have modified out-of-scope elastic
pools, since that query has no resource-group filter).

Case microsoft#22 records the final real run, with the resulting license type verified
out-of-band via 'az sql vm show' and Search-AzGraph rather than trusting the
script's own log output.

Also documents two newly-noted gaps: fixed transcript log paths overwrite prior
runs, and the Azure-side CSV lacks the UpdateResult/UpdateError columns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The integration runtime filter selected any runtime with Type 'Managed' whose
LicenseType differed from the target. The default AutoResolveIntegrationRuntime
is also Type 'Managed' (it is the data-flow runtime, not an SSIS-IR) and has a
null LicenseType, so 'null -ne LicenseIncluded' selected it. The subsequent
Set-AzDataFactoryV2IntegrationRuntime round-tripped the full payload and the
service rejected it with:

  Conflict / DataFactoryPropertyUpdateNotSupported
  Updating property managedVirtualNetwork is not supported

The filter now also requires a non-empty LicenseType, which only SSIS
integration runtimes carry.

The failure was additionally reported as a success: the cmdlet had no
-ErrorAction Stop, so the Conflict was non-terminating, the enclosing catch
never fired, and the script printed '-- DataFactory ... updated to license type
LicenseIncluded' directly after two error blocks. Each runtime is now updated
inside its own try/catch with -ErrorAction Stop.

Applies the same result-checking to the SQL VM path, which piped 'az sql vm
update' straight into ConvertFrom-Json without checking LASTEXITCODE and
appended its CSV row before the attempt.

Rows are now projected onto an explicit column set at export time, because
Export-Csv derives its header from the first object only and would otherwise
drop UpdateResult/UpdateError depending on which section emitted first.

Adds TESTPLAN cases microsoft#23-microsoft#26 and re-syncs the embedded copy in the
self-contained orchestrator.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The result-checking added for SQL VMs covered only one of five 'az ... update'
call sites. Managed Instances, SQL Databases, elastic pools and instance pools
still piped the CLI output straight into ConvertFrom-Json without inspecting
LASTEXITCODE, and appended their CSV row before the attempt, so a failed update
was recorded identically to a successful one.

The elastic pool path was the worst case:

  az sql elastic-pool update ... 2>\ | ConvertFrom-Json -ErrorAction SilentlyContinue

which discarded the service error text entirely and reported only 'No result
returned', giving no indication of why the update failed.

All five paths now route through a shared Invoke-AzCliLicenseUpdate helper that
checks LASTEXITCODE, surfaces the real service error, and returns a result
object used to populate UpdateResult/UpdateError.

The helper initially wrote its success message with Write-Output from inside the
function, which in PowerShell merges into the return value: callers received a
two-element array rather than the result object, and the message never reached
the transcript. The helper is now silent on the success stream and each caller
logs its own line.

Adds TESTPLAN cases microsoft#27-microsoft#28 and re-syncs the embedded copy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The report's UpdateResult column does not mean the same thing on both paths, and
nothing said so.

Azure CLI update calls are synchronous: no --no-wait is passed, so the CLI polls
the underlying PUT to a terminal state before returning. Measured on a SQL VM:
the call returned after 126s carrying provisioningState 'Succeeded', and the new
license type was immediately readable. 'Updated' therefore means committed.

The Arc path uses Set-AzConnectedMachineExtension -NoWait and never polls, so
'RequestSubmitted' means only that the service accepted the request. The
agent-side push can still fail afterwards without the script observing it.

Documents the distinction in the README, adds a Resource Graph query for
confirming the real Arc end state, and records TESTPLAN cases microsoft#29-microsoft#30 along with
the option of an opt-in -WaitForCompletion switch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Arc extension updates are submitted with -NoWait, so the report could only ever
record 'RequestSubmitted' - the service accepted the request, which says nothing
about whether the agent applied it. Confirming the real outcome previously
required a separate Resource Graph query.

Adds -WaitForCompletion (with -WaitTimeoutSeconds, default 300) which polls each
extension to a terminal provisioning state and records Succeeded/Failed/TimedOut
instead. The helper also compares the applied LicenseType against the requested
value, so a 'Succeeded' provisioning state carrying the wrong license is reported
as a failure rather than a success. Polling backs off 5->30s.

A timeout is deliberately not treated as a failure: the agent may still apply the
setting after the script stops waiting, so the outcome is recorded as
inconclusive.

The switch is opt-in because it serialises what is otherwise a fast parallel
fan-out across potentially hundreds of machines. Default behaviour is unchanged.

Verified live against sqltvm: reported Succeeded in 79.6s, confirmed
independently via Search-AzGraph (LicenseType LicenseOnly, provisioningState
Succeeded). Also verified inert under -ReportOnly and that the wrapper emits it
as a bare switch.

Adds TESTPLAN cases microsoft#31-microsoft#32.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure SQL updates previously always blocked until the operation completed, so a
large estate was processed serially. They are now submitted with --no-wait and
reported as 'RequestSubmitted'; passing -WaitForCompletion omits the flag so the
CLI polls to a terminal state and the result is reported as 'Updated'. This
matches the Arc path, which has always used -NoWait, giving one consistent
default across resource types.

Two resource types cannot honour this and are documented rather than faked:
'az sql vm update' and Set-AzDataFactoryV2IntegrationRuntime expose no
--no-wait/-AsJob equivalent. A generic 'az resource update/patch' fallback does
not support --no-wait either, and a direct ARM PATCH on a SQL VM is rejected
with MissingPatchParameters (approved values: tags, additionalVmPatch), so the
license type cannot be set by a lightweight non-blocking call. Hand-rolling a
full PUT was judged worse than documenting the limitation.

The helper only appends --no-wait for commands that accept it, and tolerates the
empty response body those calls return.

Adds TESTPLAN cases microsoft#33-microsoft#35 and re-syncs the embedded copy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
'az sql vm update' has no --no-wait option and blocks for roughly two minutes
per VM, so SQL virtual machines were the one Azure resource type that ignored
the async-by-default behaviour introduced with -WaitForCompletion.

Update-AzSqlVM advertises -NoWait and -AsJob but both are broken in
Az.SqlVirtualMachine 2.4.0: -NoWait forwards the bound parameter into
Get-AzSqlVM, which rejects it, and -AsJob throws a NullReferenceException.

Add Invoke-SqlVmLicenseUpdate, which submits the change to ARM directly by
reading the resource and writing it back with only sqlServerLicenseType
changed. ARM accepts the request and returns an Azure-AsyncOperation header
without waiting, so the call completes in seconds. The synchronous CLI path is
retained for -WaitForCompletion and as an automatic fallback on failure.

Verified live against rajpoTest: default run reported RequestSubmitted in
49.7s and the change was confirmed in Azure; -WaitForCompletion reported
Updated in 189.3s. Re-synced the embedded orchestrator copy and corrected the
README behaviour matrix and TESTPLAN case microsoft#34, which wrongly recorded the SQL
VM limitation as unavoidable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When an Arc machine already carries a LicenseType it is only overwritten if
-Force is supplied. That is intended, but the run was silent about it: the
unrelated ConsentToRecurringPAYG block could still set WriteSettings, so the
script wrote other settings and printed 'Updated' and 'Confirmed ... Succeeded'
for a license type that had not changed. The wait helper could not detect this
because it is passed the unmodified settings value, so expected and applied
matched. Found while restoring sqltvm, which reported success yet remained
LicenseOnly.

Emit an explicit warning naming the current and requested license types and
pointing at -Force. -Force semantics are unchanged.

Also harden Wait-ArcExtensionProvisioning against a stale terminal state.
Updates are submitted with -NoWait, so the first poll can observe the previous
operation's 'Succeeded' before the new one begins, with the old license type
still in place, which was reported as a hard failure. A terminal state carrying
an unexpected license type is now inconclusive and polling continues; the
mismatch is only returned as Failed if it survives to the timeout. The observed
state sequence Updating -> Creating -> Succeeded over ~2.5 minutes confirms the
race window is real.

Verified live: without -Force the run now reports 'Write Settings - False' and
no success line; with -Force sqltvm was restored to PAYG and independently
confirmed via Get-AzConnectedMachineExtension. Embedded Arc block re-synced.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Discovery calls piped az straight into ConvertFrom-Json with no exit-code
check. The Azure CLI signals failure through \0 rather than by
throwing, so a failed query yielded \ and every caller read that as 'no
resources found'. A transient failure was therefore indistinguishable from an
empty result: the run printed 'Found a total of 0 databases' and 'No SQL
Databases found ... that require a license update' and moved on, silently
skipping resources that needed transitioning while still looking clean.

Observed in a real run where az sql db list returned ResourceGroupNotFound for
three servers. The errors were spurious: all four resource groups exist, one
server succeeded in the same resource group where another failed, and all three
listed their databases correctly on retry.

Route every discovery path through a new Invoke-AzCliQuery helper (SQL VM list,
VM power state, MI list, server list, database list, elastic pool list,
instance pool list). It checks the exit code, surfaces the service error as a
warning and normalises the value to an array. Callers that cannot proceed
without the data now skip with an explicit warning instead of reporting zero.
This is the same bug class already fixed for the update paths.

Verified: helper unit-tested across success, failure and empty; a re-run now
reports 1 database each for demo731 and sqldbinlinemigtestserver instead of 0.
Embedded orchestrator copy re-synced.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Every az call in the Azure script is scoped by the CLI's active subscription,
but 'az account set --subscription' was issued without checking \0
at either call site. If the switch failed, the whole subscription loop body,
including the update calls, would have continued against whichever subscription
was selected beforehand, so resources in an unintended subscription could have
been modified.

The primary call site now warns and moves to the next subscription. The
mid-loop re-selection throws instead, which the enclosing handler catches so
SQL Server, database and elastic pool processing is skipped without aborting
the run.

Audited the remaining unchecked 'az ... | ConvertFrom-Json' pipes: the az tag
list one sits inside a commented-out block and the rest are az account show
login probes that are already guarded.

Regression-verified with a ReportOnly run: all 6 servers and their per-server
database counts are still enumerated correctly. Embedded copy re-synced.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds test cases 43 and 44 covering a run that completed with no errors after
the discovery-query and subscription-context fixes.

Every 'nothing found' claim in that run was checked against Azure rather than
taken at face value: the two real databases are already at the target license
type and the rest are master databases with a null licenseType; the
subscription's single SQL VM and single managed instance are both already at
their target, so they are correctly excluded by the filters rather than
skipped; and there are no elastic pools, instance pools or Arc machines.

Case 44 validates the DataFactory SSIS filter at a scale not previously
tested: 22 integration runtimes across 8 factories, all with an empty
LicenseType, including 5 of type Managed. Under the original filter all 22
would have been selected and the Managed ones would have failed with the same
managedVirtualNetwork Conflict that motivated the fix.

Also narrows the async coverage gap note: bhrout-mi exists but is already at
the target and belongs to another team, so it was left alone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verified via 'git archive' that a merge containing only the
manage-payg-transition folder delivers a self-sufficient orchestrator:
it materializes both sub-scripts from its embedded here-strings and
runs end-to-end with the sibling scripts absent, and the materialized
copies are byte-identical to the fixed standalone scripts.

Records the caveat that a folder-only merge would leave the standalone
modify-azure-sql-license-type.ps1 and modify-arc-sql-license-type.ps1
stale on master and break the embedded-vs-standalone sync invariant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Map -TargetLicenseType AHUB to 'Paid' (License with Software Assurance /
Azure Hybrid Benefit) for Arc SQL Server rather than 'LicenseOnly' (perpetual
without SA), allowing ESU to remain enabled and correctly aligning with AHB.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Implemented Format-ExecutionOutcomeSummary across Azure SQL, Arc SQL, and manage-payg-transition scripts.
- Summarizes qualified, updated, failed, and skipped resource counts grouped by friendly SQL resource type.
- Added detailed Failure & Skip Root Causes table reporting resource name, resource group, outcome, and diagnostic root cause reason.
- Updated TESTPLAN.md with test case microsoft#46 documenting the outcome summary and verification.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tatuses

- Wrapped Where-Object in @(...) to guarantee integer count in PowerShell.
- Added 'RequestSubmitted' and 'Succeeded' to the Azure script summary matching set.
- Verified live table formatting now correctly displays Updated counts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Renamed 'Updated' column to 'Updated or RequestSubmitted'.
- Set first column header to 'ResourceType' and sorted table by ResourceType.
- Consolidated summary output to print once at the very end of orchestrator execution instead of separate intermediate summaries.
- Updated sub-scripts to support -NoSummary when called by orchestrator.
- Updated TESTPLAN.md test case microsoft#46.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… summary

- Clean stale tracked_*.json files before starting Single run and after aggregating summary.
- Ensure sub-scripts remove tracked_*.json if no resources were marked for modification so prior runs do not contaminate subsequent runs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…1, modify-azure-sql-license-type.ps1, runnow.ps1)
@uc-msft
Umachandar Jayachandran (uc-msft) merged commit 3257bf8 into microsoft:master Aug 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants