Skip to content

Commit

Permalink
Merge pull request #5 from a11smiles/iss3
Browse files Browse the repository at this point in the history
- initial merge of code quality
  • Loading branch information
a11smiles authored Oct 14, 2022
2 parents 68e9a81 + 99df848 commit 3d88d01
Show file tree
Hide file tree
Showing 1,218 changed files with 234,088 additions and 32 deletions.
10 changes: 9 additions & 1 deletion .deepsource.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
version = 1

test_patterns = ["*.test.js"]

exclude_patterns = ["**/node_modules/**"]

[[analyzers]]
name = "test-coverage"
enabled = true

[[analyzers]]
name = "javascript"
enabled = true
enabled = false
24 changes: 24 additions & 0 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Run Unit Tests

on:
pull_request:
types: [opened, reopened]
push:
branches:
- '*'

jobs:
test:
runs-on: ubuntu-latest
name: Run tests
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Report results to DeepSource
run: |
npm test
curl https://deepsource.io/cli | sh
./bin/deepsource report --analyzer test-coverage --key javascript --value-file ./coverage/cobertura-coverage.xml
env:
DEEPSOURCE_DSN: ${{ secrets.DEEPSOURCE_DSN }}
33 changes: 24 additions & 9 deletions gitsync.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ const core = require('@actions/core');
const github = require('@actions/github');
const azdo = require('azure-devops-node-api');
const showdown = require('showdown');
showdown.setFlavor('github');

const JSDOM = require('jsdom').JSDOM;
;(globalThis).window = new JSDOM('', {}).window;

module.exports = class GitSync {

constructor(level = "silent") {
log.setLevel(level, true);
}


// skipcq: TCV-001
async run() {
try {
const context = github.context;
Expand All @@ -18,7 +24,13 @@ module.exports = class GitSync {
let config = this.getConfig(context.payload, env);
log.debug(config);

let workItem = await this.performWork(config);
// Temporary fix until support of PRs
if (config.issue.nodeId.startsWith("PR_")) {
// Log and skip PRs (comments)
log.info(`Action is performed on PR #${config.issue.number}. Skipping...`);
} else {
await this.performWork(config);
}
} catch (exc) {
log.error(exc);
}
Expand Down Expand Up @@ -625,7 +637,7 @@ module.exports = class GitSync {
result = await client.queryByWiql(wiql, context);
log.debug("Query results:", result);

if (result == null) {
if (result === null) {
log.error("Error: project name appears to be invalid.");
core.setFailed("Error: project name appears to be invalid.");
return -1;
Expand All @@ -641,17 +653,19 @@ module.exports = class GitSync {
workItems.forEach(async (workItem) => { await this.updateIssue(config, client, workItem); });
}

async updateIssue(config, client, workItem) {
updateIssue(config, client, workItem) {
log.info(`Updating issue for work item (${workItem.id})...`);
const octokit = new github.getOctokit(config.github.token);
const owner = config.GITHUB_REPOSITORY_OWNER;
const repo = config.GITHUB_REPOSITORY.replace(owner + "/", "");
const converter = new showdown.Converter();

log.debug(`[WORKITEM: ${workItem.id}] Owner:`, owner);
log.debug(`[WORKITEM: ${workItem.id}] Repo:`, repo);

return client.getWorkItem(workItem.id, ["System.Title", "System.Description", "System.State", "System.ChangedDate"]).then(async (wiObj) => {
let parsed = wiObj.fields["System.Title"].match(/^GH\s#(\d+):\s(.*)/);

let issue_number = parsed[1];
log.debug(`[WORKITEM: ${workItem.id} / ISSUE: ${issue_number}] Issue Number:`, issue_number);

Expand All @@ -672,17 +686,18 @@ module.exports = class GitSync {
if (new Date(wiObj.fields["System.ChangedDate"]) > new Date(issue.updated_at)) {
log.debug(`[WORKITEM: ${workItem.id} / ISSUE: ${issue_number}] WorkItem.ChangedDate (${new Date(wiObj.fields["System.ChangedDate"])}) is more recent than Issue.UpdatedAt (${new Date(issue.updated_at)}). Updating issue...`);
let title = parsed[2];
let body = wiObj.fields["System.Description"];
let body = converter.makeMarkdown(wiObj.fields["System.Description"]).replace(/<br>/g, "").trim();

let states = config.ado.states;
let state = Object.keys(states).find(k => states[k]==wiObj.fields["System.State"]);
let state = Object.keys(states).find(k => states[k]===wiObj.fields["System.State"]);

log.debug(`[WORKITEM: ${workItem.id} / ISSUE: ${issue_number}] Title:`, title);
log.debug(`[WORKITEM: ${workItem.id} / ISSUE: ${issue_number}] Body:`, body);
log.debug(`[WORKITEM: ${workItem.id} / ISSUE: ${issue_number}] State:`, state);

if (title != issue.title ||
body != issue.body ||
state != issue.state) {
if (title !== issue.title ||
body !== issue.body ||
state !== issue.state) {

let result = await octokit.rest.issues.update({
owner,
Expand Down
159 changes: 157 additions & 2 deletions gitsync.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ const chai = require('chai');
var sinon = require('sinon');
const assert = chai.assert;
chai.use(require('sinon-chai'));
const proxyquire = require('proxyquire');
const proxyquire = require('proxyquire').noPreserveCache();
const { DateTime } = require('luxon');
const decache = require('decache');

const GitSync = require('./gitsync');

Expand Down Expand Up @@ -2355,6 +2356,8 @@ describe("index", () => {
state: "new"
});
sinon.restore();
decache("./mocks/workItem.json");
decache("./mocks/githubIssue.json");
});

it("should update github issue when AzDO change date is newer than github change date and body is different", async () => {
Expand Down Expand Up @@ -2426,6 +2429,8 @@ describe("index", () => {
state: "new"
});
sinon.restore();
decache("./mocks/workItem.json");
decache("./mocks/githubIssue.json");
});

it("should update github issue when AzDO change date is newer than github change date and state is different", async () => {
Expand Down Expand Up @@ -2499,11 +2504,157 @@ describe("index", () => {
state: "closed"
});
sinon.restore();
decache("./mocks/workItem.json");
decache("./mocks/githubIssue.json");
});

it("should successfully convert html code blocks back to markdown and not update github issue when equal", async () => {
let workItem = require("./mocks/workItemCode.json");
workItem.fields["System.Description"] = "testing<br />" + workItem.fields["System.Description"];
workItem.fields["System.Title"] = "GH #12: Testing title";
let gitHubIssue = require("./mocks/githubIssue.json");
gitHubIssue.data.updated_at = DateTime.fromJSDate(new Date(workItem.fields["System.ChangedDate"])).minus({ days: 5}).toJSDate();
gitHubIssue.data.body = "testing\n\n<pre>public class Foo() {\n var number = 0;\n var text = \"Hello World!\";\n return 0;\n}</pre>";

const stubbedCore = sinon.stub().callsFake();
const stubbedWorkItemTrackingApi = {
getWorkItem: sinon.stub().resolves(workItem)
}
const stubbedIssues = {
get: sinon.stub().resolves(gitHubIssue),
update: sinon.stub().resolves()
}
const proxiedGitSync = proxyquire('./gitsync', {
"@actions/github": {
getOctokit: sinon.stub().returns({
rest: {
issues: stubbedIssues
}
})
},
"@actions/core": {
setFailed: stubbedCore
}
});

let now = Date.now();
let config = {
log_level: 'silent',
ado: {
states: { reopened: "New" },
project: "foo",
bypassRules: true,
wit: "User Story",
states: {
new: "New",
closed: "Closed",
reopened: "New",
deleted: "Removed",
active: "Active"
},
},
closed_at: now,
repository: {
full_name: "foo/bar"
},
label: {
name: "baz"
},
github: {
token: "blah blah"
},
GITHUB_REPOSITORY: "foo/bar",
GITHUB_REPOSITORY_OWNER: "foo"
};

var sync = new proxiedGitSync();
var result = await sync.updateIssue(config, stubbedWorkItemTrackingApi, workItem);

assert.isNull(result);
sinon.assert.notCalled(stubbedIssues.update);
sinon.restore();
decache("./mocks/workItemCode.json");
decache("./mocks/githubIssue.json");
});

it("should successfully convert html code blocks back to markdown and update github issue when not equal", async () => {
let workItem = require("./mocks/workItemCode.json");
workItem.fields["System.Description"] = "testing<br \>some more<br \>" + workItem.fields["System.Description"];
workItem.fields["System.Title"] = "GH #12: Testing title";
let gitHubIssue = require("./mocks/githubIssue.json");
gitHubIssue.data.updated_at = DateTime.fromJSDate(new Date(workItem.fields["System.ChangedDate"])).minus({ days: 5}).toJSDate();
gitHubIssue.data.body = "testing\n<pre>public class Foo() {\n var number = 0;\n var text = \"Hello World!\";\n return 0;\n}</pre>";

const stubbedCore = sinon.stub().callsFake();
const stubbedWorkItemTrackingApi = {
getWorkItem: sinon.stub().resolves(workItem)
}
const stubbedIssues = {
get: sinon.stub().resolves(gitHubIssue),
update: sinon.stub().resolves()
}
const proxiedGitSync = proxyquire('./gitsync', {
"@actions/github": {
getOctokit: sinon.stub().returns({
rest: {
issues: stubbedIssues
}
})
},
"@actions/core": {
setFailed: stubbedCore
}
});

let now = Date.now();
let config = {
log_level: 'silent',
ado: {
states: { reopened: "New" },
project: "foo",
bypassRules: true,
wit: "User Story",
states: {
new: "New",
closed: "Closed",
reopened: "New",
deleted: "Removed",
active: "Active"
},
},
closed_at: now,
repository: {
full_name: "foo/bar"
},
label: {
name: "baz"
},
github: {
token: "blah blah"
},
GITHUB_REPOSITORY: "foo/bar",
GITHUB_REPOSITORY_OWNER: "foo"
};

var sync = new proxiedGitSync();
await sync.updateIssue(config, stubbedWorkItemTrackingApi, workItem);

sinon.assert.calledWith(stubbedIssues.update, {
owner: "foo",
repo: "bar",
issue_number: '12',
title: "Testing title",
body: "testing\n\nsome more\n\n<pre>public class Foo() {\n var number = 0;\n var text = \"Hello World!\";\n return 0;\n}</pre>",
state: "new"
});
sinon.restore();
decache("./mocks/workItemCode.json");
decache("./mocks/githubIssue.json");
});

it("should not update github issue when AzDO change date is newer than github change date but data is the same", async () => {
let workItem = require("./mocks/workItem.json");
workItem.fields["System.Title"] = "GH #12: Testing title";
workItem.fields["System.Title"] = "GH #14: Testing title";
workItem.fields["System.Description"] = "Some body";
workItem.fields["System.State"] = "New";
let gitHubIssue = require("./mocks/githubIssue.json");
Expand Down Expand Up @@ -2566,6 +2717,8 @@ describe("index", () => {
assert.isNull(result);
sinon.assert.notCalled(stubbedIssues.update);
sinon.restore();
decache("./mocks/workItem.json");
decache("./mocks/githubIssue.json");
});

it("should not update github issue when AzDO change date is newer than github change date", async () => {
Expand Down Expand Up @@ -2629,6 +2782,8 @@ describe("index", () => {

assert.isNull(result);
sinon.restore();
decache("./mocks/workItem.json");
decache("./mocks/githubIssue.json");
});
});
});
11 changes: 11 additions & 0 deletions mocks/workItemCode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": 1,
"fields": {
"System.Title": "GH #12: title 1",
"System.Description": "<pre>public class Foo() {\n var number = 0;\n var text = &quot;Hello World!&quot;;\n return 0;\n}</pre>",
"System.WorkItemType": "User Story",
"System.State": "New",
"System.Tags": "GitHub Issue;GitHub Repo: foo/bar;GitHub Label: fiz;GitHub Label: baz;",
"System.ChangedDate": "2020-01-01"
}
}
1 change: 1 addition & 0 deletions node_modules/.bin/acorn

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node_modules/.bin/escodegen

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node_modules/.bin/esgenerate

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3d88d01

Please sign in to comment.