Skip to content
This repository was archived by the owner on Feb 26, 2020. It is now read-only.

Release itself #14

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": 2017,
"ecmaFeatures": {
"impliedStrict": true
}
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# JS Cookie Release API

Release routines for JavaScript Cookie library

## Functions

#### `Promise bumpPackageJSON(String bumpSpec, String filePath)`

Bumps the "version" property from a list of file paths that matches the [JSON](http://json.org/) spec.

#### `Promise gitCommit(String message, NodeGitRepository gitRepository)`

Add all the changes to the staging area and create a commit to the given repository.

## Release Steps

* Run `npm run release <bumpSpec>`, where `bumpSpec` is either `patch`, `minor` or `major`
* Run `npm publish ./`
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
"author": "Fagner Brack",
"license": "MIT",
"scripts": {
"test": "eslint \"src/**/*.js\" \"test/**/*.js\" && mocha --trace-warnings",
"test:watch": "eslint \"src/**/*.js\" \"test/**/*.js\" && mocha -w"
"lint": "eslint *.js \"src/**/*.js\" \"test/**/*.js\"",
"test": "mocha --trace-warnings",
"test:watch": "mocha -w",
"release:test": "node release.js fake patch",
"release": "node release.js"
},
"devDependencies": {
"chai": "4.1.2",
Expand All @@ -25,7 +28,6 @@
"dependencies": {
"app-root-path": "2.0.1",
"bluebird": "3.5.1",
"json-update": "3.0.0",
"nodegit": "0.20.2"
},
"engines": {
Expand Down
64 changes: 64 additions & 0 deletions release.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const Promise = require("bluebird");
const Git = require("nodegit");

const bumpPackageJSON = require("./src/file/bump-package-json");
const gitCommit = require("./src/git/git-commit");
const gitTag = require("./src/git/git-tag");
const gitPushTag = require("./src/git/git-push-tag");

let targetBumpSpec;
if (process.argv.includes("patch")) {
targetBumpSpec = "patch";
}
if (process.argv.includes("minor")) {
targetBumpSpec = "minor";
}
if (process.argv.includes("major")) {
targetBumpSpec = "major";
}
if (!targetBumpSpec) {
console.log("Invalid bump spec, use \"patch\", \"minor\" or \"major\"");
return;
}

const isFakeRun = process.argv.includes("fake");

let localRepo;

Promise.try(() => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use async/await

console.log("Bumping package.json...");
if (!isFakeRun) {
return bumpPackageJSON(targetBumpSpec, "package.json");
}
}).then(() => {
return Git.Repository.discover(".", 0, ".");
}).then((foundRepositoryPath) => {
console.log("Found repository on:", foundRepositoryPath);
return Git.Repository.open(foundRepositoryPath);
}).then((_localRepo) => {
localRepo = _localRepo;
}).then(() => {
console.log("Creating release commit...");
if (!isFakeRun) {
return gitCommit("Release new version", localRepo);
}
return "fake44ef0665e9e8e5fdf7c6bfcd61f95fe8b699";
}).then((commitObjectId) => {
const tagName = commitObjectId && commitObjectId.substring(0, 8);
const tagReferenceCommit = commitObjectId;
console.log("Creating tag:", tagName);
if (!isFakeRun) {
return gitTag(tagName, tagReferenceCommit, localRepo);
}
return /* FakeTag */ { name: () => "fake_tag_name" };
}).then((tag) => {
console.log("Created tag '" + tag.name() + "'");
return localRepo.getRemotes().then((localRemotes) => {
if (!isFakeRun) {
return gitPushTag(tag.name(), localRemotes[0], localRepo);
}
});
});

// TODO Don't leak NodeGitRepository to gitCommit
// TODO Allow the input of password?
18 changes: 0 additions & 18 deletions src/file/bump-json-files.js

This file was deleted.

23 changes: 23 additions & 0 deletions src/file/bump-package-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const root = require("app-root-path");
const writeFile = require("util").promisify(require("fs").writeFile);
const readFile = require("util").promisify(require("fs").readFile);

const bumpVersion = require(root + "/src/bump-version");

module.exports = async (bumpSpec, filePath) => {
const VERSION_KEY_VALUE_REGEX = /"version":( +)?"(.+)"/;
const fileContent = await readFile(filePath, "UTF-8");
const matchedVersion = fileContent.match(VERSION_KEY_VALUE_REGEX);
if (matchedVersion === null) {
throw new Error(
"Could not find 'version' property in package.json to bump"
);
}
const version = matchedVersion[2];
const bumpedVersion = bumpVersion(version, bumpSpec);
const replacedFileContent = fileContent.replace(
VERSION_KEY_VALUE_REGEX,
`"version":$1"${bumpedVersion}"`
);
await writeFile(filePath, replacedFileContent);
};
File renamed without changes.
5 changes: 5 additions & 0 deletions src/git/git-push-tag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = function(tagName, remoteName, repository) {
return repository.getRemote(remoteName).then(function(remote) {
return remote.push([`refs/tags/${tagName}:refs/tags/${tagName}`]);
});
};
75 changes: 45 additions & 30 deletions test/file/bump-json-files.spec.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,48 @@
const root = require("app-root-path");
const expect = require("chai").expect;
const Promise = require("bluebird");
const loadJSON = Promise.promisify(require("json-update").load);

const bumpJSONFiles = require(root + "/src/file/bump-json-files");
const createFileSync = require(root + "/test/dummy-data/create-file-sync");

describe("bump-json-files", function() {

describe("Given a dummy file in JSON format", function() {
const targetFilename = "bump-minor.json";
let removeDummyJSONFileSync;

beforeEach(function() {
removeDummyJSONFileSync = createFileSync(targetFilename, JSON.stringify({
version: "0.0.0"
}));
});

afterEach(function() {
removeDummyJSONFileSync();
});

it("should bump the 'minor' version attribute", function() {
return bumpJSONFiles("minor", [targetFilename]).then(function() {
return loadJSON(targetFilename);
}).then(function(targetFile) {
expect(targetFile).to.have.property("version", "0.1.0");
});
});
const readFile = require("util").promisify(require("fs").readFile);
const writeFile = require("util").promisify(require("fs").writeFile);
const unlink = require("util").promisify(require("fs").unlink);

const bumpPackageJSON = require(require("app-root-path") + "/src/file/bump-package-json");

describe("Bump Package JSON", () => {

it("bumps the patch version in the package.json", async () => {
await writeFile("target-package.json", "{\"version\":\"0.0.0\"}");
await bumpPackageJSON("patch", "target-package.json");
const targetFileContent = await readFile("target-package.json", "UTF-8");
expect(targetFileContent).to.equal("{\"version\":\"0.0.1\"}");
await unlink("target-package.json");

await writeFile("another-target-package.json", "{\"version\":\"0.0.0\"}");
await bumpPackageJSON("patch", "another-target-package.json");
const anotherTargetFileContent = await readFile("another-target-package.json", "UTF-8");
expect(anotherTargetFileContent).to.equal("{\"version\":\"0.0.1\"}");
await unlink("another-target-package.json");
});

it("keeps existing properties intact", async () => {
await writeFile("target-package.json", "{\"existing\":1,\"version\":\"0.0.0\"}");
await bumpPackageJSON("patch", "target-package.json");
const bumpedFile = await readFile("target-package.json", "UTF-8");
expect(bumpedFile).to.equal("{\"existing\":1,\"version\":\"0.0.1\"}");
await unlink("target-package.json");
});

it("keeps existing spacing intact", async () => {
await writeFile("target-package.json", "{ \"version\": \"0.0.0\" }");
await bumpPackageJSON("patch", "target-package.json");
const bumpedFile = await readFile("target-package.json", "UTF-8");
expect(bumpedFile).to.equal("{ \"version\": \"0.0.1\" }");
await unlink("target-package.json");
});

it("keep existing multiple spacing intact", async () => {
await writeFile("target-package.json", "{ \"version\": \"0.0.0\" }");
await bumpPackageJSON("patch", "target-package.json");
const bumpedFile = await readFile("target-package.json", "UTF-8");
expect(bumpedFile).to.equal("{ \"version\": \"0.0.1\" }");
await unlink("target-package.json");
});

});
56 changes: 39 additions & 17 deletions test/git/git-push.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,62 @@ const root = require("app-root-path");
const expect = require("chai").expect;

const startGitRepoWithServer = require(root + "/test/dummy-data/start-git-repo-with-server");
const gitPush = require(root + "/src/git/git-push");
const gitPushMaster = require(root + "/src/git/git-push-master");
const gitPushTag = require(root + "/src/git/git-push-tag");
const gitCommit = require(root + "/src/git/git-commit");
const gitTag = require(root + "/src/git/git-tag");
const cloneToLocalDir = require(root + "/test/dummy-data/clone-repo-to-local-dir");

describe("git-push", function() {
describe("Given a dummy server with git enabled cloned to local dir", function() {
let defaultTestRepository;
let clonedTestRepository;

describe("Given a dummy server with git enabled cloned to local dir", function() {

beforeEach(function() {
return startGitRepoWithServer().then(function(defaultTestRepositoryResult) {
defaultTestRepository = defaultTestRepositoryResult;
return cloneToLocalDir(defaultTestRepository.gitHttpUrl);
}).then(function(clonedTestRepositoryResult) {
clonedTestRepository = clonedTestRepositoryResult;
});
beforeEach(function() {
return startGitRepoWithServer().then(function(defaultTestRepositoryResult) {
defaultTestRepository = defaultTestRepositoryResult;
return cloneToLocalDir(defaultTestRepository.gitHttpUrl);
}).then(function(clonedTestRepositoryResult) {
clonedTestRepository = clonedTestRepositoryResult;
});
});

afterEach(function() {
defaultTestRepository.destroy();
clonedTestRepository.remove();
});
afterEach(function() {
defaultTestRepository.destroy();
clonedTestRepository.remove();
});

describe("Git Push Master To Remote", function() {
it("should commit and push the repository sucessfully to the remote", function() {
let dummyCommitId;
return gitCommit("Dummy commit", clonedTestRepository.repository).then(function(oid) {
dummyCommitId = oid;
return gitPush(defaultTestRepository.remotes[0].name, clonedTestRepository.repository);
return gitPushMaster(defaultTestRepository.remotes[0].name, clonedTestRepository.repository);
}).then(function() {
return defaultTestRepository.remotes[0].repository.getCommit(dummyCommitId);
}).then(function(commit) {
expect(commit.message()).to.equal("Dummy commit");
});
});
});
});

describe("Git Push Tag To Remote", function() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use async/await

it("should commit, create a tag and push successfully to the remote", function() {
const DUMMY_TAG_NAME = "dummy_tag_name";
return gitCommit("Dummy commit", clonedTestRepository.repository).then(function(dummyCommitId) {
return gitTag(DUMMY_TAG_NAME, dummyCommitId, clonedTestRepository.repository);
}).then(function() {
return gitPushTag(DUMMY_TAG_NAME, defaultTestRepository.remotes[0].name, clonedTestRepository.repository);
}).then(function deleteLocalTag() {
return require("nodegit").Tag.delete(clonedTestRepository.repository, DUMMY_TAG_NAME);
}).then(function fetchRemoteTag() {
return clonedTestRepository.repository.getRemote(defaultTestRepository.remotes[0].name).then(function(remote) {
return remote.fetch([`refs/tags/${DUMMY_TAG_NAME}`]);
});
}).then(function() {
return clonedTestRepository.repository.getTagByName(DUMMY_TAG_NAME).then(function(tag) {
expect(tag.name()).to.equal(DUMMY_TAG_NAME);
});
});
});
});
});