UNPKG

@halospv3/hce.shared-config

Version:

Automate commit message quality, changelogs, and CI/CD releases. Exports a semantic-release shareable configuration deserialized from this package's '.releaserc.yml'. Shared resources for .NET projects are also distributed with this package.

185 lines (169 loc) 6.91 kB
import { ok } from 'node:assert/strict'; import { getEnvVarValue } from '../envUtils.js'; import { MSBuildProject, MSBuildProjectPreDefinedProperties } from './MSBuildProject.js'; import { getGithubNugetRegistryPair, nugetGitHubUrlBase } from './dotnetGHPR.js'; import { getGitlabNugetRegistryPair } from './dotnetGLPR.js'; function formatDotnetPublish(projectsToPublish: string[], publishProperties: string[]): string { /* Fun Fact: You can define a property and get the evaluated value in the same command! ```pwsh dotnet msbuild .\src\HXE.csproj -property:RuntimeIdentifiers="""place;holder""" -getProperty:RuntimeIdentifiers place;holder ``` enclosing with """ is required in pwsh to prevent the semicolon from breaking the string. */ if (!(Array.isArray(projectsToPublish) && projectsToPublish.length > 0)) throw new Error(`Type of projectsToPublish (${typeof projectsToPublish}) is not allowed. Expected a string[] where length > 0.`); // each may have TargetFramework OR TargetFrameworks (plural) const evaluatedProjects: MSBuildProject[] = projectsToPublish.map( (proj) => new MSBuildProject(proj, publishProperties), ); // args appended to "dotnet publish", joined by space return evaluatedProjects.flatMap(proj => { const args: string[] = [proj.Properties.FullPath]; function appendCustomProperties(publishProperties: string[]) { // convert to dictionary and filter for user-defined properties. const dictionary = Object.entries(proj.Properties).filter( (p) => !publishProperties.includes(p[0]), ); if (dictionary.length > 0) { /* format remaining properties as "-p:Property=Value" and append to args */ args.push( ...dictionary.map((keyValuePair) => `-p:${keyValuePair[0]}=${keyValuePair[1]}`), ); } } appendCustomProperties(publishProperties); const cmdPermutations: string[][] = []; // forEach, run dotnet [...args,...v] function formatFrameworksAndRuntimes() { const RIDs: string[] = proj.Properties.RuntimeIdentifiers.length > 0 ? proj.Properties.RuntimeIdentifiers.split(';') : []; const TFMs: string[] = proj.Properties.TargetFrameworks.length > 0 ? proj.Properties.TargetFrameworks.split(';') : []; if (RIDs.length > 0) { if (TFMs.length > 0) { for (const RID of RIDs) { for (const TFM of TFMs) { cmdPermutations.push(['--runtime', RID, '--framework', TFM]); } } } else { // assume singular TFM. No need to specify it. for (const RID of RIDs) { cmdPermutations.push(['--runtime', RID]); } } } else if (TFMs.length > 0) { for (const TFM of TFMs) { cmdPermutations.push(['--framework', TFM]); } } } formatFrameworksAndRuntimes(); return cmdPermutations.length > 0 ? cmdPermutations.map((permArgs) => [...args, ...permArgs]) // string[][] : [args]; // string[][] }).map((args) => `dotnet publish ${args.join(' ')}`).join(' && '); } function formatDotnetPack(projectsToPackAndPush: string[] | false): string { return projectsToPackAndPush === false ? "" : projectsToPackAndPush .map(v => `dotnet pack ${v}`) .join(' && '); } function formatDotnetNugetSign(dotnetNugetSignArgs: string[]): string { switch (dotnetNugetSignArgs.length) { case 0: return ''; default: return `dotnet nuget sign ${dotnetNugetSignArgs.join(' ')}`; // default: { // throw new Error("") // // this needs a rework. // const packagePaths: string[] = []; // dotnetNugetSignArgs.forEach((dotnetNugetSignArg, i) => { // // if current arg doesn't start with '-' and (current arg is first -OR- previous arg also does not start with '-')... // if (!dotnetNugetSignArg.startsWith("-") && (i === 0 || (i > 0 && !dotnetNugetSignArgs[i - 1].startsWith("-")))) { // // ...then it's probably a package path. // packagePaths.push(dotnetNugetSignArg); // } // }); // if (packagePaths.length === 0) // return `dotnet nuget sign ${dotnetNugetSignArgs.join(" ")}` // else return // } } } /** * Build a prepareCmd string from .NET project paths and `dotnet nuget sign` arguments. * * todo: parse Solution files to publish all projects with default Publish parameters (as evaluated by MSBuild). If multi-targeting frameworks and/or runtime, evaluate those properties for Publish permutation matrix. * todo: cleanup, docs * @export * @param {string[]} projectsToPublish * @param {string[]|false} projectsToPackAndPush Relative and/or full file paths of projects to pass to `dotnet pack`. By default, these will be output to `./publish/`. * @param {string[]} dotnetNugetSignArgs Arguments appended to `dotnet nuget sign`. You can also append '&&' if you want to start a new command or if you want to sign different sets of packages with different keys. */ export function configurePrepareCmd( projectsToPublish: string[], projectsToPackAndPush: string[] | false, dotnetNugetSignArgs: string[] = ['./publish'], ) { // These are later evaluated with MSBuild, but are passed via --framework and --runtime arguments instead of -p:TargetFramework const publishProperties = MSBuildProjectPreDefinedProperties; return [ formatDotnetPublish(projectsToPublish, publishProperties), formatDotnetPack(projectsToPackAndPush), formatDotnetNugetSign(dotnetNugetSignArgs) ].join(' && '); } export interface NuGetRegistryInfo { tokenEnvVar: string; url: string; user?: string | undefined; } export const nugetDefault: NuGetRegistryInfo = { tokenEnvVar: 'NUGET_TOKEN', url: 'https://api.nuget.org/v3/index.json', }; /** * todo - * @param nupkgDir * @param registries * @param pushToGitHub * @returns */ export function configureDotnetNugetPush( nupkgDir = './publish', registries: NuGetRegistryInfo[] = [nugetDefault], pushToGitHub = true, ): string { if (registries.some((registry) => registry.url.trim() === '')) throw new Error('The URL for one of the provided NuGet registries was empty or whitespace.'); // if user did not specify a GitHub NuGet Registry, try determine default values and add the Source. if (pushToGitHub && !registries.some((reg) => reg.url.startsWith(nugetGitHubUrlBase))) { const ghPair: NuGetRegistryInfo | undefined = getGithubNugetRegistryPair(); if (ghPair) { registries.push(ghPair); } } if (!registries.some((reg) => reg.url.startsWith(nugetGitHubUrlBase))) { const glPair = getGitlabNugetRegistryPair(); if (glPair) { registries.push(glPair); } } return registries .map( (registry) => { const tokenValue = getEnvVarValue(registry.tokenEnvVar); ok(getEnvVarValue('SKIP_TOKEN') === 'true' || tokenValue, `The environment variable ${registry.tokenEnvVar} is undefined!`); return `dotnet nuget push ${nupkgDir} --source ${registry.url} --token ${tokenValue ?? '**placeholder**'}` } ) .join(' && '); }