Skip to content

Commit

Permalink
feat: allow to skip publish to official NuGet
Browse files Browse the repository at this point in the history
adds a flag that will skip publishing to NuGet server and only publish to (private) GitLab instance
Contributes to #203
  • Loading branch information
Kampfmoehre committed Jul 13, 2022
1 parent 3a96d8a commit 53eb0e7
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 26 deletions.
21 changes: 12 additions & 9 deletions README.md
Expand Up @@ -60,20 +60,23 @@ 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. 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` |
| 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` |
| `skipPublishToNuget` | If true, the NuGet package will not be published to the `nugetServer`. You can use this together with `publishToGitLab` to **only** publish your package to the GitLab registry. | `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.

**Note**: If `publishToGitLab` is set the environment variables for `CI_SERVER_URL`, `CI_PROJECT_ID` and `CI_JOB_TOKEN` must be set. If you are running in GitLab CI this is automatically set by GitLab for you.

**Note**: If `skipPublishToNuget` is set the package will not be published to the nuget server even if you specified an alternative via `nugetServer`. This only makes sense in combination with `publishToGitLab`.

**Note**: When you add the [NPM plugin](https://raw.githubusercontent.com/semantic-release/npm) to update your `package.json` you should set `npmPublish` to `false` to prevent Semantic Release from trying to publish an NPM package.

## Versioning
Expand Down
7 changes: 6 additions & 1 deletion src/UserConfig.ts
Expand Up @@ -6,12 +6,17 @@ export interface UserConfig {
includeSymbols?: boolean;
/** If true source coe will be included in the package. */
includeSource?: boolean;
/** The name of the registry to push to. */
/**
* The name of the registry to push to, if empty official NuGet server will be used, unless skipPublishToNuget is set
* to true.
*/
nugetServer?: string;
/** The path to the dotnet executable if not in PATH. */
dotnet?: string;
/** If true, package will also be published to the GitLab registry. */
publishToGitLab?: boolean;
/** If true, package version is overriden via PackageVersion argument. */
usePackageVersion?: boolean;
/** If true, package will not be published to the official NuGet server. */
skipPublishToNuget?: boolean;
}
36 changes: 20 additions & 16 deletions src/publish.ts
Expand Up @@ -13,28 +13,32 @@ export const publish = async (pluginConfig: Config & UserConfig, context: Contex
const baseCliArgs: string[] = ["nuget", "push"];
const token: string = process.env.NUGET_TOKEN!;

try {
const cliArgs = [...baseCliArgs, "-s", registry, "-k", token];
if (pluginConfig.skipPublishToNuget) {
context.logger.log("Skipping publish to NuGet server because skipPublishToNuget is set to true.");
} else {
try {
const cliArgs = [...baseCliArgs, "-s", registry, "-k", token];

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

const argStrings = cliArgs.map((value) => (value === token ? "[redacted]" : value)).join(" ");
context.logger.log(`running command "${dotnet} ${argStrings}" ...`);
const argStrings = cliArgs.map((value) => (value === token ? "[redacted]" : value)).join(" ");
context.logger.log(`running command "${dotnet} ${argStrings}" ...`);

await execa(dotnet, cliArgs, { stdio: "inherit" });
} catch (error) {
context.logger.error(`${dotnet} push failed: ${(error as Error).message}`);
await execa(dotnet, cliArgs, { stdio: "inherit" });
} catch (error) {
context.logger.error(`${dotnet} push failed: ${(error as Error).message}`);

if (typeof error === "object" && (error as ExecaReturnBase<void>).exitCode) {
const err = error as ExecaReturnBase<void>;
let description = err.command;
if (typeof error === "object" && (error as ExecaReturnBase<void>).exitCode) {
const err = error as ExecaReturnBase<void>;
let description = err.command;

// hide token from SR output
if (err.command && err.command.includes(token)) {
description = description.replace(token, "[redacted]");
}
// hide token from SR output
if (err.command && err.command.includes(token)) {
description = description.replace(token, "[redacted]");
}

throw new SemanticReleaseError(`publish to registry ${registry} failed`, err.exitCode, description);
throw new SemanticReleaseError(`publish to registry ${registry} failed`, err.exitCode, description);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/verify.ts
Expand Up @@ -18,6 +18,12 @@ export const verify = async (pluginConfig: Config & UserConfig, _: Context): Pro
errors.push(new Error(`GitLab environment variable ${envVar} is not set.`));
}
}
} else if (pluginConfig.skipPublishToNuget) {
errors.push(
new Error(
"skipPublishToNuget is set to true, but publishToGitLab is not set to true so the package will not be published anywhere.",
),
);
}

pluginConfig.projectPath = Array.isArray(pluginConfig.projectPath)
Expand Down
52 changes: 52 additions & 0 deletions test/publish.test.ts
Expand Up @@ -124,6 +124,58 @@ describe("publish", () => {
expect(execaMock).toHaveBeenCalledTimes(1);
});

it("should not publish to nugetServer when skipPublishToNuget is true", async () => {
await publish(
{
projectPath: "src/MyProject/MyProject.csproj",
skipPublishToNuget: true,
publishToGitLab: false,
},
context,
);

expect(execaMock).not.toHaveBeenCalled();
});

it("should publish to nugetServer when skipPublishToNuget is false", async () => {
execaMock.mockImplementationOnce(() => {
return {
command: "dotnet nuget push -s https://api.nuget.org/v3/index.json -k 104E4 out/*.nupkg",
exitCode: 0,
} as ExecaReturnBase<string>;
});

await publish(
{
projectPath: "src/MyProject/MyProject.csproj",
skipPublishToNuget: false,
publishToGitLab: false,
},
context,
);

expect(execaMock).toHaveBeenCalledTimes(1);
});

it("should publish to nugetServer when skipPublishToNuget is not set", async () => {
execaMock.mockImplementationOnce(() => {
return {
command: "dotnet nuget push -s https://api.nuget.org/v3/index.json -k 104E4 out/*.nupkg",
exitCode: 0,
} as ExecaReturnBase<string>;
});

await publish(
{
projectPath: "src/MyProject/MyProject.csproj",
publishToGitLab: false,
},
context,
);

expect(execaMock).toHaveBeenCalledTimes(1);
});

it("should react nuget token from command output", async () => {
execaMock.mockImplementationOnce(() => {
return {
Expand Down
19 changes: 19 additions & 0 deletions test/verify.test.ts
Expand Up @@ -85,6 +85,25 @@ describe("verify", () => {
expect(actualErr?.errors[0].message).toBe("GitLab environment variable CI_JOB_TOKEN is not set.");
});

it("should report an error when publishToGitlab is false and skipPublishToNuget is true", async () => {
process.env.NUGET_TOKEN = "104E2";

let actualErr: AggregateError | undefined;
try {
await verify(
{ publishToGitLab: false, skipPublishToNuget: true, projectPath: "test/fixture/some.csproj" } as UserConfig,
context,
);
} catch (err) {
actualErr = err as AggregateError;
}

expect(actualErr).toBeDefined();
expect(actualErr?.errors[0].message).toBe(
"skipPublishToNuget is set to true, but publishToGitLab is not set to true so the package will not be published anywhere.",
);
});

it("should report an error if path to non existing project file is given", async () => {
process.env.NUGET_TOKEN = "104E2";

Expand Down

0 comments on commit 53eb0e7

Please sign in to comment.