Skip to content

Commit

Permalink
feat(gem): add canary hook
Browse files Browse the repository at this point in the history
  • Loading branch information
angeliski committed Mar 27, 2021
1 parent 6505c79 commit 6c2bfe5
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 0 deletions.
72 changes: 72 additions & 0 deletions plugins/gem/__tests__/gem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import glob from "fast-glob";
import { makeHooks } from "@auto-it/core/dist/utils/make-hooks";
import { dummyLog } from "@auto-it/core/dist/utils/logger";
import { execSync } from "child_process";
import { when } from 'jest-when';

import * as utils from "../src/utils";
import Gem from "../src";
Expand Down Expand Up @@ -265,6 +266,10 @@ describe("Gem Plugin", () => {
});

describe("publish", () => {
beforeEach(() => {
execSpy.mockClear();
});

test("uses bundler + rake as default publishing method", async () => {
globSpy.mockReturnValueOnce(["test.gemspec"]);
readFile.mockReturnValue(endent`
Expand Down Expand Up @@ -303,4 +308,71 @@ describe("Gem Plugin", () => {
});
});
});

describe("canary", () => {
beforeEach(() => {
execSpy.mockClear();
});
test("uses (bundler + rake + gem push) as default publishing method", async () => {
globSpy.mockReturnValue(["test.gemspec"]);
readFile.mockReturnValue(endent`
Gem::Specification.new do |spec|
spec.name = "test"
spec.version = "0.1.0"
end
`);

const canaryIdentifier = '-canary-x'
when(execSpy).calledWith("bundle", ["exec", "rake", "build"])
.mockReturnValue(`test 0.2.0.pre${canaryIdentifier} built to pkg/test-0.2.0.pre${canaryIdentifier.replace('-','.')}.gem.`);

const plugin = new Gem();
const hooks = makeHooks();

plugin.apply({ hooks, logger } as any);

const result = await hooks.canary
.promise({ bump: SEMVER.minor, canaryIdentifier: "-canary-x", dryRun: false, quiet: false });

expect(result.newVersion).toBe(`0.2.0.pre${canaryIdentifier.replace('-','.')}`)
expect(result.details).toBe(endent`
:sparkles: Test out this PR via:
\`\`\`bash
gem test, 0.2.0.pre${canaryIdentifier.replace('-','.')}
or
gem install test -v 0.2.0.pre${canaryIdentifier.replace('-','.')}
\`\`\`
`)

expect(execSpy).toHaveBeenCalledWith("bundle", ["exec", "rake", "build"]);
expect(execSpy).toHaveBeenCalledWith("gem", ["push", "pkg/test-0.2.0.pre.canary-x.gem"]);
});

test("dry-run not release", async () => {
globSpy.mockReturnValue(["test.gemspec"]);
readFile.mockReturnValue(endent`
Gem::Specification.new do |spec|
spec.name = "test"
spec.version = "0.1.0"
end
`);

const canaryIdentifier = '-canary-x'
when(execSpy).calledWith("bundle", ["exec", "rake", "build"])
.mockReturnValue(`test 0.2.0.pre${canaryIdentifier} built to pkg/test-0.2.0.pre${canaryIdentifier.replace('-','.')}.gem.`);

const plugin = new Gem();
const hooks = makeHooks();

plugin.apply({ hooks, logger } as any);

await hooks.canary
.promise({ bump: SEMVER.minor, canaryIdentifier: "-canary-x", dryRun: true, quiet: false });

expect(execSpy).not.toHaveBeenCalledWith("bundle", ["exec", "rake", "build"]);
expect(execSpy).not.toHaveBeenCalledWith("gem", ["push", "pkg/test-0.2.0.pre.canary-x.gem"]);
});

});
});
3 changes: 3 additions & 0 deletions plugins/gem/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@
"parse-github-url": "1.0.2",
"semver": "^7.0.0",
"tslib": "2.1.0"
},
"devDependencies": {
"jest-when": "^3.2.1"
}
}
111 changes: 111 additions & 0 deletions plugins/gem/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import envCi from "env-ci";
import { readFile, writeFile, mkdir } from "./utils";

const VERSION_REGEX = /\d+\.\d+\.\d+/;
const GEM_PKG_BUILD_REGEX = /(pkg.*)[^.]/;
const GEM_SPEC_NAME_REGEX = /name\s*=\s*["']([\S ]+)["']/;

const { isCi } = envCi();

const pluginOptions = t.partial({
Expand Down Expand Up @@ -120,6 +123,93 @@ export default class GemPlugin implements IPlugin {
}
);

auto.hooks.canary.tapPromise(
this.name,
async ({ bump, canaryIdentifier, dryRun, quiet }) => {
if (
isCi &&
!fs.existsSync("~/.gem/credentials") &&
process.env.RUBYGEMS_API_KEY
) {
const home = process.env.HOME || "~";
const gemDir = path.join(home, ".gem");

if (!fs.existsSync(gemDir)) {
auto.logger.verbose.info(`Creating ${gemDir} directory`);
await mkdir(gemDir);
}

const credentials = path.join(gemDir, "credentials");

await writeFile(
credentials,
endent`
---
:rubygems_api_key: ${process.env.RUBYGEMS_API_KEY}
`
);
auto.logger.verbose.success(`Wrote ${credentials}`);

execSync(`chmod 0600 ${credentials}`, {
stdio: "inherit",
});
}

const [version, versionFile] = await this.getVersion(auto);
const newTag = inc(version, bump as ReleaseType);

if (!newTag) {
throw new Error(
`The version "${version}" parsed from your version file "${versionFile}" was invalid and could not be incremented. Please fix this!`
);
}

const canaryVersion = `${newTag}.pre${canaryIdentifier.replace('-','.')}`

if (dryRun) {
if (quiet) {
console.log(canaryVersion);
} else {
auto.logger.log.info(`Would have published: ${canaryVersion}`);
}

return;
}


const content = await readFile(versionFile, { encoding: "utf8" });
await writeFile(versionFile, content.replace(version, canaryVersion));

/** Commit the new version. we wait because "rake build" changes the lock file */
/** we don't push that version, is just to clean the stage */
const commitVersion = async () =>
execPromise("git", [
"commit",
"-am",
`"update version: ${canaryVersion} [skip ci]"`,
"--no-verify",
]);


auto.logger.verbose.info("Running default release command");
const buildResult = await execPromise("bundle", ["exec", "rake", "build"]);
const gemPath = GEM_PKG_BUILD_REGEX.exec(buildResult)?.[0]
await commitVersion();
// will push the canary gem
await execPromise("gem", ["push", `${gemPath}`]);

auto.logger.verbose.info("Successfully published canary version");

const name = await this.loadGemName();

return {
newVersion: canaryVersion,
details: this.makeInstallDetails(name, canaryVersion),
};

});

auto.hooks.publish.tapPromise(this.name, async () => {
if (
isCi &&
Expand Down Expand Up @@ -176,6 +266,27 @@ export default class GemPlugin implements IPlugin {
});
}

/** create the installation details */
private makeInstallDetails(name: string | undefined, canaryVersion: string) {
return [
":sparkles: Test out this PR via:\n",
"```bash",
`gem ${name}, ${canaryVersion}`,
"or",
`gem install ${name} -v ${canaryVersion}`,
"```",
].join("\n");
}

/** loads the gem name from .gemspec */
private async loadGemName() {
const gemspec = glob.sync("*.gemspec")[0];
const content = await readFile(gemspec, { encoding: "utf8" });

return content.match(GEM_SPEC_NAME_REGEX)?.[1];
}


/** Get the current version of the gem and where it was found */
private async getVersion(auto: Auto) {
let content = await readFile(this.gemspec, { encoding: "utf8" });
Expand Down

0 comments on commit 6c2bfe5

Please sign in to comment.