\n
%s
%s %s
\n"
+ % (a["url"], rel, b["url"]))
+ for side in [a, b]:
+ html.write("

\n" % side["screenshot"])
+ url = side["url"]
+ prefix = "/_mozilla/"
+ if url.startswith(prefix):
+ filename = "mozilla/tests/" + url[len(prefix):]
+ else:
+ filename = "web-platform-tests" + url
+ with open(filename, encoding="utf-8") as f:
+ src = html_escape(f.read())
+ html.write("
%s
\n" % src)
+ html.write("\n")
+ html.write("\n")
+
+
+if __name__ == "__main__":
+ sys.exit(main(*sys.argv[1:]))
diff --git a/etc/layout-2020-regressions/prism.css b/etc/layout-2020-regressions/prism.css
new file mode 100644
index 00000000000..6fa6fcc5be6
--- /dev/null
+++ b/etc/layout-2020-regressions/prism.css
@@ -0,0 +1,141 @@
+/* PrismJS 1.19.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+
+code[class*="language-"],
+pre[class*="language-"] {
+ color: black;
+ background: none;
+ text-shadow: 0 1px white;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+ font-size: 1em;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+ line-height: 1.5;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
+ text-shadow: none;
+ background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
+code[class*="language-"]::selection, code[class*="language-"] ::selection {
+ text-shadow: none;
+ background: #b3d4fc;
+}
+
+@media print {
+ code[class*="language-"],
+ pre[class*="language-"] {
+ text-shadow: none;
+ }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+ padding: 1em;
+ margin: .5em 0;
+ overflow: auto;
+}
+
+:not(pre) > code[class*="language-"],
+pre[class*="language-"] {
+ background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre) > code[class*="language-"] {
+ padding: .1em;
+ border-radius: .3em;
+ white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+ color: slategray;
+}
+
+.token.punctuation {
+ color: #999;
+}
+
+.token.namespace {
+ opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+ color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+ color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+ color: #9a6e3a;
+ background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+ color: #07a;
+}
+
+.token.function,
+.token.class-name {
+ color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+ color: #e90;
+}
+
+.token.important,
+.token.bold {
+ font-weight: bold;
+}
+.token.italic {
+ font-style: italic;
+}
+
+.token.entity {
+ cursor: help;
+}
diff --git a/etc/layout-2020-regressions/prism.js b/etc/layout-2020-regressions/prism.js
new file mode 100644
index 00000000000..a43970450d6
--- /dev/null
+++ b/etc/layout-2020-regressions/prism.js
@@ -0,0 +1,7 @@
+/* PrismJS 1.19.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,r=0,C={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(r){return r instanceof _?new _(r.type,e(r.content),r.alias):Array.isArray(r)?r.map(e):r.replace(/&/g,"&").replace(/e.length)return;if(!(k instanceof _)){if(h&&y!=r.length-1){if(c.lastIndex=v,!(S=c.exec(e)))break;for(var b=S.index+(f&&S[1]?S[1].length:0),w=S.index+S[0].length,A=y,P=v,x=r.length;A
"+a.content+""+a.tag+">"},!u.document)return u.addEventListener&&(C.disableWorkerMessageHandler||u.addEventListener("message",function(e){var r=JSON.parse(e.data),n=r.language,t=r.code,a=r.immediateClose;u.postMessage(C.highlight(t,C.languages[n],n)),a&&u.close()},!1)),C;var e=C.util.currentScript();function n(){C.manual||C.highlightAll()}if(e&&(C.filename=e.src,e.hasAttribute("data-manual")&&(C.manual=!0)),!C.manual){var t=document.readyState;"loading"===t||"interactive"===t&&e&&e.defer?document.addEventListener("DOMContentLoaded",n):window.requestAnimationFrame?window.requestAnimationFrame(n):window.setTimeout(n,16)}return C}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
+Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:(?!)*\]\s*)?>/i,greedy:!0},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var n={"included-cdata":{pattern://i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp("(<__[\\s\\S]*?>)(?:\\s*|[\\s\\S])*?(?=<\\/__>)".replace(/__/g,a),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",t)}}),Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
+!function(s){var e=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,lookbehind:!0,alias:"selector"}}},url:{pattern:RegExp("url\\((?:"+e.source+"|[^\n\r()]*)\\)","i"),inside:{function:/^url/i,punctuation:/^\(|\)$/}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+e.source+")*?(?=\\s*\\{)"),string:{pattern:e,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),s.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:t.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:s.languages.css}},alias:"language-css"}},t.tag))}(Prism);
+Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
+Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&|\|\||[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?[.?]?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*[\s\S]*?\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript;
diff --git a/etc/taskcluster/decision_task.py b/etc/taskcluster/decision_task.py
index 575cf841e5b..c5407f66fe7 100644
--- a/etc/taskcluster/decision_task.py
+++ b/etc/taskcluster/decision_task.py
@@ -48,6 +48,7 @@ def tasks(task_for):
],
"master": [
upload_docs,
+ layout_2020_regressions_report,
],
# The "try-*" keys match those in `servo_try_choosers` in Homu’s config:
@@ -186,7 +187,7 @@ def linux_tidy_unit():
./etc/ci/lockfile_changed.sh
./etc/ci/check_no_panic.sh
""")
- .find_or_create("linux_unit." + CONFIG.task_id())
+ .find_or_create("linux_unit." + CONFIG.tree_hash())
)
@@ -216,12 +217,12 @@ def linux_docs_check():
./mach check
""")
.with_artifacts("/repo/target/doc/docs.bundle")
- .find_or_create("docs." + CONFIG.task_id())
+ .find_or_create("docs." + CONFIG.tree_hash())
)
def upload_docs():
- docs_build_task_id = decisionlib.Task.find("docs." + CONFIG.task_id())
+ docs_build_task_id = decisionlib.Task.find("docs." + CONFIG.tree_hash())
return (
linux_task("Upload docs to GitHub Pages")
.with_treeherder("Linux x64", "DocUpload")
@@ -247,6 +248,21 @@ def upload_docs():
)
+def layout_2020_regressions_report():
+ return (
+ linux_task("Layout 2020 regressions report")
+ .with_treeherder("Linux x64", "RegressionsReport")
+ .with_dockerfile(dockerfile_path("base"))
+ .with_repo_bundle()
+ .with_script(
+ "python3 etc/layout-2020-regressions/gen.py %s %s"
+ % (CONFIG.tree_hash(), CONFIG.git_sha)
+ )
+ .with_index_and_artifacts_expire_in(log_artifacts_expire_in)
+ .with_artifacts("/repo/etc/layout-2020-regressions/regressions.html")
+ .find_or_create("layout-2020-regressions-report")
+ )
+
def macos_unit():
return (
macos_build_task("Dev build + unit tests")
@@ -257,7 +273,7 @@ def macos_unit():
./mach package --dev
./etc/ci/lockfile_changed.sh
""")
- .find_or_create("macos_unit." + CONFIG.task_id())
+ .find_or_create("macos_unit." + CONFIG.tree_hash())
)
@@ -302,7 +318,7 @@ def windows_arm64():
"python mach package --dev --target aarch64-uwp-windows-msvc --uwp=arm64",
)
.with_artifacts(appx_artifact(debug=True))
- .find_or_create("build.windows_uwp_arm64_dev." + CONFIG.task_id())
+ .find_or_create("build.windows_uwp_arm64_dev." + CONFIG.tree_hash())
)
@@ -318,7 +334,7 @@ def windows_uwp_x64():
"python mach test-tidy --force-cpp --no-wpt",
)
.with_artifacts(appx_artifact(debug=True))
- .find_or_create("build.windows_uwp_x64_dev." + CONFIG.task_id())
+ .find_or_create("build.windows_uwp_x64_dev." + CONFIG.tree_hash())
)
@@ -339,7 +355,7 @@ def uwp_nightly():
)
.with_artifacts(appx_artifact(debug=False))
.with_max_run_time_minutes(3 * 60)
- .find_or_create("build.windows_uwp_nightlies." + CONFIG.task_id())
+ .find_or_create("build.windows_uwp_nightlies." + CONFIG.tree_hash())
)
@@ -368,7 +384,7 @@ def windows_unit(cached=True):
"repo/target/debug/msi/Servo.zip")
)
if cached:
- return task.find_or_create("build.windows_x64_dev." + CONFIG.task_id())
+ return task.find_or_create("build.windows_x64_dev." + CONFIG.tree_hash())
else:
return task.create()
@@ -385,7 +401,7 @@ def windows_nightly():
"mach upload-nightly windows-msvc --secret-from-taskcluster")
.with_artifacts("repo/target/release/msi/Servo.exe",
"repo/target/release/msi/Servo.zip")
- .find_or_create("build.windows_x64_nightly." + CONFIG.task_id())
+ .find_or_create("build.windows_x64_nightly." + CONFIG.tree_hash())
)
@@ -402,7 +418,7 @@ def linux_nightly():
"./mach upload-nightly linux --secret-from-taskcluster",
)
.with_artifacts("/repo/target/release/servo-tech-demo.tar.gz")
- .find_or_create("build.linux_x64_nightly" + CONFIG.task_id())
+ .find_or_create("build.linux_x64_nightly" + CONFIG.tree_hash())
)
@@ -414,7 +430,7 @@ def linux_release():
"./mach build --release",
"./mach package --release",
)
- .find_or_create("build.linux_x64_release" + CONFIG.task_id())
+ .find_or_create("build.linux_x64_release" + CONFIG.tree_hash())
)
@@ -433,7 +449,7 @@ def macos_nightly():
"./mach upload-nightly mac --secret-from-taskcluster",
)
.with_artifacts("repo/target/release/servo-tech-demo.dmg")
- .find_or_create("build.mac_x64_nightly." + CONFIG.task_id())
+ .find_or_create("build.mac_x64_nightly." + CONFIG.tree_hash())
)
@@ -476,7 +492,7 @@ def macos_release_build_with_debug_assertions(priority=None):
" target/release/build/osmesa-src-*/out/src/mapi/shared-glapi/.libs",
]))
.with_artifacts("repo/target.tar.gz")
- .find_or_create("build.macos_x64_release_w_assertions." + CONFIG.task_id())
+ .find_or_create("build.macos_x64_release_w_assertions." + CONFIG.tree_hash())
)
@@ -508,7 +524,7 @@ def linux_release_build_with_debug_assertions(layout_2020):
.with_artifacts("/target.tar.gz")
.find_or_create("build.linux_x64%s_release_w_assertions.%s" % (
index_key_suffix,
- CONFIG.task_id(),
+ CONFIG.tree_hash(),
))
)
@@ -658,7 +674,7 @@ def wpt_chunks(platform, make_chunk_task, build_task, total_chunks, processes,
platform.replace(" ", "_").lower(),
job_id_prefix.replace("-", "_"),
this_chunk,
- CONFIG.task_id(),
+ CONFIG.tree_hash(),
))
diff --git a/etc/taskcluster/decisionlib.py b/etc/taskcluster/decisionlib.py
index 34cc634e5c2..cb899319ea5 100644
--- a/etc/taskcluster/decisionlib.py
+++ b/etc/taskcluster/decisionlib.py
@@ -64,14 +64,14 @@ class Config:
self.default_provisioner_id = "proj-example"
- def task_id(self):
- if not hasattr(self, "_task_id"):
+ def tree_hash(self):
+ if not hasattr(self, "_tree_hash"):
# Use the SHA-1 hash of the git "tree" object rather than the commit.
# A `@bors-servo retry` command creates a new merge commit with a different commit hash
# but with the same tree hash.
output = subprocess.check_output(["git", "show", "-s", "--format=%T", "HEAD"])
- self._task_id = output.decode("utf-8").strip()
- return self._task_id
+ self._tree_hash = output.decode("utf-8").strip()
+ return self._tree_hash
def git_sha_is_current_head(self):
output = subprocess.check_output(["git", "rev-parse", "HEAD"])