[bcl] Add API diff targets (#4406)
authorAlexander Köplinger <alex.koeplinger@outlook.com>
Fri, 28 Apr 2017 18:28:32 +0000 (20:28 +0200)
committerGitHub <noreply@github.com>
Fri, 28 Apr 2017 18:28:32 +0000 (20:28 +0200)
With these targets we can generate a snapshot of the current
Mono API in C# source code form.

Whenever we make changes, we can rerun this to ensure we didn't
inadvertently change the public API.

It also outputs a diff in html form that we can show on CI.

.gitmodules
external/api-snapshot [new submodule]
mcs/.gitignore
mcs/Makefile
mcs/class/Facades/subdirs.make
mcs/diff.html.in [new file with mode: 0644]
scripts/ci/run-test-default.sh
scripts/ci/util.sh [new file with mode: 0644]

index 52dd2e7d5b2e23bfad4e2868ab9848bdf5c77650..73d55a0a9b903a2f261f9a60b0dfee03b66f0a3c 100644 (file)
@@ -58,3 +58,6 @@
 [submodule "external/api-doc-tools"]
        path = external/api-doc-tools
        url = git://github.com/mono/api-doc-tools.git
+[submodule "external/api-snapshot"]
+       path = external/api-snapshot
+       url = git://github.com/mono/api-snapshot.git
diff --git a/external/api-snapshot b/external/api-snapshot
new file mode 160000 (submodule)
index 0000000..d6eb25e
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d6eb25eb492847b8c2634d0b01829a17e6226258
index 95c3b1615e6d84a226ad253408dfe4c87aa3ca62..ac21fbc31e58122816e8f9194fdf215b1cba8d95 100644 (file)
@@ -11,6 +11,7 @@ TestResult-*.log
 TestResult-*.xml
 TestResult*.xml
 .dep_dirs-*
+apidiff/*
 errors/*.log
 errors/dummy.xml
 class/Mono.Data.Sqlite/test.db
index 54cb4574e240760f8eaf3545bd4bd76021132c3f..eeda3d38bbea49e906b809faf5ab43ec719e8d04 100644 (file)
@@ -159,3 +159,29 @@ monocharge-lite:
        $(MAKE) -C class/Mono.CSharp.Debugger install DESTDIR="$$DESTDIR" || exit 1; \
        tar cvjf "$$chargedir".tar.bz2 "$$chargedir" ; \
        rm -rf "$$chargedir"
+
+# Targets for creating API diffs of the framework
+
+MONO_API_SNAPSHOT_PATH := $(topdir)../external/api-snapshot/
+GENAPI := $(MONO_API_SNAPSHOT_PATH)tools/genapi/GenAPI.exe
+MONO_API_SNAPSHOT_PROFILE_PATH := $(MONO_API_SNAPSHOT_PATH)profiles/$(PROFILE)/
+MONO_API_ASSEMBLIES_IGNORED := $(addprefix $(topdir)class/lib/$(PROFILE)/, SystemWebTestShim.dll standalone-runner-support.dll nunit.core.dll nunit.core.extensions.dll nunit.core.interfaces.dll nunit.framework.dll nunit.framework.extensions.dll nunit.mocks.dll nunit.util.dll nunit-console-runner.dll nunitlite.dll)
+MONO_API_ASSEMBLIES := $(filter-out $(MONO_API_ASSEMBLIES_IGNORED), $(wildcard $(topdir)class/lib/$(PROFILE)/*.dll)) $(wildcard $(topdir)class/lib/$(PROFILE)/Facades/*.dll)
+MONO_API_ASSEMBLIES_CS := $(MONO_API_ASSEMBLIES:$(topdir)class/lib/$(PROFILE)/%.dll=$(MONO_API_SNAPSHOT_PROFILE_PATH)%.cs)
+
+$(MONO_API_SNAPSHOT_PROFILE_PATH)%.cs: $(topdir)class/lib/$(PROFILE)/%.dll $(GENAPI) $(MONO_API_SNAPSHOT_PATH)profiles/license-header.txt
+       @mkdir -p $(dir $@)
+       $(Q) MONO_PATH=$(topdir)class/lib/$(BUILD_TOOLS_PROFILE) $(RUNTIME) $(GENAPI) -libPath:$(topdir)class/lib/$(PROFILE),$(topdir)class/lib/$(PROFILE)/Facades -out:$(dir $@) -headerFile:$(MONO_API_SNAPSHOT_PATH)profiles/license-header.txt -assemblyAttributes -typeForwardedTo -assemblyVersion -assembly:$< || echo "Couldn't process assembly." > $@
+
+mono-api-current: $(MONO_API_ASSEMBLIES_CS)
+
+mono-api-diff:
+       @echo "Regenerating API snapshot..."
+       $(Q) rm -rf "$(MONO_API_SNAPSHOT_PROFILE_PATH)"
+       $(Q) $(MAKE) mono-api-current
+       @echo "Checking public API differences..."
+       $(Q) cd $(MONO_API_SNAPSHOT_PATH); git add -A .
+       $(Q) cd $(MONO_API_SNAPSHOT_PATH); git diff --no-renames HEAD > $(abspath $(topdir))/temp.patch
+       @mkdir -p apidiff
+       $(Q) sed -e "/@diffdata@/r temp.patch" -e "/@diffdata@/d" -e "s/@title@/Public API Diff/g" -e "s/@description@/If the changes are intentional, run <code>make -C mcs mono-api-diff<\/code> locally and commit changes in external\/api-snapshot./g" diff.html.in > apidiff/index.html
+       $(Q) if [ -s temp.patch ]; then echo "Error: Found public API differences, see mcs/apidiff/index.html. If the changes are intentional, please go to external/api-snapshot and commit them."; rm -f temp.patch; exit 1; else echo "No differences found."; rm -f temp.patch; fi
index b21f1cda4747b0715220249b2d8e782cb3c6ba77..d1dd9c4f6b98115dcdf049f431fbcdfb61a57f34 100644 (file)
@@ -60,7 +60,7 @@ System.Runtime.Numerics System.Xml.XDocument System.Reflection.Extensions System
 System.Diagnostics.FileVersionInfo System.Security.Cryptography.Primitives System.Security.Cryptography.Algorithms System.ValueTuple \
 System.Text.Encoding.CodePages
 
-build_PARALLEL_SUBDIRS = $(basic_PARALLEL_SUBDIRS)
+build_PARALLEL_SUBDIRS = $(basic_PARALLEL_SUBDIRS) System.Text.RegularExpressions System.Diagnostics.Contracts
 
 monodroid_SUBDIRS = $(monotouch_SUBDIRS)
 monodroid_PARALLEL_SUBDIRS = $(monotouch_PARALLEL_SUBDIRS)
diff --git a/mcs/diff.html.in b/mcs/diff.html.in
new file mode 100644 (file)
index 0000000..370a279
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" />
+    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
+    <title>@title@</title>
+    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/github.min.css">
+    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.3.0/diff2html.min.css">
+    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Open+Sans' />
+  </head>
+  <body style="font-family: 'Open Sans'">
+    <h1>@title@</h1>
+    <p>@description@</p>
+    <div id="diff"><!--<![CDATA[
+@diffdata@
+]]>-->
+    </div>
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/highlight.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/languages/cs.min.js"></script>
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.3.0/diff2html.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.3.0/diff2html-ui.min.js"></script>
+
+    <script>
+    $(document).ready(function() {
+        var diff2htmlUi = new Diff2HtmlUI({diff: $("#diff")[0].childNodes[0].nodeValue});
+        diff2htmlUi.draw('#diff', {showFiles: true, matching: 'lines'});
+        diff2htmlUi.highlightCode('#diff');
+    });
+    </script>
+  </body>
+</html>
index 2e7c807d924477595bac23801ed61ab09b77f99c..9b418f5adc0b1eacd6c4cf2b35858c121a5cef7e 100755 (executable)
@@ -97,4 +97,12 @@ if [[ ${label} == osx-* ]]
 then ${TESTCMD} --label=ms-test-suite --timeout=30m make -w -C acceptance-tests check-ms-test-suite
 else ${TESTCMD} --label=ms-test-suite --skip;
 fi
+if [[ ${label} == 'ubuntu-1404-amd64' ]]; then
+    source ${MONO_REPO_ROOT}/scripts/ci/util.sh
+    if ${TESTCMD} --label=apidiff --timeout=15m --fatal make -w -C mcs -j4 mono-api-diff
+    then report_github_status "success" "API Diff" "No public API changes found."
+    else report_github_status "error" "API Diff" "The public API changed." "$BUILD_URL/Public_API_Diff/"
+    fi
+else ${TESTCMD} --label=apidiff --skip
+fi
 rm -fr /tmp/jenkins-temp-aspnet*
diff --git a/scripts/ci/util.sh b/scripts/ci/util.sh
new file mode 100644 (file)
index 0000000..d4b09e8
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash -e
+
+function report_github_status {
+    if [ -z "$1" ]; then echo "No status specified. Skipping GitHub manual status report."; return 1; fi;
+    if [ -z "$2" ]; then echo "No context specified. Skipping GitHub manual status report."; return 1; fi;
+    if [ -z "$3" ]; then echo "No description specified. Skipping GitHub manual status report."; return 1; fi;
+    if [ -z "${ghprbActualCommit}" ]; then echo "Not a pull request. Skipping GitHub manual status report."; return 1; fi;
+    if [ -z "${GITHUB_STATUS_AUTH_TOKEN}" ]; then echo "No auth token specified. Skipping GitHub manual status report."; return 1; fi;
+
+    wget -qO- --header "Content-Type: application/json" --post-data "{\"state\": \"$1\", \"context\":\"$2\", \"description\": \"$3\", \"target_url\": \"$4\"}" "https://api.github.com/repos/mono/mono/statuses/${ghprbActualCommit}?access_token=${GITHUB_STATUS_AUTH_TOKEN}"
+}