forked from metabase/metabase
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompare-screenshots
executable file
·145 lines (130 loc) · 5.24 KB
/
compare-screenshots
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env babel-node
import fetch from "isomorphic-fetch";
import path from "path";
import fs from "fs-promise"
import imageDiff_ from "image-diff";
import https from "https";
import os from "os";
import { WebClient } from "@slack/client";
const CIRCLECI_TOKEN = process.env["CIRCLECI_TOKEN"];
const SLACK_TOKEN = process.env["SLACK_TOKEN"];
const SLACK_CHANNEL = "#ci-screenshots";
const CIRCLE_PROJECT = "github/metabase/metabase";
const CIRCLE_BRANCH = "master";
const CIRCLE_SCREENSHOT_PATH = "/home/ubuntu/metabase/screenshots/";
const slack = new WebClient(SLACK_TOKEN);
async function circleci(path) {
const response = await fetch(
`https://circleci.com/api/v1.1/${path}?circle-token=${encodeURIComponent(CIRCLECI_TOKEN)}`
);
return response.json();
}
function imageDiff(options) {
return new Promise((resolve, reject) => {
imageDiff_.getFullResult(options, (err, result) =>
err ? reject(err) : resolve(result)
);
});
}
function download(url, path) {
return new Promise((resolve, reject) => {
https.get(url, response => {
response.pipe(fs.createWriteStream(path)).on("finish", resolve);
}).on('error', reject);
});
}
async function getCircleArtifactScreenshots(buildPath) {
let artifacts = await circleci(`project/${buildPath}/artifacts`);
let results = {};
for (const artifact of artifacts) {
if (artifact.pretty_path.startsWith(CIRCLE_SCREENSHOT_PATH)) {
const downloadPath = path.join(os.tmpdir(), path.basename(artifact.pretty_path));
console.log("Downloading ", artifact.url, "to", downloadPath);
await download(artifact.url, downloadPath);
results[artifact.pretty_path.slice(CIRCLE_SCREENSHOT_PATH.length)] = downloadPath;
}
}
return results;
}
async function getLocalScreenshots(directory) {
const filenames = await fs.readdir(directory);
let results = {};
for (const filename of filenames) {
results[filename] = path.resolve(directory, filename);
}
return results;
}
async function getScreenshots(target) {
if (target.circleProject && target.circleBranch) {
let builds = await circleci(`project/${target.circleProject}/tree/${target.circleBranch}`);
let ok = builds.filter(build => build.status === "success" || build.status === "fixed");
let screenshots = await getCircleArtifactScreenshots(`${target.circleProject}/${ok[0].build_num}`);
return screenshots;
} else if (target.localDirectory) {
return await getLocalScreenshots(target.localDirectory);
} else {
throw "unknown target type";
}
}
async function run(expectedTarget, actualTarget) {
try {
const expectedScreenshots = await getScreenshots(expectedTarget);
console.log("Expected", Object.keys(expectedScreenshots));
const actualScreenshots = await getScreenshots(actualTarget);
console.log("Actual", Object.keys(expectedScreenshots));
let images = Object.keys({ ...expectedScreenshots, ...actualScreenshots });
for (const image of images) {
const expectedImage = expectedScreenshots[image];
const actualImage = actualScreenshots[image];
const diffImage = path.join(os.tmpdir(), "diff-"+image);
if (!actualImage) {
console.log("Added", image);
await slack.files.upload(image, {
title: "Added " + image,
channels: [SLACK_CHANNEL],
file: fs.createReadStream(actualImage)
});
} else if (!expectedImage) {
console.log("Removed", image);
await slack.files.upload(image, {
title: "Removed " + image,
channels: [SLACK_CHANNEL],
file: fs.createReadStream(expectedImage)
});
} else {
const result = await imageDiff({
expectedImage,
actualImage,
diffImage,
shadow: true
})
if (result.percentage === 0.0) {
console.log("No difference", image);
} else {
console.log("Changed", result.percentage.toFixed(2), image);
await slack.files.upload(image, {
title: "Diff (" + result.percentage.toFixed(2) + ") " + image,
channels: [SLACK_CHANNEL],
file: fs.createReadStream(diffImage)
});
await slack.files.upload(image, {
title: "Expected " + image,
channels: [SLACK_CHANNEL],
file: fs.createReadStream(expectedImage)
});
await slack.files.upload(image, {
title: "Actual " + image,
channels: [SLACK_CHANNEL],
file: fs.createReadStream(actualImage)
});
}
}
}
} catch (e) {
console.error(e);
}
}
run(
{ circleProject: CIRCLE_PROJECT, circleBranch: CIRCLE_BRANCH },
{ localDirectory: "screenshots" }
);