versionary 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -100,6 +100,7 @@ For a quick trial, use:
100
100
  - optional monorepo planning with `monorepo-mode` and `packages`:
101
101
  - `independent` computes package bumps per path
102
102
  - `fixed` computes one shared bump across configured package paths
103
+ - per-package `package-name` can override release identity (labels + tag base)
103
104
 
104
105
  Rust strategy examples:
105
106
 
@@ -136,6 +137,26 @@ Current rust non-goals/limits:
136
137
  - does not add missing `version = ...` fields to dependency inline tables
137
138
  - does not perform Cargo publish/release to crates.io
138
139
 
140
+ ### Monorepo release names and tag naming
141
+
142
+ For independent monorepo targets, Versionary derives release tags as:
143
+
144
+ - root package (`"."`): `v<version>`
145
+ - non-root package: `<release-name>-v<version>`
146
+
147
+ `release-name` precedence is:
148
+
149
+ 1. `packages.<path>.package-name` (explicit override)
150
+ 2. strategy-native package name from version file:
151
+ - Node: `package.json` `name`
152
+ - Rust: `Cargo.toml` `[package].name`
153
+ - R: `DESCRIPTION` `Package:`
154
+ 3. package path fallback
155
+
156
+ When multiple packages resolve to the same `<release-name>` and version, the run
157
+ fails fast with a duplicate-tag error and suggests setting unique
158
+ `package-name` values.
159
+
139
160
  ## Commit parsing and release analysis
140
161
 
141
162
  Release planning is based on Conventional Commit parsing semantics:
@@ -231,7 +252,7 @@ steps:
231
252
  - id: versionary
232
253
  uses: jolars/versionary@v1
233
254
  with:
234
- github-token: ${{ secrets.RELEASE_TOKEN }}
255
+ token: ${{ secrets.RELEASE_TOKEN }}
235
256
  ```
236
257
 
237
258
  ```yaml
@@ -247,11 +268,16 @@ steps:
247
268
  - id: versionary
248
269
  uses: jolars/versionary@v1
249
270
  with:
250
- github-token: ${{ secrets.RELEASE_TOKEN }}
271
+ token: ${{ secrets.RELEASE_TOKEN }}
251
272
  - if: ${{ steps.versionary.outputs.release_created == 'true' }}
252
273
  run: echo "Released ${{ steps.versionary.outputs.tag_name }}"
253
274
  ```
254
275
 
276
+ `token` is used for both GitHub API calls and git push authentication in
277
+ the composite action. This means release-branch force-pushes are attributed to
278
+ that token and can trigger downstream workflows when using a PAT/App token.
279
+ (`github-token` remains as a deprecated alias for backward compatibility.)
280
+
255
281
  Action outputs:
256
282
 
257
283
  - `action`: `noop`, `pr-prepared`, `release-published`, `release-skipped`
@@ -10,7 +10,9 @@ exports.openOrUpdateSimpleReviewRequest = openOrUpdateSimpleReviewRequest;
10
10
  exports.pushReleaseBranch = pushReleaseBranch;
11
11
  exports.isReleaseCommitMessage = isReleaseCommitMessage;
12
12
  const node_child_process_1 = require("node:child_process");
13
+ const node_fs_1 = __importDefault(require("node:fs"));
13
14
  const node_path_1 = __importDefault(require("node:path"));
15
+ const toml_1 = __importDefault(require("@iarna/toml"));
14
16
  const load_config_js_1 = require("../../config/load-config.js");
15
17
  const changelog_js_1 = require("../../domain/release/changelog.js");
16
18
  const plan_js_1 = require("../../domain/release/plan.js");
@@ -68,6 +70,101 @@ function ensureCleanWorktree(cwd, logger) {
68
70
  logger?.warn(`Ignoring safe tracked changes before versionary pr:\n${ignored.join("\n")}`);
69
71
  }
70
72
  }
73
+ function normalizeReleaseNameForTag(releaseName) {
74
+ return releaseName
75
+ .trim()
76
+ .replace(/^@/u, "")
77
+ .replaceAll("/", "-")
78
+ .replace(/\s+/gu, "-");
79
+ }
80
+ function readNodePackageName(versionPath) {
81
+ const raw = JSON.parse(node_fs_1.default.readFileSync(versionPath, "utf8"));
82
+ const name = raw.name;
83
+ if (typeof name !== "string" || name.trim().length === 0) {
84
+ return null;
85
+ }
86
+ return name.trim();
87
+ }
88
+ function readRustPackageName(versionPath) {
89
+ const parsed = toml_1.default.parse(node_fs_1.default.readFileSync(versionPath, "utf8"));
90
+ const name = parsed.package?.name;
91
+ if (typeof name !== "string" || name.trim().length === 0) {
92
+ return null;
93
+ }
94
+ return name.trim();
95
+ }
96
+ function readRPackageName(versionPath) {
97
+ const content = node_fs_1.default.readFileSync(versionPath, "utf8");
98
+ const match = content.match(/^Package:\s*(.+)\s*$/mu);
99
+ if (!match?.[1]) {
100
+ return null;
101
+ }
102
+ const name = match[1].trim();
103
+ return name.length > 0 ? name : null;
104
+ }
105
+ function resolveReleaseName(cwd, packagePath, packageConfig, strategyName, versionFile) {
106
+ const configuredName = packageConfig["package-name"]?.trim();
107
+ if (configuredName) {
108
+ return configuredName;
109
+ }
110
+ const versionPath = node_path_1.default.join(cwd, versionFile);
111
+ if (strategyName === "node") {
112
+ return readNodePackageName(versionPath) ?? packagePath;
113
+ }
114
+ if (strategyName === "rust") {
115
+ return readRustPackageName(versionPath) ?? packagePath;
116
+ }
117
+ if (strategyName === "r") {
118
+ return readRPackageName(versionPath) ?? packagePath;
119
+ }
120
+ return packagePath;
121
+ }
122
+ function buildReleaseTargets(cwd, plan, loadedConfig) {
123
+ const releaseTargets = plan.packages
124
+ ? plan.packages
125
+ .filter((pkg) => pkg.nextVersion)
126
+ .map((pkg) => {
127
+ if (pkg.path === ".") {
128
+ return {
129
+ path: pkg.path,
130
+ version: pkg.nextVersion ?? "",
131
+ tag: `v${pkg.nextVersion ?? ""}`,
132
+ };
133
+ }
134
+ const packageConfig = loadedConfig.packages?.[pkg.path] ?? {};
135
+ const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loadedConfig, pkg.path, packageConfig);
136
+ const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy.name, packageContext.versionFile);
137
+ const tagPrefix = normalizeReleaseNameForTag(releaseName);
138
+ return {
139
+ path: pkg.path,
140
+ version: pkg.nextVersion ?? "",
141
+ tag: `${tagPrefix}-v${pkg.nextVersion ?? ""}`,
142
+ };
143
+ })
144
+ : [
145
+ {
146
+ path: ".",
147
+ version: plan.nextVersion ?? "",
148
+ tag: `v${plan.nextVersion ?? ""}`,
149
+ },
150
+ ];
151
+ const seenTags = new Map();
152
+ for (const target of releaseTargets) {
153
+ const existingPath = seenTags.get(target.tag);
154
+ if (existingPath) {
155
+ throw new Error(`Duplicate release tag "${target.tag}" for packages "${existingPath}" and "${target.path}". Configure unique "package-name" values.`);
156
+ }
157
+ seenTags.set(target.tag, target.path);
158
+ }
159
+ return releaseTargets;
160
+ }
161
+ function formatReleaseCommitTitle(releaseTargets) {
162
+ if (releaseTargets.length === 0) {
163
+ return "chore(release): v0.0.0";
164
+ }
165
+ const tags = releaseTargets.map((target) => target.tag);
166
+ return `chore(release): ${tags.join(", ")}`;
167
+ }
71
168
  function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
72
169
  const plan = (0, plan_js_1.createSimplePlan)(cwd);
73
170
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
@@ -100,8 +197,9 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
100
197
  const updatedArtifactFiles = (0, artifact_rules_js_1.applyConfiguredArtifactRules)(cwd, loaded.config, plan);
101
198
  const section = (0, changelog_js_1.renderSimpleChangelog)(plan);
102
199
  (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section);
200
+ const releaseTargets = buildReleaseTargets(cwd, plan, loaded.config);
103
201
  const branch = plan.releaseBranchPrefix;
104
- const title = `chore(release): v${plan.nextVersion}`;
202
+ const title = formatReleaseCommitTitle(releaseTargets);
105
203
  (0, node_child_process_1.execFileSync)("git", ["checkout", "-B", branch], {
106
204
  cwd,
107
205
  stdio: ["ignore", "pipe", "ignore"],
@@ -121,23 +219,6 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
121
219
  cwd,
122
220
  stdio: ["ignore", "pipe", "ignore"],
123
221
  });
124
- const releaseTargets = plan.packages
125
- ? plan.packages
126
- .filter((pkg) => pkg.nextVersion)
127
- .map((pkg) => ({
128
- path: pkg.path,
129
- version: pkg.nextVersion ?? "",
130
- tag: pkg.path === "."
131
- ? `v${pkg.nextVersion ?? ""}`
132
- : `${pkg.path.replaceAll("/", "-")}-v${pkg.nextVersion ?? ""}`,
133
- }))
134
- : [
135
- {
136
- path: ".",
137
- version: plan.nextVersion,
138
- tag: `v${plan.nextVersion}`,
139
- },
140
- ];
141
222
  (0, state_js_1.writeBaselineSha)(cwd, undefined, releaseTargets);
142
223
  (0, node_child_process_1.execFileSync)("git", ["add", (0, state_js_1.getBaselineStatePath)(cwd)], {
143
224
  cwd,
@@ -157,10 +238,13 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
157
238
  };
158
239
  }
159
240
  function renderSimpleReviewRequestBody(version, previousVersion, commits, plan = null, cwd = process.cwd()) {
241
+ const rootPackageLabel = node_path_1.default.basename(cwd);
242
+ const formatPackageLabel = (packagePath) => packagePath === "." ? rootPackageLabel : packagePath;
160
243
  if (plan?.packages && plan.packages.length > 1) {
161
244
  const sections = plan.packages
162
245
  .filter((pkg) => pkg.nextVersion)
163
246
  .map((pkg) => {
247
+ const packageLabel = formatPackageLabel(pkg.path);
164
248
  const notes = (0, changelog_js_1.renderSimpleReleaseNotes)({
165
249
  currentVersion: pkg.currentVersion,
166
250
  nextVersion: pkg.nextVersion ?? "",
@@ -170,12 +254,12 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
170
254
  const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
171
255
  if (linkedHeader) {
172
256
  const [, , compareUrl, date] = linkedHeader;
173
- return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${pkg.path}: ${pkg.nextVersion ?? ""}](${compareUrl}) (${date})`);
257
+ return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${packageLabel}: ${pkg.nextVersion ?? ""}](${compareUrl}) (${date})`);
174
258
  }
175
259
  const plainHeader = notes.match(/^##\s+([^\s]+)\s+\(([^)]+)\)/u);
176
260
  if (plainHeader) {
177
261
  const [, , date] = plainHeader;
178
- return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${pkg.path}: ${pkg.nextVersion ?? ""} (${date})`);
262
+ return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${packageLabel}: ${pkg.nextVersion ?? ""} (${date})`);
179
263
  }
180
264
  return notes;
181
265
  })
@@ -223,5 +307,5 @@ function pushReleaseBranch(cwd, branch) {
223
307
  });
224
308
  }
225
309
  function isReleaseCommitMessage(subject) {
226
- return /^chore\(release\):\sv\d+\.\d+\.\d+/u.test(subject);
310
+ return /^chore\(release\):\s+(?:v\d+\.\d+\.\d+|\S+-v\d+\.\d+\.\d+)(?:,\s+(?:v\d+\.\d+\.\d+|\S+-v\d+\.\d+\.\d+))*$/u.test(subject);
227
311
  }
@@ -11,26 +11,29 @@ const node_child_process_1 = require("node:child_process");
11
11
  const node_fs_1 = __importDefault(require("node:fs"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
13
  const load_config_js_1 = require("../../config/load-config.js");
14
+ const MANIFEST_VERSION_KEY = "manifest-version";
15
+ const BASELINE_SHA_KEY = "baseline-sha";
16
+ const RELEASE_TARGETS_KEY = "release-targets";
14
17
  function parseStateFile(raw, filePath) {
15
18
  const parsed = JSON.parse(raw);
16
19
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
17
20
  throw new Error(`Invalid release manifest at ${filePath}: expected an object.`);
18
21
  }
19
22
  const manifest = parsed;
20
- if (manifest.manifestVersion !== undefined &&
21
- manifest.manifestVersion !== 1) {
22
- throw new Error(`Unsupported manifestVersion in ${filePath}: ${String(manifest.manifestVersion)}.`);
23
+ if (manifest[MANIFEST_VERSION_KEY] !== undefined &&
24
+ manifest[MANIFEST_VERSION_KEY] !== 1) {
25
+ throw new Error(`Unsupported ${MANIFEST_VERSION_KEY} in ${filePath}: ${String(manifest[MANIFEST_VERSION_KEY])}.`);
23
26
  }
24
- if (manifest.baselineSha !== undefined &&
25
- typeof manifest.baselineSha !== "string") {
26
- throw new Error(`Invalid release manifest at ${filePath}: baselineSha must be a string.`);
27
+ if (manifest[BASELINE_SHA_KEY] !== undefined &&
28
+ typeof manifest[BASELINE_SHA_KEY] !== "string") {
29
+ throw new Error(`Invalid release manifest at ${filePath}: ${BASELINE_SHA_KEY} must be a string.`);
27
30
  }
28
- if (manifest.releaseTargets !== undefined &&
29
- !Array.isArray(manifest.releaseTargets)) {
30
- throw new Error(`Invalid release manifest at ${filePath}: releaseTargets must be an array.`);
31
+ if (manifest[RELEASE_TARGETS_KEY] !== undefined &&
32
+ !Array.isArray(manifest[RELEASE_TARGETS_KEY])) {
33
+ throw new Error(`Invalid release manifest at ${filePath}: ${RELEASE_TARGETS_KEY} must be an array.`);
31
34
  }
32
- if (Array.isArray(manifest.releaseTargets)) {
33
- for (const target of manifest.releaseTargets) {
35
+ if (Array.isArray(manifest[RELEASE_TARGETS_KEY])) {
36
+ for (const target of manifest[RELEASE_TARGETS_KEY]) {
34
37
  if (!target || typeof target !== "object" || Array.isArray(target)) {
35
38
  throw new Error(`Invalid release manifest at ${filePath}: each release target must be an object.`);
36
39
  }
@@ -38,7 +41,7 @@ function parseStateFile(raw, filePath) {
38
41
  if (typeof record.path !== "string" ||
39
42
  typeof record.version !== "string" ||
40
43
  typeof record.tag !== "string") {
41
- throw new Error(`Invalid release manifest at ${filePath}: releaseTargets must contain string path, version, and tag.`);
44
+ throw new Error(`Invalid release manifest at ${filePath}: ${RELEASE_TARGETS_KEY} must contain string path, version, and tag.`);
42
45
  }
43
46
  }
44
47
  }
@@ -66,7 +69,7 @@ function readBaselineSha(cwd = process.cwd()) {
66
69
  return null;
67
70
  }
68
71
  const parsed = parseStateFile(node_fs_1.default.readFileSync(filePath, "utf8"), filePath);
69
- return parsed.baselineSha ?? null;
72
+ return parsed[BASELINE_SHA_KEY] ?? null;
70
73
  }
71
74
  function readReleaseTargets(cwd = process.cwd()) {
72
75
  const filePath = getBaselineStatePath(cwd);
@@ -74,10 +77,10 @@ function readReleaseTargets(cwd = process.cwd()) {
74
77
  return [];
75
78
  }
76
79
  const parsed = parseStateFile(node_fs_1.default.readFileSync(filePath, "utf8"), filePath);
77
- return parsed.releaseTargets ?? [];
80
+ return parsed[RELEASE_TARGETS_KEY] ?? [];
78
81
  }
79
82
  function writeBaselineSha(cwd = process.cwd(), sha, releaseTargets = []) {
80
- const baselineSha = sha ??
83
+ const baselineShaValue = sha ??
81
84
  (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], {
82
85
  cwd,
83
86
  encoding: "utf8",
@@ -85,9 +88,9 @@ function writeBaselineSha(cwd = process.cwd(), sha, releaseTargets = []) {
85
88
  }).trim();
86
89
  const filePath = getBaselineStatePath(cwd);
87
90
  const next = {
88
- manifestVersion: 1,
89
- baselineSha,
90
- releaseTargets,
91
+ [MANIFEST_VERSION_KEY]: 1,
92
+ [BASELINE_SHA_KEY]: baselineShaValue,
93
+ [RELEASE_TARGETS_KEY]: releaseTargets,
91
94
  };
92
95
  node_fs_1.default.writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
93
96
  }
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const configSchema: z.ZodObject<{
3
+ $schema: z.ZodOptional<z.ZodString>;
3
4
  version: z.ZodLiteral<1>;
4
5
  "review-mode": z.ZodOptional<z.ZodEnum<{
5
6
  direct: "direct";
@@ -33,7 +34,7 @@ export declare const configSchema: z.ZodObject<{
33
34
  jsonpath: z.ZodOptional<z.ZodString>;
34
35
  pattern: z.ZodOptional<z.ZodString>;
35
36
  }, z.core.$strip>>>;
36
- }, z.core.$strip>>>;
37
+ }, z.core.$strict>>>;
37
38
  plugins: z.ZodOptional<z.ZodArray<z.ZodString>>;
38
- }, z.core.$strip>;
39
+ }, z.core.$strict>;
39
40
  export type ConfigSchema = z.infer<typeof configSchema>;
@@ -40,13 +40,17 @@ const artifactRuleSchema = zod_1.z
40
40
  });
41
41
  }
42
42
  });
43
- const packageSchema = zod_1.z.object({
43
+ const packageSchema = zod_1.z
44
+ .object({
44
45
  "release-type": zod_1.z.string().optional(),
45
46
  "package-name": zod_1.z.string().optional(),
46
47
  "exclude-paths": zod_1.z.array(zod_1.z.string()).optional(),
47
48
  "extra-files": zod_1.z.array(artifactRuleSchema).optional(),
48
- });
49
- exports.configSchema = zod_1.z.object({
49
+ })
50
+ .strict();
51
+ exports.configSchema = zod_1.z
52
+ .object({
53
+ $schema: zod_1.z.string().optional(),
50
54
  version: zod_1.z.literal(1),
51
55
  "review-mode": zod_1.z.enum(["direct", "review"]).optional(),
52
56
  "version-file": zod_1.z.string().optional(),
@@ -61,4 +65,5 @@ exports.configSchema = zod_1.z.object({
61
65
  "release-type": zod_1.z.string().optional(),
62
66
  packages: zod_1.z.record(zod_1.z.string().min(1), packageSchema).optional(),
63
67
  plugins: zod_1.z.array(zod_1.z.string().min(1)).optional(),
64
- });
68
+ })
69
+ .strict();
@@ -287,6 +287,14 @@ function parseDependencyName(line) {
287
287
  const match = line.match(/^\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_-]+))\s*=/u);
288
288
  return match?.[1] ?? match?.[2] ?? match?.[3] ?? null;
289
289
  }
290
+ function rewriteCargoVersionRequirement(currentRequirement, nextVersion) {
291
+ const simpleRequirementMatch = currentRequirement.match(/^(\s*)(\^|~|>=|<=|>|<|=)?(\s*)([0-9A-Za-z.+-]+)(\s*)$/u);
292
+ if (!simpleRequirementMatch) {
293
+ return nextVersion;
294
+ }
295
+ const [, leadingWhitespace = "", operator = "", operatorWhitespace = "", , trailingWhitespace = "",] = simpleRequirementMatch;
296
+ return `${leadingWhitespace}${operator}${operatorWhitespace}${nextVersion}${trailingWhitespace}`;
297
+ }
290
298
  function writeInternalDependencyVersionInLine(line, dependencyName, versionByDependency) {
291
299
  const nextVersion = versionByDependency.get(dependencyName);
292
300
  if (!nextVersion) {
@@ -294,19 +302,24 @@ function writeInternalDependencyVersionInLine(line, dependencyName, versionByDep
294
302
  }
295
303
  const stringVersionMatch = line.match(/^(\s*(?:"[^"]+"|'[^']+'|[A-Za-z0-9_-]+)\s*=\s*)(["'])([^"']*)(\2)(\s*(?:#.*)?)?$/u);
296
304
  if (stringVersionMatch) {
297
- const [, prefix = "", quote = '"', , , suffix = ""] = stringVersionMatch;
298
- return `${prefix}${quote}${nextVersion}${quote}${suffix}`;
305
+ const [, prefix = "", quote = '"', current = "", , suffix = ""] = stringVersionMatch;
306
+ const rewrittenRequirement = rewriteCargoVersionRequirement(current, nextVersion);
307
+ return `${prefix}${quote}${rewrittenRequirement}${quote}${suffix}`;
299
308
  }
300
309
  const inlineTableMatch = line.match(/^(\s*(?:"[^"]+"|'[^']+'|[A-Za-z0-9_-]+)\s*=\s*\{)(.*)(\}\s*(?:#.*)?)$/u);
301
- if (!inlineTableMatch) {
302
- return line;
310
+ if (inlineTableMatch) {
311
+ const [, prefix = "", tableBody = "", suffix = ""] = inlineTableMatch;
312
+ const updatedTableBody = tableBody.replace(/(\bversion\s*=\s*)(["'])([^"']*)(\2)/u, (_match, versionPrefix, quote, currentVersion) => `${versionPrefix}${quote}${rewriteCargoVersionRequirement(String(currentVersion), nextVersion)}${quote}`);
313
+ if (updatedTableBody === tableBody) {
314
+ return line;
315
+ }
316
+ return `${prefix}${updatedTableBody}${suffix}`;
303
317
  }
304
- const [, prefix = "", tableBody = "", suffix = ""] = inlineTableMatch;
305
- const updatedTableBody = tableBody.replace(/(\bversion\s*=\s*)(["'])([^"']*)(\2)/u, `$1$2${nextVersion}$4`);
306
- if (updatedTableBody === tableBody) {
318
+ const updatedTableLine = line.replace(/(\bversion\s*=\s*)(["'])([^"']*)(\2)/u, (_match, versionPrefix, quote, currentVersion) => `${versionPrefix}${quote}${rewriteCargoVersionRequirement(String(currentVersion), nextVersion)}${quote}`);
319
+ if (updatedTableLine === line) {
307
320
  return line;
308
321
  }
309
- return `${prefix}${updatedTableBody}${suffix}`;
322
+ return updatedTableLine;
310
323
  }
311
324
  function writeInternalDependencyVersions(cargoTomlRaw, internalCrates, version) {
312
325
  if (internalCrates.size === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versionary",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Automatic release framework based on conventional commits and semantic versioning",
5
5
  "keywords": [
6
6
  "releasing",