Skip to content

Commit

Permalink
Merge pull request #2107 from KetanReddy/bazel-plugin
Browse files Browse the repository at this point in the history
Version File Plugin
  • Loading branch information
hipstersmoothie committed May 20, 2022
2 parents 52b0a81 + a9cac5d commit 233ebdc
Show file tree
Hide file tree
Showing 8 changed files with 611 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/cli/package.json
Expand Up @@ -52,6 +52,7 @@
"@auto-it/core": "link:../core",
"@auto-it/npm": "link:../../plugins/npm",
"@auto-it/released": "link:../../plugins/released",
"@auto-it/version-file": "link:../../plugins/version-file",
"await-to-js": "^3.0.0",
"chalk": "^4.0.0",
"command-line-application": "^0.10.1",
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/tsconfig.json
Expand Up @@ -17,6 +17,9 @@
},
{
"path": "../../plugins/released"
},
{
"path": "../../plugins/version-file"
}
]
}
39 changes: 39 additions & 0 deletions plugins/version-file/README.md
@@ -0,0 +1,39 @@
# Version File Plugin

For managing versions in a repository that maintains the version primarily in a flat file.
Agnostic to the primary language of the repository.
Optional input for a release script to call during the publish/canary/next hooks.

## Installation

This plugin is included with the `auto` CLI so you do not have to install it. To install if you are using the `auto` API directly:

```bash
npm i --save-dev @auto-it/version-file
# or
yarn add -D @auto-it/version-file
```

## Options

- versionFile (optional, default="VERSION"): Path to where the version is stored in the repository. It should be a file containing just the semver.
- releaseScript: (optional, default=None): Path to script that runs the publish actions in your repository. If not supplied nothing will be called. If supplied will be called during the `publish`,`canary` and `next` hooks. For the `publish` hook the first parameter passed to the script will be `release` to indicate that a regular release is being called. For `canary` and `next` hooks the first parameter will be `snapshot` to indicate a prerelease version.

## Usage

### With default options
```json
{
"plugins": [
"version-file"
// other plugins
]
}
```
### With optional arguments
```json
{
"plugins": [
"version-file", {"versionFile": "./tools/Version.txt", "releaseScript":"./tools/publish.sh"}
]
}
305 changes: 305 additions & 0 deletions plugins/version-file/__tests__/version-file.test.ts
@@ -0,0 +1,305 @@
import Auto, { SEMVER } from '@auto-it/core';
import mockFs from "mock-fs";
import fs from "fs";
import BazelPlugin from '../src';
import { makeHooks } from '@auto-it/core/dist/utils/make-hooks';
import { dummyLog } from "@auto-it/core/dist/utils/logger";

// Mocks
const execPromise = jest.fn();
jest.mock(
"../../../packages/core/dist/utils/exec-promise",
() => (...args: any[]) => execPromise(...args)
);
jest.mock("../../../packages/core/dist/utils/get-current-branch", () => ({
getCurrentBranch: () => "main",
}));

beforeEach(() => {
execPromise.mockClear();
});
afterEach(() => {
mockFs.restore();
})

describe('Version File Read Operations', () => {
test("It should return the value in the default file", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

expect(await hooks.getPreviousVersion.promise()).toBe("1.0.0");
});

test("It should return the value in the specified file", async () => {
mockFs({
"VERSIONFILE": `1.0.0`,
});
const plugin = new BazelPlugin({versionFile: "VERSIONFILE"});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

expect(await hooks.getPreviousVersion.promise()).toBe("1.0.0");
});
});

describe("Version File Write Operations", () => {
test("It should version the file properly for major releases", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

await hooks.version.promise({bump: SEMVER.major})
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("2.0.0")
// check that the proper git operations were performed
expect(execPromise).toHaveBeenNthCalledWith(1, "git", ["commit", "-am", "\"Bump version to: v2.0.0 [skip ci]\""]);
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["tag", "v2.0.0"]);
});

test("It should version the file properly for minor releases", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

await hooks.version.promise({bump: SEMVER.minor})
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("1.1.0");
// check that the proper git operations were performed
expect(execPromise).toHaveBeenNthCalledWith(1, "git", ["commit", "-am", "\"Bump version to: v1.1.0 [skip ci]\""]);
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["tag", "v1.1.0"]);
});

test("It should version the file properly for patch releases", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

await hooks.version.promise({bump: SEMVER.patch})
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("1.0.1");
// check that the proper git operations were performed
expect(execPromise).toHaveBeenNthCalledWith(1, "git", ["commit", "-am", "\"Bump version to: v1.0.1 [skip ci]\""]);
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["tag", "v1.0.1"]);
});
})

describe("Test Release Types", () => {
test("Full release with no release script", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

await hooks.publish.promise({bump: SEMVER.major})

// check release script was not called but check changes would be pushed
expect(execPromise).toHaveBeenNthCalledWith(1, "git", ["push", "origin", "main", "--tags"]);
});

test("Full release with release script", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({publishScript:"./tools/release.sh"});
const hooks = makeHooks();

plugin.apply({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
} as Auto);

await hooks.publish.promise({bump: SEMVER.major})

// check release script was called
expect(execPromise).toHaveBeenNthCalledWith(1, "./tools/release.sh", ["release"]);

// check changes would be pushed
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["push", "origin", "main", "--tags"]);
});

test("Canary release with no release script", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply(({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
getCurrentVersion: () => "1.0.0",
git: {
getLatestRelease: () => "1.0.0",
getLatestTagInBranch: () => Promise.resolve("1.0.0"),
},
} as unknown) as Auto);

await hooks.canary.promise({bump: SEMVER.minor, canaryIdentifier: "canary.368.1"})

// check release script was not called and local changes were reverted
expect(execPromise).toHaveBeenNthCalledWith(1, "git", ["reset", "--hard", "HEAD"]);

// Check the right version was written
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("1.1.0-canary.368.1")
});

test("Canary release with release script", async () => {
mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({publishScript:"./tools/release.sh"});
const hooks = makeHooks();

plugin.apply(({
hooks,
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
getCurrentVersion: () => "1.0.0",
git: {
getLatestRelease: () => "1.0.0",
getLatestTagInBranch: () => Promise.resolve("1.0.0"),
},
} as unknown) as Auto);

await hooks.canary.promise({bump: SEMVER.minor, canaryIdentifier: "canary.368.1"})

// check release script was called
expect(execPromise).toHaveBeenNthCalledWith(1, "./tools/release.sh", ["snapshot"]);

// check local changes were reverted
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["reset", "--hard", "HEAD"]);

// Check the right version was written
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("1.1.0-canary.368.1")
});

test("Next release with no release script", async () => {

const prefixRelease: (a: string) => string = (version: string) => {
return `v${version}`;
};

mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({});
const hooks = makeHooks();

plugin.apply(({
hooks,
config: { prereleaseBranches: ["next"] },
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
prefixRelease,
getCurrentVersion: () => "1.0.0",
git: {
getLastTagNotInBaseBranch: async () => undefined,
getLatestRelease: () => "1.0.0",
getLatestTagInBranch: () => Promise.resolve("1.0.0"),
},
} as unknown) as Auto);

await hooks.next.promise(["1.0.0"], {bump: SEMVER.major, fullReleaseNotes:"", releaseNotes:"", commits:[]})

// check release script was not called but git ops were performed
expect(execPromise).toHaveBeenNthCalledWith(1, "git", ["tag", "v2.0.0-next.0"]);
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["push", "origin", "main", "--tags"]);

// Check the right version was written
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("v2.0.0-next.0")
});

test("Next release with release script", async () => {

const prefixRelease: (a: string) => string = (version: string) => {
return `v${version}`;
};

mockFs({
"VERSION": `1.0.0`,
});
const plugin = new BazelPlugin({publishScript:"./tools/release.sh"});
const hooks = makeHooks();

plugin.apply(({
hooks,
config: { prereleaseBranches: ["next"] },
remote: "origin",
baseBranch: "main",
logger: dummyLog(),
prefixRelease,
getCurrentVersion: () => "1.0.0",
git: {
getLastTagNotInBaseBranch: async () => undefined,
getLatestRelease: () => "1.0.0",
getLatestTagInBranch: () => Promise.resolve("1.0.0"),
},
} as unknown) as Auto);

await hooks.next.promise(["1.0.0"], {bump: SEMVER.major, fullReleaseNotes:"", releaseNotes:"", commits:[]})

// check release script was called
expect(execPromise).toHaveBeenNthCalledWith(1, "./tools/release.sh", ["snapshot"]);

// Check git ops
expect(execPromise).toHaveBeenNthCalledWith(2, "git", ["tag", "v2.0.0-next.0"]);
expect(execPromise).toHaveBeenNthCalledWith(3, "git", ["push", "origin", "main", "--tags"]);

// Check the right version was written
expect(fs.readFileSync("VERSION", "utf-8")).toStrictEqual("v2.0.0-next.0")
});
});

0 comments on commit 233ebdc

Please sign in to comment.