mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 03:39:55 +00:00
remove mocking from implementation and use jest to mock git cli instead
This commit is contained in:
parent
332e429a41
commit
b094707324
@ -12,7 +12,7 @@ class GitHelper {
|
||||
}
|
||||
|
||||
getRefRegex(branch) {
|
||||
return new RegExp("s*([a-z,0-9]+[.][.][a-z,0-9]+) " + branch, "g");
|
||||
return new RegExp(`s*([a-z,0-9]+[.][.][a-z,0-9]+) ${branch}`, "g");
|
||||
}
|
||||
|
||||
async execShell(command) {
|
||||
@ -22,10 +22,10 @@ class GitHelper {
|
||||
}
|
||||
|
||||
async isGitRepo(moduleFolder) {
|
||||
const res = await this.execShell(`cd ${moduleFolder} && git remote -v`);
|
||||
const { stderr } = await this.execShell(`cd ${moduleFolder} && git remote -v`);
|
||||
|
||||
if (res.stderr) {
|
||||
Log.error(`Failed to fetch git data for ${moduleFolder}: ${res.stderr}`);
|
||||
if (stderr) {
|
||||
Log.error(`Failed to fetch git data for ${moduleFolder}: ${stderr}`);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -68,33 +68,27 @@ class GitHelper {
|
||||
isBehindInStatus: false
|
||||
};
|
||||
|
||||
let res;
|
||||
if (repo.module === "default") {
|
||||
// the hash is only needed for the mm repo
|
||||
res = await this.execShell(`cd ${repo.folder} && git rev-parse HEAD`);
|
||||
const { stderr, stdout } = await this.execShell(`cd ${repo.folder} && git rev-parse HEAD`);
|
||||
|
||||
if (res.stderr) {
|
||||
Log.error(`Failed to get current commit hash for ${repo.module}: ${res.stderr}`);
|
||||
if (stderr) {
|
||||
Log.error(`Failed to get current commit hash for ${repo.module}: ${stderr}`);
|
||||
}
|
||||
|
||||
gitInfo.hash = res.stdout;
|
||||
gitInfo.hash = stdout;
|
||||
}
|
||||
|
||||
if (repo.res) {
|
||||
// mocking
|
||||
res = repo.res;
|
||||
} else {
|
||||
res = await this.execShell(`cd ${repo.folder} && git status -sb`);
|
||||
}
|
||||
const { stderr, stdout } = await this.execShell(`cd ${repo.folder} && git status -sb`);
|
||||
|
||||
if (res.stderr) {
|
||||
Log.error(`Failed to get git status for ${repo.module}: ${res.stderr}`);
|
||||
if (stderr) {
|
||||
Log.error(`Failed to get git status for ${repo.module}: ${stderr}`);
|
||||
// exit without git status info
|
||||
return;
|
||||
}
|
||||
|
||||
// only the first line of stdout is evaluated
|
||||
let status = res.stdout.split("\n")[0];
|
||||
let status = stdout.split("\n")[0];
|
||||
// examples for status:
|
||||
// ## develop...origin/develop
|
||||
// ## master...origin/master [behind 8]
|
||||
@ -119,14 +113,7 @@ class GitHelper {
|
||||
}
|
||||
|
||||
async getRepoInfo(repo) {
|
||||
let gitInfo;
|
||||
|
||||
if (repo.gitInfo) {
|
||||
// mocking
|
||||
gitInfo = repo.gitInfo;
|
||||
} else {
|
||||
gitInfo = await this.getStatusInfo(repo);
|
||||
}
|
||||
const gitInfo = await this.getStatusInfo(repo);
|
||||
|
||||
if (!gitInfo) {
|
||||
return;
|
||||
@ -136,20 +123,13 @@ class GitHelper {
|
||||
return gitInfo;
|
||||
}
|
||||
|
||||
let res;
|
||||
|
||||
if (repo.res) {
|
||||
// mocking
|
||||
res = repo.res;
|
||||
} else {
|
||||
res = await this.execShell(`cd ${repo.folder} && git fetch --dry-run`);
|
||||
}
|
||||
const { stderr } = await this.execShell(`cd ${repo.folder} && git fetch --dry-run`);
|
||||
|
||||
// example output:
|
||||
// From https://github.com/MichMich/MagicMirror
|
||||
// e40ddd4..06389e3 develop -> origin/develop
|
||||
// here the result is in stderr (this is a git default, don't ask why ...)
|
||||
const matches = res.stderr.match(this.getRefRegex(gitInfo.current));
|
||||
const matches = stderr.match(this.getRefRegex(gitInfo.current));
|
||||
|
||||
if (!matches || !matches[0]) {
|
||||
// no refs found, nothing to do
|
||||
@ -158,8 +138,8 @@ class GitHelper {
|
||||
|
||||
// get behind with refs
|
||||
try {
|
||||
res = await this.execShell(`cd ${repo.folder} && git rev-list --ancestry-path --count ${matches[0]}`);
|
||||
gitInfo.behind = parseInt(res.stdout);
|
||||
const { stdout } = await this.execShell(`cd ${repo.folder} && git rev-list --ancestry-path --count ${matches[0]}`);
|
||||
gitInfo.behind = parseInt(stdout);
|
||||
|
||||
return gitInfo;
|
||||
} catch (err) {
|
||||
@ -167,28 +147,18 @@ class GitHelper {
|
||||
}
|
||||
}
|
||||
|
||||
async getStatus() {
|
||||
const gitResultList = [];
|
||||
|
||||
for (let repo of this.gitRepos) {
|
||||
const gitInfo = await this.getStatusInfo(repo);
|
||||
|
||||
if (gitInfo) {
|
||||
gitResultList.push(gitInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return gitResultList;
|
||||
}
|
||||
|
||||
async getRepos() {
|
||||
const gitResultList = [];
|
||||
|
||||
for (const repo of this.gitRepos) {
|
||||
const gitInfo = await this.getRepoInfo(repo);
|
||||
try {
|
||||
const gitInfo = await this.getRepoInfo(repo);
|
||||
|
||||
if (gitInfo) {
|
||||
gitResultList.push(gitInfo);
|
||||
if (gitInfo) {
|
||||
gitResultList.push(gitInfo);
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error(`Failed to retrieve repo info for ${repo.module}: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Updatenotification custom module returns status information 1`] = `
|
||||
Object {
|
||||
"behind": 7,
|
||||
"current": "master",
|
||||
"hash": "",
|
||||
"isBehindInStatus": false,
|
||||
"module": "MMM-Fuel",
|
||||
"tracking": "origin/master",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Updatenotification custom module returns status information without hash 1`] = `
|
||||
Object {
|
||||
"behind": 7,
|
||||
"current": "master",
|
||||
"hash": "",
|
||||
"isBehindInStatus": false,
|
||||
"module": "MMM-Fuel",
|
||||
"tracking": "origin/master",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Updatenotification default returns status information 1`] = `
|
||||
Object {
|
||||
"behind": 5,
|
||||
"current": "develop",
|
||||
"hash": "332e429a41f1a2339afd4f0ae96dd125da6beada",
|
||||
"isBehindInStatus": false,
|
||||
"module": "default",
|
||||
"tracking": "origin/develop",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Updatenotification default returns status information early if isBehindInStatus 1`] = `
|
||||
Object {
|
||||
"behind": 5,
|
||||
"current": "develop",
|
||||
"hash": "332e429a41f1a2339afd4f0ae96dd125da6beada",
|
||||
"isBehindInStatus": true,
|
||||
"module": "default",
|
||||
"tracking": "origin/develop",
|
||||
}
|
||||
`;
|
@ -1,126 +1,139 @@
|
||||
const path = require("path");
|
||||
const git_Helper = require("../../../modules/default/updatenotification/git_helper.js");
|
||||
const gitHelper = new git_Helper.gitHelper();
|
||||
gitHelper.add("default");
|
||||
jest.mock("util", () => ({
|
||||
...jest.requireActual("util"),
|
||||
promisify: jest.fn()
|
||||
}));
|
||||
|
||||
const test1 = {
|
||||
module: "test1",
|
||||
folder: "",
|
||||
res: {
|
||||
stdout: "## master...origin/master [behind 8]",
|
||||
stderr: ""
|
||||
},
|
||||
gitInfo: {
|
||||
module: "default",
|
||||
// commits behind:
|
||||
behind: 0,
|
||||
// branch name:
|
||||
current: "develop",
|
||||
// current hash:
|
||||
hash: "",
|
||||
// remote branch:
|
||||
tracking: "",
|
||||
isBehindInStatus: false
|
||||
}
|
||||
};
|
||||
jest.mock("fs", () => ({
|
||||
...jest.requireActual("fs"),
|
||||
statSync: jest.fn()
|
||||
}));
|
||||
|
||||
const test2 = {
|
||||
module: "test2",
|
||||
folder: "",
|
||||
res: {
|
||||
stdout: "## develop...origin/develop",
|
||||
stderr: ""
|
||||
}
|
||||
};
|
||||
|
||||
const test3 = {
|
||||
module: "test3",
|
||||
folder: "",
|
||||
res: {
|
||||
stdout: "",
|
||||
stderr: "error"
|
||||
},
|
||||
gitInfo: {
|
||||
module: "default",
|
||||
// commits behind:
|
||||
behind: 2,
|
||||
// branch name:
|
||||
current: "develop",
|
||||
// current hash:
|
||||
hash: "",
|
||||
// remote branch:
|
||||
tracking: "",
|
||||
isBehindInStatus: true
|
||||
}
|
||||
};
|
||||
|
||||
const test4 = {
|
||||
module: "default",
|
||||
folder: path.join(__dirname, "../../.."),
|
||||
res: {
|
||||
stdout: "",
|
||||
stderr: " e40ddd4..06389e3 develop -> origin/develop"
|
||||
},
|
||||
gitInfo: {
|
||||
module: "default",
|
||||
// commits behind:
|
||||
behind: 0,
|
||||
// branch name:
|
||||
current: "develop",
|
||||
// current hash:
|
||||
hash: "",
|
||||
// remote branch:
|
||||
tracking: "",
|
||||
isBehindInStatus: false
|
||||
}
|
||||
};
|
||||
jest.mock("logger", () => ({
|
||||
...jest.requireActual("logger"),
|
||||
error: jest.fn(),
|
||||
info: jest.fn()
|
||||
}));
|
||||
|
||||
describe("Updatenotification", function () {
|
||||
it("should return valid output for git status", async function () {
|
||||
const arr = await gitHelper.getStatus();
|
||||
expect(arr.length).toBe(1);
|
||||
const gitInfo = arr[0];
|
||||
expect(gitInfo.current).not.toBe("");
|
||||
expect(gitInfo.hash).not.toBe("");
|
||||
}, 15000);
|
||||
const execMock = jest.fn();
|
||||
|
||||
it("should return behind=8 for test1", async function () {
|
||||
const gitInfo = await gitHelper.getStatusInfo(test1);
|
||||
expect(gitInfo.behind).toBe(8);
|
||||
expect(gitInfo.isBehindInStatus).toBe(true);
|
||||
let gitHelper;
|
||||
|
||||
let gitRemoteOut;
|
||||
let gitRevParseOut;
|
||||
let gitStatusOut;
|
||||
let gitFetchOut;
|
||||
let gitRevListOut;
|
||||
let gitRemoteErr;
|
||||
let gitRevParseErr;
|
||||
let gitStatusErr;
|
||||
let gitFetchErr;
|
||||
let gitRevListErr;
|
||||
|
||||
beforeAll(async function () {
|
||||
const { promisify } = require("util");
|
||||
promisify.mockReturnValue(execMock);
|
||||
|
||||
const GitHelper = require(`../../../modules/default/updatenotification/git_helper`);
|
||||
gitHelper = new GitHelper();
|
||||
});
|
||||
|
||||
it("should return behind=0 for test2", async function () {
|
||||
const gitInfo = await gitHelper.getStatusInfo(test2);
|
||||
expect(gitInfo.behind).toBe(0);
|
||||
expect(gitInfo.isBehindInStatus).toBe(false);
|
||||
beforeEach(function () {
|
||||
gitRemoteOut = "";
|
||||
gitRevParseOut = "";
|
||||
gitStatusOut = "";
|
||||
gitFetchOut = "";
|
||||
gitRevListOut = "";
|
||||
gitRemoteErr = "";
|
||||
gitRevParseErr = "";
|
||||
gitStatusErr = "";
|
||||
gitFetchErr = "";
|
||||
gitRevListErr = "";
|
||||
|
||||
execMock.mockImplementation(function (command) {
|
||||
if (command.includes("git remote -v")) {
|
||||
return { stdout: gitRemoteOut, stderr: gitRemoteErr };
|
||||
} else if (command.includes("git rev-parse HEAD")) {
|
||||
return { stdout: gitRevParseOut, stderr: gitRevParseErr };
|
||||
} else if (command.includes("git status -sb")) {
|
||||
return { stdout: gitStatusOut, stderr: gitStatusErr };
|
||||
} else if (command.includes("git fetch --dry-run")) {
|
||||
return { stdout: gitFetchOut, stderr: gitFetchErr };
|
||||
} else if (command.includes("git rev-list --ancestry-path --count")) {
|
||||
return { stdout: gitRevListOut, stderr: gitRevListErr };
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should return empty status object for test3", async function () {
|
||||
const gitInfo = await gitHelper.getStatusInfo(test3);
|
||||
expect(gitInfo).toBe(undefined);
|
||||
afterEach(async function () {
|
||||
gitHelper.gitRepos = [];
|
||||
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should return empty repo object for test2", async function () {
|
||||
// no gitInfo provided in res, so returns undefined
|
||||
const gitInfo = await gitHelper.getRepoInfo(test2);
|
||||
expect(gitInfo).toBe(undefined);
|
||||
describe("default", () => {
|
||||
const moduleName = "default";
|
||||
|
||||
beforeEach(async function () {
|
||||
gitRemoteOut = "origin\tgit@github.com:MichMich/MagicMirror.git (fetch)\norigin\tgit@github.com:MichMich/MagicMirror.git (push)\n";
|
||||
gitRevParseOut = "332e429a41f1a2339afd4f0ae96dd125da6beada";
|
||||
gitStatusOut = "## develop...origin/develop\n M tests/unit/functions/updatenotification_spec.js\n";
|
||||
gitFetchErr = "From github.com:MichMich/MagicMirror\n60e0377..332e429 develop -> origin/develop\n";
|
||||
gitRevListOut = "5";
|
||||
|
||||
await gitHelper.add(moduleName);
|
||||
});
|
||||
|
||||
it("returns status information", async function () {
|
||||
const repos = await gitHelper.getRepos();
|
||||
expect(repos[0]).toMatchSnapshot();
|
||||
expect(execMock).toHaveBeenCalledTimes(5);
|
||||
});
|
||||
|
||||
it("returns status information early if isBehindInStatus", async function () {
|
||||
gitStatusOut = "## develop...origin/develop [behind 5]";
|
||||
|
||||
const repos = await gitHelper.getRepos();
|
||||
expect(repos[0]).toMatchSnapshot();
|
||||
expect(execMock).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("excludes repo if status can't be retrieved", async function () {
|
||||
const errorMessage = "Failed to retrieve status";
|
||||
execMock.mockRejectedValueOnce(errorMessage);
|
||||
|
||||
const repos = await gitHelper.getRepos();
|
||||
expect(repos.length).toBe(0);
|
||||
|
||||
const { error } = require("logger");
|
||||
expect(error).toHaveBeenCalledWith(`Failed to retrieve repo info for ${moduleName}: Failed to retrieve status`);
|
||||
});
|
||||
|
||||
it("excludes repo if refs don't match regex", async function () {
|
||||
gitFetchErr = "";
|
||||
|
||||
const repos = await gitHelper.getRepos();
|
||||
expect(repos.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it("should return empty repo object for test1", async function () {
|
||||
// no regex match for refs in empty string, so returns undefined
|
||||
const gitInfo = await gitHelper.getRepoInfo(test1);
|
||||
expect(gitInfo).toBe(undefined);
|
||||
});
|
||||
describe("custom module", () => {
|
||||
const moduleName = "MMM-Fuel";
|
||||
|
||||
it("should return empty repo object for test4", async function () {
|
||||
// git ref list throws error, so returns undefined
|
||||
const gitInfo = await gitHelper.getRepoInfo(test4);
|
||||
expect(gitInfo).toBe(undefined);
|
||||
});
|
||||
beforeEach(async function () {
|
||||
gitRemoteOut = `origin\thttps://github.com/fewieden/${moduleName}.git (fetch)\norigin\thttps://github.com/fewieden/${moduleName}.git (push)\n`;
|
||||
gitRevParseOut = "9d8310163da94441073a93cead711ba43e8888d0";
|
||||
gitStatusOut = "## master...origin/master";
|
||||
gitFetchErr = `From https://github.com/fewieden/${moduleName}\n19f7faf..9d83101 master -> origin/master`;
|
||||
gitRevListOut = "7";
|
||||
|
||||
it("should return behind=2 for test3", async function () {
|
||||
const gitInfo = await gitHelper.getRepoInfo(test3);
|
||||
expect(gitInfo.behind).toBe(2);
|
||||
await gitHelper.add(moduleName);
|
||||
});
|
||||
|
||||
it("returns status information without hash", async function () {
|
||||
const repos = await gitHelper.getRepos();
|
||||
expect(repos[0]).toMatchSnapshot();
|
||||
expect(execMock).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user