Skip to content

Commit

Permalink
feat: allow to build multiple NuGet packages in one Repo
Browse files Browse the repository at this point in the history
  • Loading branch information
Kampfmoehre committed Mar 15, 2022
1 parent e90f173 commit 39c5fa3
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Expand Up @@ -52,7 +52,7 @@ jobs:
run: npx jest --coverage
release:
name: Semantic Release
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta')
runs-on: ubuntu-latest
needs:
- lint
Expand Down
42 changes: 33 additions & 9 deletions README.md
Expand Up @@ -60,15 +60,15 @@ The NuGet server authentication is **required** and can be set via [environment

### Options

| Options | Description | Default |
| ------------------- | --------------------------------------------------------------- | ----------- |
| `nugetServer` | The URL of the NuGet server to push the package to. | `nuget.org` |
| `projectPath` | The relative path to the project file to pack. | |
| `includeSymbols` | If true Debug symbols will be included in the package. | `false` |
| `includeSource` | If true source code will be included in the package. | `false` |
| `dotnet` | The path to the dotnet executable if not in PATH. | `dotnet` |
| `publishToGitLab` | If true, package will also be published to the GitLab registry. | `false` |
| `usePackageVersion` | If true, version is directly set via dotnet pack argument. | `false` |
| Options | Description | Default |
| ------------------- | ------------------------------------------------------------------------------------------------ | ----------- |
| `nugetServer` | The URL of the NuGet server to push the package to. | `nuget.org` |
| `projectPath` | The relative path to the project file to pack. Can also be an array including multiple projects. | |
| `includeSymbols` | If true Debug symbols will be included in the package. | `false` |
| `includeSource` | If true source code will be included in the package. | `false` |
| `dotnet` | The path to the dotnet executable if not in PATH. | `dotnet` |
| `publishToGitLab` | If true, package will also be published to the GitLab registry. | `false` |
| `usePackageVersion` | If true, version is directly set via dotnet pack argument. | `false` |

**Note**: If `usePackageVersion` is set the version from Semantic Release is given directly to the `dotnet pack` command via the `-p:PackageVersion=<version>` argument. In this case any existing version in project files are ignored.

Expand Down Expand Up @@ -152,3 +152,27 @@ No configure Semantic Release and use the update file plugin to update values in
]
}
```

### Multiple packages

You can build multiple NuGet packages from one repositories. To do this, specify the relative paths to the projects. Instead of

```json
{
"projectPath": "src/DroidSolutions.SemanticVersion/DroidSolutions.SemanticVersion.csproj"
}
```

you could also use something like this:

```json
{
"projectPath": [
"src/DroidSolutions.Oss.JobService/DroidSolutions.Oss.JobService.csproj",
"src/DroidSolutions.Oss.JobService.EFCore/DroidSolutions.Oss.JobService.EFCore.csproj",
"src/DroidSolutions.Oss.JobService.Postgres/DroidSolutions.Oss.JobService.Postgres.csproj"
]
}
```

All NuGet packages will be in the `out` directory in project root.
6 changes: 5 additions & 1 deletion package.json
Expand Up @@ -73,7 +73,11 @@
},
"release": {
"branches": [
"main"
"main",
{
"name": "beta",
"prerelease": true
}
],
"plugins": [
"@semantic-release/commit-analyzer",
Expand Down
2 changes: 1 addition & 1 deletion src/UserConfig.ts
@@ -1,7 +1,7 @@
/** The external configuration the user can made via Semantic Release. */
export interface UserConfig {
/** The relative path to the project to pack. */
projectPath: string;
projectPath: string | string[];
/** If true Debug symbols will be included in the package. */
includeSymbols?: boolean;
/** If true source coe will be included in the package. */
Expand Down
31 changes: 17 additions & 14 deletions src/prepare.ts
Expand Up @@ -5,25 +5,28 @@ import { UserConfig } from "./UserConfig";

export const prepare = async (pluginConfig: Config & UserConfig, context: Context): Promise<void> => {
const dotnet = pluginConfig.dotnet || "dotnet";
const project = resolve(pluginConfig.projectPath);

try {
const cliArgs = ["pack", project, "-c", "Release"];
if (pluginConfig.includeSource === true) {
cliArgs.push("--include-source");
}
if (pluginConfig.includeSymbols === true) {
cliArgs.push("--include-symbols", "-p:SymbolPackageFormat=snupkg");
}
for (const projectPath of pluginConfig.projectPath as string[]) {
const project = resolve(projectPath);

if (pluginConfig.usePackageVersion === true) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
cliArgs.push(`-p:PackageVersion=${context.nextRelease!.version}`);
}
const cliArgs = ["pack", project, "-c", "Release", "-o", "out"];
if (pluginConfig.includeSource === true) {
cliArgs.push("--include-source");
}
if (pluginConfig.includeSymbols === true) {
cliArgs.push("--include-symbols", "-p:SymbolPackageFormat=snupkg");
}

context.logger.log(`running command "${dotnet} ${cliArgs.join(" ")}" ...`);
if (pluginConfig.usePackageVersion === true) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
cliArgs.push(`-p:PackageVersion=${context.nextRelease!.version}`);
}

await execa(dotnet, cliArgs, { stdio: "inherit" });
context.logger.log(`running command "${dotnet} ${cliArgs.join(" ")}" ...`);

await execa(dotnet, cliArgs, { stdio: "inherit" });
}
} catch (err) {
context.logger.error(`${dotnet} pack failed: ${(err as Error).message}`);
throw err;
Expand Down
8 changes: 4 additions & 4 deletions src/publish.ts
@@ -1,19 +1,19 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import execa from "execa";
import { resolve, dirname } from "path";
import { resolve } from "path";
import { Config, Context } from "semantic-release";
import { UserConfig } from "./UserConfig";

export const publish = async (pluginConfig: Config & UserConfig, context: Context): Promise<void> => {
const dotnet = pluginConfig.dotnet || "dotnet";
const registry = pluginConfig.nugetServer ?? "https://api.nuget.org/v3/index.json";
const project = resolve(dirname(resolve(pluginConfig.projectPath)), "bin", "Release");
const packagePath = resolve("out");
const baseCliArgs: string[] = ["nuget", "push"];

try {
const cliArgs = [...baseCliArgs, "-s", registry, "-k", process.env.NUGET_TOKEN!];

cliArgs.push(`${project}/*.nupkg`);
cliArgs.push(`${packagePath}/*.nupkg`);

context.logger.log(`running command "${dotnet} ${cliArgs.join(" ")}" ...`);

Expand Down Expand Up @@ -48,7 +48,7 @@ export const publish = async (pluginConfig: Config & UserConfig, context: Contex
{ stdio: "inherit" },
);

const cliArgs = [...baseCliArgs, "--source", "gitlab", `${project}/*.nupkg`];
const cliArgs = [...baseCliArgs, "--source", "gitlab", `${packagePath}/*.nupkg`];

context.logger.log(`running command "${dotnet} ${cliArgs.join(" ")}" ...`);

Expand Down
24 changes: 17 additions & 7 deletions src/verify.ts
Expand Up @@ -20,14 +20,24 @@ export const verify = async (pluginConfig: Config & UserConfig, _: Context): Pro
}
}

const project = resolve(pluginConfig.projectPath ?? "");
try {
const stats = await promises.stat(project);
if (!stats.isFile()) {
throw new Error(`The given project path ${project} is not a file.`);
const projects: string[] = Array.isArray(pluginConfig.projectPath)
? pluginConfig.projectPath
: [pluginConfig.projectPath];

if (projects.length < 1) {
errors.push(new Error("No project files given"));
}

for (const project of projects) {
const projectPath = resolve(project ?? "");
try {
const stats = await promises.stat(projectPath);
if (!stats.isFile()) {
throw new Error(`The given project path ${projectPath} is not a file.`);
}
} catch (err) {
errors.push(new Error(`The given project path ${projectPath} could not be found.`));
}
} catch (err) {
errors.push(new Error(`The given project path ${project} could not be found.`));
}

const dotnet = pluginConfig.dotnet || "dotnet";
Expand Down
10 changes: 6 additions & 4 deletions test/prepare.test.ts
Expand Up @@ -31,7 +31,7 @@ describe("prepare", () => {
expect(execaMock).toHaveBeenCalledTimes(1);
expect(execaMock.mock.calls[0]).toEqual([
"a",
expect.arrayContaining(["pack", resolve("b"), "-c", "Release"]),
expect.arrayContaining(["pack", resolve("b"), "-c", "Release", "-o", "out"]),
{ stdio: "inherit" },
]);
});
Expand All @@ -45,7 +45,7 @@ describe("prepare", () => {
expect(execaMock).toHaveBeenCalledTimes(1);
expect(execaMock.mock.calls[0]).toEqual([
"dotnet",
expect.arrayContaining(["pack", resolve("b"), "-c", "Release"]),
expect.arrayContaining(["pack", resolve("b"), "-c", "Release", "-o", "out"]),
{ stdio: "inherit" },
]);
});
Expand All @@ -59,7 +59,7 @@ describe("prepare", () => {
expect(execaMock).toHaveBeenCalledTimes(1);
expect(execaMock.mock.calls[0]).toEqual([
"dotnet",
expect.arrayContaining(["pack", resolve("b"), "-c", "Release", "--include-source"]),
expect.arrayContaining(["pack", resolve("b"), "-c", "Release", "-o", "out", "--include-source"]),
{ stdio: "inherit" },
]);
});
Expand All @@ -78,6 +78,8 @@ describe("prepare", () => {
resolve("b"),
"-c",
"Release",
"-o",
"out",
"--include-symbols",
"-p:SymbolPackageFormat=snupkg",
]),
Expand Down Expand Up @@ -105,7 +107,7 @@ describe("prepare", () => {
expect(execaMock).toHaveBeenCalledTimes(1);
expect(execaMock.mock.calls[0]).toEqual([
"dotnet",
expect.arrayContaining(["pack", resolve("b"), "-c", "Release", "-p:PackageVersion=1.0.0"]),
expect.arrayContaining(["pack", resolve("b"), "-c", "Release", "-o", "out", "-p:PackageVersion=1.0.0"]),
{ stdio: "inherit" },
]);
});
Expand Down
6 changes: 3 additions & 3 deletions test/publish.test.ts
Expand Up @@ -44,7 +44,7 @@ describe("publish", () => {
"https://api.nuget.org/v3/index.json",
"-k",
"104E4",
expect.stringMatching(/^[\w\\/-]+\/src\/MyProject\/bin\/Release\/\*.nupkg$/),
expect.stringMatching(/^[\w\\/-]+\/out\/\*.nupkg$/),
],
{ stdio: "inherit" },
]);
Expand All @@ -69,7 +69,7 @@ describe("publish", () => {
"https://gitlab.com/mygroup/myproject",
"-k",
"104E4",
expect.stringMatching(/^[\w\\/-]+\/bin\/Release\/\*.nupkg$/),
expect.stringMatching(/^[\w\\/-]+\/out\/\*.nupkg$/),
],
{ stdio: "inherit" },
]);
Expand All @@ -94,7 +94,7 @@ describe("publish", () => {
"https://api.nuget.org/v3/index.json",
"-k",
"104E4",
expect.stringMatching(/^[\w\\/-]+\/MyProject\/bin\/Release\/\*.nupkg$/),
expect.stringMatching(/^[\w\\/-]+\/out\/\*.nupkg$/),
],
{ stdio: "inherit" },
]);
Expand Down
5 changes: 4 additions & 1 deletion test/verify.test.ts
Expand Up @@ -90,7 +90,10 @@ describe("verify", () => {

let actualErr: AggregateError | undefined;
try {
await verify({ projectPath: "test/fixture/some-missing.csproj" } as UserConfig, context);
await verify(
{ projectPath: ["test/fixture/some-missing.csproj", "test/fixture/some.csproj"] } as UserConfig,
context,
);
} catch (err) {
actualErr = err as AggregateError;
}
Expand Down

0 comments on commit 39c5fa3

Please sign in to comment.