[v2,06/13] Add a build definition for Azure DevOps
diff mbox series

Message ID 1a22efe849d6da79f2c639c62a1483361a130238.1539598316.git.gitgitgadget@gmail.com
State New
Headers show
Series
  • Offer to run CI/PR builds in Azure Pipelines
Related show

Commit Message

Mikhail Terekhov via GitGitGadget Oct. 15, 2018, 10:12 a.m. UTC
From: Johannes Schindelin <johannes.schindelin@gmx.de>

This commit adds an azure-pipelines.yml file which is Azure DevOps'
equivalent to Travis CI's .travis.yml.

To make things a bit easier to understand, we refrain from using the
`matrix` feature here because (while it is powerful) it can be a bit
confusing to users who are not familiar with CI setups. Therefore, we
use a separate phase even for similar configurations (such as GCC vs
Clang on Linux, GCC vs Clang on macOS).

Also, we make use of the shiny new feature we just introduced where the
test suite can output JUnit-style .xml files. This information is made
available in a nice UI that allows the viewer to filter by phase and/or
test number, and to see trends such as: number of (failing) tests, time
spent running the test suite, etc.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 azure-pipelines.yml   | 319 ++++++++++++++++++++++++++++++++++++++++++
 ci/mount-fileshare.sh |  26 ++++
 2 files changed, 345 insertions(+)
 create mode 100644 azure-pipelines.yml
 create mode 100755 ci/mount-fileshare.sh

Comments

Junio C Hamano Oct. 16, 2018, 5:35 a.m. UTC | #1
"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> Also, we make use of the shiny new feature we just introduced where the
> test suite can output JUnit-style .xml files. This information is made
> available in a nice UI that allows the viewer to filter by phase and/or
> test number, and to see trends such as: number of (failing) tests, time
> spent running the test suite, etc.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  azure-pipelines.yml   | 319 ++++++++++++++++++++++++++++++++++++++++++
>  ci/mount-fileshare.sh |  26 ++++
>  2 files changed, 345 insertions(+)
>  create mode 100644 azure-pipelines.yml
>  create mode 100755 ci/mount-fileshare.sh

I wonder if there is a need to keep what is tested by this and
Travis in sync in any way, but most of the logic is not defined in
these "steps" but implemented in ci/*.sh scripts to be shared, so it
would be OK, I guess.

> diff --git a/ci/mount-fileshare.sh b/ci/mount-fileshare.sh
> new file mode 100755
> index 0000000000..5fb5f74b70
> --- /dev/null
> +++ b/ci/mount-fileshare.sh
> @@ -0,0 +1,26 @@
> +#!/bin/sh
> +
> +die () {
> +	echo "$*" >&2
> +	exit 1
> +}
> +
> +test $# = 4 ||
> +die "Usage: $0 <share> <username> <password> <mountpoint"

Missing closing '>'.

> +
> +mkdir -p "$4" || die "Could not create $4"
> +
> +case "$(uname -s)" in
> +Linux)
> +	sudo mount -t cifs -o vers=3.0,username="$2",password="$3",dir_mode=0777,file_mode=0777,serverino "$1" "$4"
> +	;;
> +Darwin)
> +	pass="$(echo "$3" | sed -e 's/\//%2F/g' -e 's/+/%2B/g')" &&
> +	mount -t smbfs,soft "smb://$2:$pass@${1#//}" "$4"
> +	;;
> +*)
> +	die "No support for $(uname -s)"
> +	;;
> +esac ||
> +die "Could not mount $4"
> +

Trailing blank line.

Thanks.
Johannes Schindelin Oct. 16, 2018, 9:58 a.m. UTC | #2
Hi Junio,

On Tue, 16 Oct 2018, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
> 
> > Also, we make use of the shiny new feature we just introduced where the
> > test suite can output JUnit-style .xml files. This information is made
> > available in a nice UI that allows the viewer to filter by phase and/or
> > test number, and to see trends such as: number of (failing) tests, time
> > spent running the test suite, etc.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  azure-pipelines.yml   | 319 ++++++++++++++++++++++++++++++++++++++++++
> >  ci/mount-fileshare.sh |  26 ++++
> >  2 files changed, 345 insertions(+)
> >  create mode 100644 azure-pipelines.yml
> >  create mode 100755 ci/mount-fileshare.sh
> 
> I wonder if there is a need to keep what is tested by this and
> Travis in sync in any way, but most of the logic is not defined in
> these "steps" but implemented in ci/*.sh scripts to be shared, so it
> would be OK, I guess.

Indeed, that was my intention.

These ci scripts are not only useful for Travis and Azure Pipelines, after
all, but also a good documentation how to test locally. For example, to
repeat Luke's Perforce testing, I could simply use the URLs listed in
those ci scripts to get almost the same setup locally (close enough for
testing).

So it is not only about sharing, and ease of maintenance, but it is also
about documenting.

And yes, sharing means that we do not have to waste brain cycles on
keeping things in sync.

> > diff --git a/ci/mount-fileshare.sh b/ci/mount-fileshare.sh
> > new file mode 100755
> > index 0000000000..5fb5f74b70
> > --- /dev/null
> > +++ b/ci/mount-fileshare.sh
> > @@ -0,0 +1,26 @@
> > +#!/bin/sh
> > +
> > +die () {
> > +	echo "$*" >&2
> > +	exit 1
> > +}
> > +
> > +test $# = 4 ||
> > +die "Usage: $0 <share> <username> <password> <mountpoint"
> 
> Missing closing '>'.

Thanks!

> > +
> > +mkdir -p "$4" || die "Could not create $4"
> > +
> > +case "$(uname -s)" in
> > +Linux)
> > +	sudo mount -t cifs -o vers=3.0,username="$2",password="$3",dir_mode=0777,file_mode=0777,serverino "$1" "$4"
> > +	;;
> > +Darwin)
> > +	pass="$(echo "$3" | sed -e 's/\//%2F/g' -e 's/+/%2B/g')" &&
> > +	mount -t smbfs,soft "smb://$2:$pass@${1#//}" "$4"
> > +	;;
> > +*)
> > +	die "No support for $(uname -s)"
> > +	;;
> > +esac ||
> > +die "Could not mount $4"
> > +
> 
> Trailing blank line.
> 
> Thanks.

Thank you, both issues will be fixed in the next iteration,
Dscho
SZEDER Gábor Oct. 16, 2018, 7:12 p.m. UTC | #3
On Mon, Oct 15, 2018 at 03:12:06AM -0700, Johannes Schindelin via GitGitGadget wrote:
> diff --git a/azure-pipelines.yml b/azure-pipelines.yml
> new file mode 100644
> index 0000000000..b5749121d2
> --- /dev/null
> +++ b/azure-pipelines.yml
> @@ -0,0 +1,319 @@
> +resources:
> +- repo: self
> +  fetchDepth: 1
> +
> +phases:
> +- phase: linux_clang
> +  displayName: linux-clang
> +  condition: succeeded()
> +  queue:
> +    name: Hosted Ubuntu 1604
> +  steps:
> +  - bash: |
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> +
> +       sudo apt-get update &&
> +       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin &&
> +
> +       export CC=clang || exit 1
> +
> +       ci/install-dependencies.sh

I think you would want to 'exit 1' when this script fails.
This applies to other build jobs (erm, phases?) below as well.

> +       ci/run-build-and-tests.sh || {
> +           ci/print-test-failures.sh
> +           exit 1
> +       }
> +
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
> +    displayName: 'ci/run-build-and-tests.sh'
> +    env:
> +      GITFILESHAREPWD: $(gitfileshare.pwd)
> +  - task: PublishTestResults@2
> +    displayName: 'Publish Test Results **/TEST-*.xml'
> +    inputs:
> +      mergeTestResults: true
> +      testRunTitle: 'linux-clang'
> +      platform: Linux
> +      publishRunAttachments: false
> +    condition: succeededOrFailed()
> +
> +- phase: linux_gcc
> +  displayName: linux-gcc
> +  condition: succeeded()
> +  queue:
> +    name: Hosted Ubuntu 1604
> +  steps:
> +  - bash: |
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> +
> +       sudo apt-get update &&
> +       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin || exit 1
> +

On Travis CI the Linux GCC build job uses gcc-8 instead of whatever
the default is in that old-ish Ubuntu LTS; see 37fa4b3c78 (travis-ci:
run gcc-8 on linux-gcc jobs, 2018-05-19).

> +       ci/install-dependencies.sh
> +       ci/run-build-and-tests.sh || {
> +           ci/print-test-failures.sh
> +           exit 1
> +       }
> +
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
> +    displayName: 'ci/run-build-and-tests.sh'
> +    env:
> +      GITFILESHAREPWD: $(gitfileshare.pwd)
> +  - task: PublishTestResults@2
> +    displayName: 'Publish Test Results **/TEST-*.xml'
> +    inputs:
> +      mergeTestResults: true
> +      testRunTitle: 'linux-gcc'
> +      platform: Linux
> +      publishRunAttachments: false
> +    condition: succeededOrFailed()
> +
> +- phase: osx_clang
> +  displayName: osx-clang
> +  condition: succeeded()
> +  queue:
> +    name: Hosted macOS
> +  steps:
> +  - bash: |
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> +
> +       export CC=clang
> +
> +       ci/install-dependencies.sh
> +       ci/run-build-and-tests.sh || {
> +           ci/print-test-failures.sh
> +           exit 1
> +       }
> +
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
> +    displayName: 'ci/run-build-and-tests.sh'
> +    env:
> +      GITFILESHAREPWD: $(gitfileshare.pwd)
> +  - task: PublishTestResults@2
> +    displayName: 'Publish Test Results **/TEST-*.xml'
> +    inputs:
> +      mergeTestResults: true
> +      testRunTitle: 'osx-clang'
> +      platform: macOS
> +      publishRunAttachments: false
> +    condition: succeededOrFailed()
> +
> +- phase: osx_gcc
> +  displayName: osx-gcc
> +  condition: succeeded()
> +  queue:
> +    name: Hosted macOS
> +  steps:
> +  - bash: |
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> +

Here you should 'export CC=gcc', because on macOS 'cc' is 'clang' by
default.

Note, however, that setting 'CC' in the environment alone has no
effect on the build process, it will still use 'cc'.  Keep an eye on
where this thread will lead to:

  https://public-inbox.org/git/20181016184537.GN19800@szeder.dev/T/#u

> +       ci/install-dependencies.sh
> +       ci/run-build-and-tests.sh || {
> +           ci/print-test-failures.sh
> +           exit 1
> +       }
> +
> +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
> +    displayName: 'ci/run-build-and-tests.sh'
> +    env:
> +      GITFILESHAREPWD: $(gitfileshare.pwd)
> +  - task: PublishTestResults@2
> +    displayName: 'Publish Test Results **/TEST-*.xml'
> +    inputs:
> +      mergeTestResults: true
> +      testRunTitle: 'osx-gcc'
> +      platform: macOS
> +      publishRunAttachments: false
> +    condition: succeededOrFailed()
> +
Johannes Schindelin Oct. 17, 2018, 2:58 p.m. UTC | #4
Hi Gábor,

On Tue, 16 Oct 2018, SZEDER Gábor wrote:

> On Mon, Oct 15, 2018 at 03:12:06AM -0700, Johannes Schindelin via GitGitGadget wrote:
> > diff --git a/azure-pipelines.yml b/azure-pipelines.yml
> > new file mode 100644
> > index 0000000000..b5749121d2
> > --- /dev/null
> > +++ b/azure-pipelines.yml
> > @@ -0,0 +1,319 @@
> > +resources:
> > +- repo: self
> > +  fetchDepth: 1
> > +
> > +phases:
> > +- phase: linux_clang
> > +  displayName: linux-clang
> > +  condition: succeeded()
> > +  queue:
> > +    name: Hosted Ubuntu 1604
> > +  steps:
> > +  - bash: |
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> > +
> > +       sudo apt-get update &&
> > +       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin &&
> > +
> > +       export CC=clang || exit 1
> > +
> > +       ci/install-dependencies.sh
> 
> I think you would want to 'exit 1' when this script fails.
> This applies to other build jobs (erm, phases?) below as well.

True.

FWIW the nomenclature is "build" or "job" or "build job" for the entire
run, from what I understand. The "phase" is the individual chunk that is
run in an individual agent, i.e. you can have a single job running test on
different OSes in separate phases.

> > +       ci/run-build-and-tests.sh || {
> > +           ci/print-test-failures.sh
> > +           exit 1
> > +       }
> > +
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
> > +    displayName: 'ci/run-build-and-tests.sh'
> > +    env:
> > +      GITFILESHAREPWD: $(gitfileshare.pwd)
> > +  - task: PublishTestResults@2
> > +    displayName: 'Publish Test Results **/TEST-*.xml'
> > +    inputs:
> > +      mergeTestResults: true
> > +      testRunTitle: 'linux-clang'
> > +      platform: Linux
> > +      publishRunAttachments: false
> > +    condition: succeededOrFailed()
> > +
> > +- phase: linux_gcc
> > +  displayName: linux-gcc
> > +  condition: succeeded()
> > +  queue:
> > +    name: Hosted Ubuntu 1604
> > +  steps:
> > +  - bash: |
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> > +
> > +       sudo apt-get update &&
> > +       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin || exit 1
> > +
> 
> On Travis CI the Linux GCC build job uses gcc-8 instead of whatever
> the default is in that old-ish Ubuntu LTS; see 37fa4b3c78 (travis-ci:
> run gcc-8 on linux-gcc jobs, 2018-05-19).

I'll add those dependencies explicitly. It does seem, however, from a
cursory look at the log, that gcc-8 should not even be picked up, as it is
set via the environment variable `CC` (which, as you point out in
below-referenced thread, is not respected):

[...]
2018-10-16T10:00:36.0177072Z ++ '[' linux-gcc = linux-gcc ']'
2018-10-16T10:00:36.0177380Z ++ export CC=gcc-8
2018-10-16T10:00:36.0177630Z ++ CC=gcc-8
2018-10-16T10:00:36.0177917Z ++ case "$jobname"
[...]

(see https://dev.azure.com/git/git/_build/results?buildId=192&view=logs)

> > +       ci/install-dependencies.sh
> > +       ci/run-build-and-tests.sh || {
> > +           ci/print-test-failures.sh
> > +           exit 1
> > +       }
> > +
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
> > +    displayName: 'ci/run-build-and-tests.sh'
> > +    env:
> > +      GITFILESHAREPWD: $(gitfileshare.pwd)
> > +  - task: PublishTestResults@2
> > +    displayName: 'Publish Test Results **/TEST-*.xml'
> > +    inputs:
> > +      mergeTestResults: true
> > +      testRunTitle: 'linux-gcc'
> > +      platform: Linux
> > +      publishRunAttachments: false
> > +    condition: succeededOrFailed()
> > +
> > +- phase: osx_clang
> > +  displayName: osx-clang
> > +  condition: succeeded()
> > +  queue:
> > +    name: Hosted macOS
> > +  steps:
> > +  - bash: |
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> > +
> > +       export CC=clang
> > +
> > +       ci/install-dependencies.sh
> > +       ci/run-build-and-tests.sh || {
> > +           ci/print-test-failures.sh
> > +           exit 1
> > +       }
> > +
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
> > +    displayName: 'ci/run-build-and-tests.sh'
> > +    env:
> > +      GITFILESHAREPWD: $(gitfileshare.pwd)
> > +  - task: PublishTestResults@2
> > +    displayName: 'Publish Test Results **/TEST-*.xml'
> > +    inputs:
> > +      mergeTestResults: true
> > +      testRunTitle: 'osx-clang'
> > +      platform: macOS
> > +      publishRunAttachments: false
> > +    condition: succeededOrFailed()
> > +
> > +- phase: osx_gcc
> > +  displayName: osx-gcc
> > +  condition: succeeded()
> > +  queue:
> > +    name: Hosted macOS
> > +  steps:
> > +  - bash: |
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
> > +
> 
> Here you should 'export CC=gcc', because on macOS 'cc' is 'clang' by
> default.
> 
> Note, however, that setting 'CC' in the environment alone has no
> effect on the build process, it will still use 'cc'.  Keep an eye on
> where this thread will lead to:
> 
>   https://public-inbox.org/git/20181016184537.GN19800@szeder.dev/T/#u

Will do.

Thanks,
Dscho

> 
> > +       ci/install-dependencies.sh
> > +       ci/run-build-and-tests.sh || {
> > +           ci/print-test-failures.sh
> > +           exit 1
> > +       }
> > +
> > +       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
> > +    displayName: 'ci/run-build-and-tests.sh'
> > +    env:
> > +      GITFILESHAREPWD: $(gitfileshare.pwd)
> > +  - task: PublishTestResults@2
> > +    displayName: 'Publish Test Results **/TEST-*.xml'
> > +    inputs:
> > +      mergeTestResults: true
> > +      testRunTitle: 'osx-gcc'
> > +      platform: macOS
> > +      publishRunAttachments: false
> > +    condition: succeededOrFailed()
> > +
>

Patch
diff mbox series

diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 0000000000..b5749121d2
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,319 @@ 
+resources:
+- repo: self
+  fetchDepth: 1
+
+phases:
+- phase: linux_clang
+  displayName: linux-clang
+  condition: succeeded()
+  queue:
+    name: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin &&
+
+       export CC=clang || exit 1
+
+       ci/install-dependencies.sh
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'linux-clang'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: linux_gcc
+  displayName: linux-gcc
+  condition: succeeded()
+  queue:
+    name: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin || exit 1
+
+       ci/install-dependencies.sh
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'linux-gcc'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: osx_clang
+  displayName: osx-clang
+  condition: succeeded()
+  queue:
+    name: Hosted macOS
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       export CC=clang
+
+       ci/install-dependencies.sh
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'osx-clang'
+      platform: macOS
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: osx_gcc
+  displayName: osx-gcc
+  condition: succeeded()
+  queue:
+    name: Hosted macOS
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       ci/install-dependencies.sh
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'osx-gcc'
+      platform: macOS
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: gettext_poison
+  displayName: GETTEXT_POISON
+  condition: succeeded()
+  queue:
+    name: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev &&
+
+       export jobname=GETTEXT_POISON || exit 1
+
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'gettext-poison'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: windows
+  displayName: Windows
+  condition: succeeded()
+  queue:
+    name: Hosted VS2017
+    timeoutInMinutes: 240
+  steps:
+  - powershell: |
+       # Helper to check the error level of the latest command (exit with error when appropriate)
+       function c() { if (!$?) { exit(1) } }
+
+       if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
+         net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no; c
+         cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\; c
+       }
+
+       # Add build agent's MinGit to PATH
+       $env:PATH = $env:AGENT_HOMEDIRECTORY +"\externals\\git\cmd;" +$env:PATH
+
+       # Helper to initialize (or update) a Git worktree
+       function init ($path, $url, $set_origin) {
+           if (Test-Path $path) {
+               cd $path; c
+               if (Test-Path .git) {
+                   git init; c
+               } else {
+                   git status
+               }
+           } else {
+               git init $path; c
+               cd $path; c
+           }
+           git config core.autocrlf false; c
+           git config core.untrackedCache true; c
+           if (($set_origin -ne 0) -and !(git config remote.origin.url)) {
+               git remote add origin $url; c
+           }
+           git fetch --depth=1 $url master; c
+           git reset --hard FETCH_HEAD; c
+           git clean -df; c
+       }
+
+       # Initialize Git for Windows' SDK
+       $sdk_path = "$(Build.SourcesDirectory)\git-sdk-64"
+       init "$sdk_path" "https://dev.azure.com/git-for-windows/git-sdk-64/_git/git-sdk-64" 0
+       init usr\src\build-extra https://github.com/git-for-windows/build-extra 1
+
+       cd "$(Build.SourcesDirectory)"; c
+
+       $env:HOME = "$(Build.SourcesDirectory)"
+       $env:MSYSTEM = "MINGW64"
+       git-sdk-64\git-cmd --command=usr\\bin\\bash.exe -lc @"
+         . ci/lib.sh
+
+         make -j10 DEVELOPER=1 NO_PERL=1 || exit 1
+         NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"--quiet --write-junit-xml\" time make -j15 -k DEVELOPER=1 test || {
+           NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"-i -v -x\" make -k -C t failed; exit 1
+         }
+
+         save_good_tree
+       "@
+       c
+
+       if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
+         cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
+       }
+    displayName: 'build & test'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'windows'
+      platform: Windows
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: linux32
+  displayName: Linux32
+  condition: succeeded()
+  queue:
+    name: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get -y install \
+           apt-transport-https \
+           ca-certificates \
+           curl \
+           software-properties-common &&
+       curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &&
+       sudo add-apt-repository \
+          "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
+          $(lsb_release -cs) \
+          stable" &&
+       sudo apt-get update &&
+       sudo apt-get -y install docker-ce &&
+
+       sudo AGENT_OS="$AGENT_OS" BUILD_BUILDNUMBER="$BUILD_BUILDNUMBER" BUILD_REPOSITORY_URI="$BUILD_REPOSITORY_URI" BUILD_SOURCEBRANCH="$BUILD_SOURCEBRANCH" BUILD_SOURCEVERSION="$BUILD_SOURCEVERSION" SYSTEM_PHASENAME="$SYSTEM_PHASENAME" SYSTEM_TASKDEFINITIONSURI="$SYSTEM_TASKDEFINITIONSURI" SYSTEM_TEAMPROJECT="$SYSTEM_TEAMPROJECT" CC=$CC MAKEFLAGS=-j3 bash -lxc ci/run-linux32-docker.sh || exit 1
+
+       sudo chmod a+r t/out/TEST-*.xml
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-linux32-docker.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'linux32'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+
+- phase: static_analysis
+  displayName: StaticAnalysis
+  condition: succeeded()
+  queue:
+    name: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get install -y coccinelle &&
+
+       export jobname=StaticAnalysis &&
+
+       ci/run-static-analysis.sh || exit 1
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-static-analysis.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+
+- phase: documentation
+  displayName: Documentation
+  condition: succeeded()
+  queue:
+    name: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get install -y asciidoc xmlto asciidoctor &&
+
+       export ALREADY_HAVE_ASCIIDOCTOR=yes. &&
+       export jobname=Documentation &&
+
+       ci/test-documentation.sh || exit 1
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/test-documentation.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
diff --git a/ci/mount-fileshare.sh b/ci/mount-fileshare.sh
new file mode 100755
index 0000000000..5fb5f74b70
--- /dev/null
+++ b/ci/mount-fileshare.sh
@@ -0,0 +1,26 @@ 
+#!/bin/sh
+
+die () {
+	echo "$*" >&2
+	exit 1
+}
+
+test $# = 4 ||
+die "Usage: $0 <share> <username> <password> <mountpoint"
+
+mkdir -p "$4" || die "Could not create $4"
+
+case "$(uname -s)" in
+Linux)
+	sudo mount -t cifs -o vers=3.0,username="$2",password="$3",dir_mode=0777,file_mode=0777,serverino "$1" "$4"
+	;;
+Darwin)
+	pass="$(echo "$3" | sed -e 's/\//%2F/g' -e 's/+/%2B/g')" &&
+	mount -t smbfs,soft "smb://$2:$pass@${1#//}" "$4"
+	;;
+*)
+	die "No support for $(uname -s)"
+	;;
+esac ||
+die "Could not mount $4"
+