Skip to content

Commit

Permalink
Merge pull request #18 from 123FLO321/beta
Browse files Browse the repository at this point in the history
add support for job parameters
  • Loading branch information
123FLO321 authored Jun 23, 2023
2 parents 39c9c28 + 72081f0 commit 031032a
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 65 deletions.
47 changes: 44 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The plugin can be configured in the [**semantic-release** configuration file](ht

With this example a [JetBrains Space Deployment](https://www.jetbrains.com/help/space/deployments.html) will be published on the `example-target` deployment target .


## Configuration

Make sure to set `targetId` or `JB_SPACE_TARGET_ID` to the deployment target you want to use.
Expand All @@ -60,7 +61,19 @@ All other options are automatically set via their environment variables in a Spa

#### Option Types
- TargetConfiguration: `string | string[] | { [branch: string]: string | string[] }`
- JobConfiguration: `string | string[] | { [branch: string]: string | string[] }`
- JobConfiguration: `JobBranchConfiguration | { [branch: string]: JobBranchConfiguration }`
- JobBranchConfiguration: `string | string[] | { id: string, parameters?: { [name: string]: string } }`

#### Job Parameters

Job parameters can be set via the `parameters` property of a job configuration for all or only specific branches.
The values will be parsed using [Handlebars](https://handlebarsjs.com/) and with the [plugin context](https://semantic-release.gitbook.io/semantic-release/developer-guide/plugin#context) as template context.
Examples:
- `"parameters": { "hello": "world" }` will set the parameter `hello` to `world`
- `"parameters": { "version": "{{nextRelease.version}}" }` will set the parameter `version` to the next release version
- `"parameters": { "channel": "{{#if nextRelease.channel}}{{nextRelease.channel}}{{else}}latest{{/if}}" }` will set the parameter `channel` to the next release channel or `latest` if no channel is set



## Job Example

Expand Down Expand Up @@ -102,7 +115,15 @@ of the new tag will be published on the `example-target` deployment target.
[
"semantic-release-space",
{
"targetId": "example-target"
"targetId": "example-target",
"job": {
"id": "Example",
"parameters": {
"example-param": "example-value",
"release-version": "{{nextRelease.version}}",
"release-channel": "{{#if nextRelease.channel}}{{nextRelease.channel}}{{else}}latest{{/if}}"
}
}
}
],
[
Expand All @@ -124,7 +145,7 @@ of the new tag will be published on the `example-target` deployment target.

### .space.kts
```kotlin
job("Verify") {
job("Release") {
git {
refSpec = "refs/heads/main"
}
Expand All @@ -140,4 +161,24 @@ job("Verify") {
}
}
}

job("Example") {
parameters {
text("release-version")
text("release-channel")
text("example-param")
}

startOn {}

container(image = "alpine:lts") {
shellScript {
content = """
echo {{ release-version }}
echo {{ release-channel }}
echo {{ example-param }}
"""
}
}
}
```
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "semantic-release-space",
"version": "1.3.4",
"version": "1.4.0-beta.4",
"description": "A Semantic Release JetBrains Space plugin",
"author": "Florian Kostenzer (https://github.com/123FLO321)",
"repository": {
Expand Down Expand Up @@ -29,8 +29,9 @@
],
"license": "MIT",
"dependencies": {
"axios": "^0.27.2",
"jetbrains-space-api": "~1.3.0"
"axios": "~0.27.2",
"handlebars": "~4.7.7",
"jetbrains-space-api": "~1.7.0"
},
"devDependencies": {
"@commitlint/cli": "^17.0.3",
Expand Down
18 changes: 18 additions & 0 deletions src/lib/build-job-parameters.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { buildJobParameters } from "./build-job-parameters";
import { getContext } from "./get-context.spec";

describe("build-job-parameters", () => {
it("should correctly build parameters", () => {
const context = getContext();
expect(buildJobParameters({}, context)).toEqual([]);
expect(buildJobParameters({ test: "test" }, context)).toEqual([{ name: "test", value: "test" }]);
expect(buildJobParameters({ test: "test", hello: "world" }, context)).toEqual([
{ name: "test", value: "test" },
{ name: "hello", value: "world" }
]);
expect(buildJobParameters({ version: "{{nextRelease.version}}" }, context)).toEqual([{ name: "version", value: "1.0.0" }]);
expect(buildJobParameters({ channel: "{{#if nextRelease.channel}}{{nextRelease.channel}}{{else}}latest{{/if}}" }, context)).toEqual([
{ name: "channel", value: "test" }
]);
});
});
26 changes: 26 additions & 0 deletions src/lib/build-job-parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Handlebars from "handlebars";
import { JobParameter } from "jetbrains-space-api";

import { PluginContext } from "../types/plugin-context";

/**
* Builds the job parameters and adds the release information.
* @param params The job parameters from the config.
* @param context The plugin context.
*/
export function buildJobParameters(params: { [name: string]: string }, context: PluginContext): JobParameter[] {
const parameters: JobParameter[] = [];
for (const [name, value] of Object.entries(params)) {
parameters.push({ name, value: buildParameter(value, context) });
}
return parameters;
}

/**
* Builds the parameter value template as handlebars template.
* @param value The parameter value template.
* @param context The plugin context.
*/
function buildParameter(value: string, context: PluginContext): string {
return Handlebars.compile(value)(context);
}
5 changes: 5 additions & 0 deletions src/lib/get-config.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PluginConfig } from "../types/plugin-config";

export function getConfig(config: Partial<PluginConfig> = {}): Partial<PluginConfig> {
return config;
}
39 changes: 39 additions & 0 deletions src/lib/get-context.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { PluginContext } from "../types/plugin-context";

export function getContext(env: { [key: string]: string } = {}, branchName = "main"): PluginContext {
return {
env,
commits: [],
branch: {
name: branchName
},
logger: {
await: jest.fn(),
complete: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
fatal: jest.fn(),
fav: jest.fn(),
info: jest.fn(),
log: jest.fn(),
note: jest.fn(),
pause: jest.fn(),
pending: jest.fn(),
star: jest.fn(),
start: jest.fn(),
success: jest.fn(),
wait: jest.fn(),
warn: jest.fn(),
watch: jest.fn()
},
nextRelease: {
type: "major",
name: "test",
channel: "test",
gitHead: "012345",
gitTag: "v1.0.0",
version: "1.0.0",
notes: "Hello World"
}
};
}
10 changes: 7 additions & 3 deletions src/lib/run-jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SpaceApi } from "jetbrains-space-api";

import { PluginConfig } from "../types/plugin-config";
import { PluginContext } from "../types/plugin-context";
import { buildJobParameters } from "./build-job-parameters";

/**
* Starts jobs for the given context and waits for them to finish.
Expand All @@ -21,24 +22,27 @@ export async function runJobs(client: SpaceApi, pluginConfig: PluginConfig, cont
const start = Date.now();
const startedJobs: { executionId: string; name: string }[] = [];
for (const jobId of pluginConfig.currentJobIds) {
const job = allJobs.find((j) => j.name.toLowerCase() === jobId.toLowerCase() || j.id === jobId);
const job = allJobs.find((j) => j.name.toLowerCase() === jobId.id?.toLowerCase() || j.id === jobId.id);
if (!job) {
throw new Error(`Job '${jobId}' not found`);
}
context.logger.info(`Starting job '${job.name}'`);
const startedJob = (
await client.projectsProjectAutomationJobsJobIdStartPost(pluginConfig.projectId, job.id, {
branch: { branchName: pluginConfig.branch }
branch: { branchName: pluginConfig.branch },
parameters: buildJobParameters(jobId.parameters ?? {}, context)
})
).data;
if (!startedJob.executionId) {
throw new Error(startedJob.message ? `Job '${job.name}' failed: ${startedJob.message}` : `Job '${jobId}' failed`);
}
startedJobs.push({ executionId: startedJob.executionId, name: job.name });
}

context.logger.info("Waiting for jobs to complete");
while (Date.now() - start < pluginConfig.jobTimeout * 1000 && startedJobs.length > 0) {
for (const startedJob of startedJobs) {
const jobState = (await client.projectsAutomationGraphExecutionsIdGet(startedJob.executionId)).data;
jobState.status;
if (jobState.status === "FAILED") {
throw new Error(`Job '${startedJob.name}' failed`);
} else if (jobState.status === "TERMINATED") {
Expand Down
77 changes: 36 additions & 41 deletions src/lib/validate-plugin-config.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PluginConfig } from "../types/plugin-config";
import { PluginContext } from "../types/plugin-context";
import { getConfig } from "./get-config.spec";
import { getContext } from "./get-context.spec";
import { setCommitInfo, verifyApiToken, verifyApiUrl, verifyJobId, verifyProjectId, verifyTargetId } from "./validate-plugin-config";

describe("validate-plugin-config", () => {
Expand Down Expand Up @@ -126,42 +126,70 @@ describe("validate-plugin-config", () => {
const config = getConfig({ job: "example" });
const context = getContext();
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual(["example"]);
expect(config.currentJobIds).toEqual([{ id: "example" }]);
});

it("should set single job id from environment", () => {
const config = getConfig();
const context = getContext({ JB_SPACE_JOB_ID: "example" });
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual(["example"]);
expect(config.currentJobIds).toEqual([{ id: "example" }]);
});

it("should set multiple job ids from config", () => {
const config = getConfig({ job: ["example", "other"] });
const context = getContext();
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual(["example", "other"]);
expect(config.currentJobIds).toEqual([{ id: "example" }, { id: "other" }]);
});

it("should set multiple job ids from environment", () => {
const config = getConfig();
const context = getContext({ JB_SPACE_JOB_ID: "example,other" });
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual(["example", "other"]);
expect(config.currentJobIds).toEqual([{ id: "example" }, { id: "other" }]);
});

it("should set single job id from branch config", () => {
const config = getConfig({ branch: "main", job: { main: "example" } });
const context = getContext();
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual(["example"]);
expect(config.currentJobIds).toEqual([{ id: "example" }]);
});

it("should set multiple job ids from branch config", () => {
const config = getConfig({ branch: "main", job: { main: ["example", "other"] } });
const context = getContext();
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual(["example", "other"]);
expect(config.currentJobIds).toEqual([{ id: "example" }, { id: "other" }]);
});

it("should set single job with parameters from config", () => {
const config = getConfig({
branch: "main",
job: { id: "example", parameters: { example1: "hello", example2: "world" } }
});
const context = getContext();
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual([{ id: "example", parameters: { example1: "hello", example2: "world" } }]);
});

it("should set multiple jobs with parameters from branch config", () => {
const config = getConfig({
branch: "main",
job: {
main: [
{ id: "example", parameters: { example1: "hello", example2: "world" } },
{ id: "other", parameters: {} }
]
}
});
const context = getContext();
expect(() => verifyJobId(config, context)).not.toThrow();
expect(config.currentJobIds).toEqual([
{ id: "example", parameters: { example1: "hello", example2: "world" } },
{ id: "other", parameters: {} }
]);
});

it("should set the commit info from environment", () => {
Expand All @@ -172,36 +200,3 @@ describe("validate-plugin-config", () => {
expect(config.repositoryName).toEqual("EXAMPLE");
});
});

function getContext(env: { [key: string]: string } = {}, branchName = "main"): PluginContext {
return {
env,
commits: [],
branch: {
name: branchName
},
logger: {
await: jest.fn(),
complete: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
fatal: jest.fn(),
fav: jest.fn(),
info: jest.fn(),
log: jest.fn(),
note: jest.fn(),
pause: jest.fn(),
pending: jest.fn(),
star: jest.fn(),
start: jest.fn(),
success: jest.fn(),
wait: jest.fn(),
warn: jest.fn(),
watch: jest.fn()
}
};
}

function getConfig(config: Partial<PluginConfig> = {}): Partial<PluginConfig> {
return config;
}
Loading

0 comments on commit 031032a

Please sign in to comment.