NpmPS.psm1
$Script:PSModuleRoot = $PSScriptRoot # Importing from [/home/vsts/work/1/s/NpmPS\Public] # ./NpmPS/Public/Get-NpmPackageInfo.ps1 function Get-NpmPackageInfo { <# .Synopsis Get package info from NPM registry .Example Get-NpmPackageInfo -Name contoso-component -Registry 'http://contoso.local/npm' .Notes #> [cmdletbinding()] param( # Name of the npm package [Alias('PackageName')] [Parameter( Mandatory, Position = 0, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] [String] $Name, # NPM registry uri [Alias('URI','Repository')] [Parameter( Mandatory, Position = 1, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] [String] $Registry ) process { try { # need trailing slash on registry name if ( $Registry -notmatch '/$' ) { $Registry = "$Registry/" } $uri = "{0}{1}" -f $Registry, $Name Invoke-RestMethod -Uri $uri } catch { $PSCmdlet.ThrowTerminatingError( $PSItem ) } } } # ./NpmPS/Public/Publish-NpmPackage.ps1 function Publish-NpmPackage { <# .Synopsis Publishes a npm package .Example $registry = 'https://contoso.local/npm' $credential = Get-Credential $publishLDNpmPackageSplat = @{ Credential = $credential Email = user@contoso.com Path = $path Registry = $registry Version = '0.1.0-rc.1' Tag = 'testrelease' } Publish-NpmPackage @publishLDNpmPackageSplat .Notes #> [cmdletbinding()] param( # Location of the package.json [Parameter( Mandatory, Position = 0, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] [String] $Path, # NPM Registry to publish [Alias('Repository')] [String] $Registry, # Username and API Token as password [PSCredential] $Credential, [String] $Email, # SemVer [String] $Version, # tags to set when publishing [Alias('Tags')] [String[]] $Tag, # Force publish even if package already exists [Switch] $Force ) begin { $npmProtocolRegex = '^https?:' } process { try { $Path = $Path -replace '\\\\[\w\d-]*\\(\w)\$', '$1:' if ( -not ( Test-Path -Path $Path ) ) { Write-Error "Could not find [$Path] or access is denied" -ErrorAction Stop } elseif ( Test-Path -Path $Path -PathType Leaf ) { $Path = Split-Path -Path $Path } $package = Join-Path -Path $Path -ChildPath 'package.json' if ( -not ( Test-Path -Path $package ) ) { Write-Error "Could not find NPM Package [$package] or access is denied" -ErrorAction Stop } if ( $Registry -notmatch $npmProtocolRegex ) { Write-Error "Registry URI [$Registry] is not valid. Should match regex pattern [$npmProtocolRegex]" -ErrorAction Stop } Write-Verbose "Deploying package from path [$path]" Push-Location -Path $Path -StackName PublishNpmPackage Write-Verbose "Working directory [$pwd]" if ( ![string]::IsNullOrEmpty( $Version ) ) { if ($Version -notmatch '^v?\d+\.\d+(\.\d+)?') { Write-Error "Version [$Version] is not a valid SemVer" -ErrorAction 'Stop' } # ProGet needs to use period instead of plus for semver $Version -replace '\+', '.' $json = Get-Content $package -Raw | ConvertFrom-LDJson -ErrorAction Stop $json.version = $Version Write-Verbose "Set version to [{0}]" -f $json.version $json | Format-LDJson | Set-Content -Path $package -Encoding UTF8 } Write-Verbose "Contents of [$package]:" $packageData = Get-Content -Path $package -Raw $packageObject = $packageData | ConvertFrom-JSON Write-Verbose "Package version [$($packageObject.Version)]" Write-Verbose "Checking to see if package is already published" if ( Test-NpmPackage -Name $packageObject.name -Version $packageObject.version ) { Write-Verbose 'This package is already published' if ( !$Force ) { return } Write-Warning "This version of the package is already published. This will invalidate existing checksums for this version." } Write-Verbose "NPM Version [$(npm --version)]" $password = $Credential.GetNetworkCredential().password # need trailing slash on registry name if ( $Registry -notmatch '/$' ) { $Registry = "$Registry/" } # need registry without protocol prefix $shortRegName = $Registry -replace $npmProtocolRegex $config = @" registry=${Registry} ${shortRegName}:_password=$password ${shortRegName}:username=$($credential.username) ${shortRegName}:email=$Email ${shortRegName}:always-auth=false "@ $configPath = Join-Path $pwd -ChildPath '.npmrc' Write-Verbose "Saving registry info to project local config [$configPath]" Set-Content -Path $configPath -Value $config Write-Verbose "Running [npm config list]" npm config list if ( $null -eq $PSBoundParameters.Tag ) { Write-Verbose "Running [npm publish]" npm publish -tag prerelease } else { Write-Verbose "Publishing with tags [$( $Tag -join ',' )]" foreach ($publishTag in $Tag) { Write-Verbose "Running [npm publish -tag $publishTag]" npm publish -tag $publishTag } } if ( Test-NpmPackage -Name $packageObject.name -Version $packageObject.version ) { Write-Verbose 'This package is now available in the registry' } else { Write-Error "This published package could not be found in the registry [$registry]" } } catch { $PSCmdlet.ThrowTerminatingError( $PSItem ) } finally { Pop-Location -StackName PublishNpmPackage } } } # ./NpmPS/Public/Test-NpmPackage.ps1 function Test-NpmPackage { <# .Synopsis Tests to see if specified package is already published .Example $Name = 'contoso-component' $Registry = 'http://contoso.local/npm/' Test-NpmPackage -Name $Name -Registry $Registry .Example $Name = 'contoso-component' $Registry = 'http://contoso.local/npm/' Test-NpmPackage -Name $Name -Registry $Registry -Version 0.0.1 -Tag Latest .Notes #> [cmdletbinding()] param( # Name of the npm package [Alias('PackageName')] [Parameter( Mandatory, Position = 0, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] [String] $Name, # NPM Registry uri [Alias('URI','Repository')] [Parameter( Mandatory, Position = 1, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] [String] $Registry, # NPM Package Version [Parameter( Position = 2, ValueFromPipelineByPropertyName )] [String] $Version, # Package tag [Parameter( Position = 3, ValueFromPipelineByPropertyName )] [String] $Tag ) process { try { try { Write-Verbose "Querying for [$Name] in [$Registry]" $package = Get-NpmPackageInfo -Name $Name -Registry $Registry -ErrorAction Stop } catch { Write-Verbose 'Was not able to connect to registry or find the package' Write-Verbose $PSItem return $false } if ( $null -eq $package ) { Write-Verbose 'No package was found' return $false } if ( ![String]::IsNullOrEmpty( $Version ) ) { if ( $null -eq $package.versions ) { Write-Verbose "This package does not have a version" return $false } if ( -not $package.versions.$Version ) { Write-Verbose "This package version [$Version] was not found" return $false } } if ( ![String]::IsNullOrEmpty( $Tag ) ) { if ( $null -eq $package.'dist-tags' -or @($package.'dist-tags').count -lt 1 ) { Write-Verbose "This package does not have a tag" return $false } if ( -not $package.'dist-tags'.$Tag ) { Write-Verbose "This package tag [$Tag] was not found" return $false } } if ( ![String]::IsNullOrEmpty( $Version ) -and ![String]::IsNullOrEmpty( $Tag ) ) { if ( $package.'dist-tags'.$Tag -ne $Version ) { Write-Verbose ( "This package has tag [{0}][{1}] but did not match version [{2}]" -f $Tag,$package.'dist-tags'[$Tag],$Version ) return $false } } $true } catch { $PSCmdlet.ThrowTerminatingError( $PSItem ) } } } |