From 1e67d0a167c6dd462db8f4c183664c119d8d2b4b Mon Sep 17 00:00:00 2001 From: Nathan Brown Date: Fri, 6 Oct 2017 09:15:12 -0700 Subject: [PATCH] NH-3807 - Develop AppVeyor and CircleCI builds. - Allow failure for MySQL. - Include TestLoggers. - Exclude committed directories to Tools folder from being deleted. --- .circleci/config.yml | 137 ++++++++++ .../nhibernate-build-dotnet-sdk/Dockerfile | 50 ++++ .../nhibernate-build-firebird/Dockerfile | 25 ++ .../nhibernate-build-firebird/README.md | 67 +++++ .../images/nhibernate-build-firebird/build.sh | 64 +++++ .../docker-entrypoint.sh | 128 +++++++++ Tools/.gitignore | 3 + Tools/packages.config | 1 + appveyor.yml | 103 +++++++ build.cake | 251 ++++++++++++++++++ build.ps1 | 228 ++++++++++++++++ build.sh | 67 +++++ src/NHibernate.Test/NHibernate.Test.csproj | 2 + src/NHibernate.Test/test-x64.runsettings | 11 + src/NHibernate.Test/test-x86.runsettings | 11 + src/NuGet.config | 7 + 16 files changed, 1155 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 .circleci/images/nhibernate-build-dotnet-sdk/Dockerfile create mode 100644 .circleci/images/nhibernate-build-firebird/Dockerfile create mode 100644 .circleci/images/nhibernate-build-firebird/README.md create mode 100644 .circleci/images/nhibernate-build-firebird/build.sh create mode 100644 .circleci/images/nhibernate-build-firebird/docker-entrypoint.sh create mode 100644 appveyor.yml create mode 100644 build.cake create mode 100644 build.ps1 create mode 100755 build.sh create mode 100644 src/NHibernate.Test/test-x64.runsettings create mode 100644 src/NHibernate.Test/test-x86.runsettings create mode 100644 src/NuGet.config diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..02124bc33e1 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,137 @@ +# CircleCI 2.0 configuration file +--- +# Common primary image +ref-base-image: &ref-base-image + image: ngbrown/nhibernate-build-dotnet-sdk:latest + environment: + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 + - CAKE_VERSION: 0.21.1 + +# Download and cache dependencies +ref-restore-cache: &ref-restore-cache + restore_cache: + keys: + - cake-{{ .Environment.CAKE_VERSION }} + +ref-save-cache: &ref-save-cache + save_cache: + key: cake-{{ .Environment.CAKE_VERSION }} + paths: + - ~/project/tools + +version: 2 +jobs: + test-mssql: + docker: + - *ref-base-image + + - image: microsoft/mssql-server-linux:2017-latest + environment: + - ACCEPT_EULA: Y + - SA_PASSWORD: Password12! + + working_directory: ~/project + + steps: + - checkout + + # Download and cache dependencies + - *ref-restore-cache + - run: ./build.sh --target Restore + - *ref-save-cache + + # compile and run tests. + - run: + name: Test on Microsoft SQL Server 2017 for Linux + environment: + - NHIBERNATE_DATABASE_TEMPLATE: MSSQL.cfg.xml + - NHIBERNATE_CONNECTION_STRING: Server=(local);Database=master;User ID=sa;Password=Password12! + - NHIBERNATE_DIALECT: NHibernate.Dialect.MsSql2012Dialect + - DOTNET_FRAMEWORK: netcoreapp2.0 + - TARGET_PLATFORM: x64 + command: ./build.sh --target CircleCI --configuration Debug + + - store_test_results: + path: ~/test-reports + - store_artifacts: + path: ~/test-reports + + test-postgresql: + docker: + - *ref-base-image + + - image: postgres:9.6-alpine + environment: + - POSTGRES_PASSWORD: Password12! + command: ["postgres", "-c", "max_prepared_transactions=100"] + + working_directory: ~/project + + steps: + - checkout + + # Download and cache dependencies + - *ref-restore-cache + - run: ./build.sh --target Restore + - *ref-save-cache + + # compile and run tests. + - run: + name: Test on PostgreSQL 9.6 for Linux + environment: + - NHIBERNATE_DATABASE_TEMPLATE: PostgreSQL.cfg.xml + - NHIBERNATE_CONNECTION_STRING: Server=localhost;Port=5432;Database=nhibernate;User ID=postgres;Password=Password12!;Enlist=true; + - NHIBERNATE_DIALECT: NHibernate.Dialect.PostgreSQL83Dialect + - DOTNET_FRAMEWORK: netcoreapp2.0 + - TARGET_PLATFORM: x64 + command: ./build.sh --target CircleCI --configuration Debug + + - store_test_results: + path: ~/test-reports + - store_artifacts: + path: ~/test-reports + + test-firebird: + docker: + - *ref-base-image + + - image: ngbrown/nhibernate-build-firebird + environment: + - ISC_PASSWORD: Password12! + FIREBIRD_USER: nhibernate + FIREBIRD_PASSWORD: Password12! + FIREBIRD_DATABASE: nhibernate + + working_directory: ~/project + + steps: + - checkout + + # Download and cache dependencies + - *ref-restore-cache + - run: ./build.sh --target Restore + - *ref-save-cache + + # compile and run tests. + - run: + name: Test on Firebird 3.0 for Linux + environment: + - NHIBERNATE_DATABASE_TEMPLATE: FireBird.cfg.xml + - NHIBERNATE_CONNECTION_STRING: DataSource=localhost;Database=nhibernate;User ID=SYSDBA;Password=Password12!;MaxPoolSize=200; + - NHIBERNATE_DIALECT: NHibernate.Dialect.FirebirdDialect + - DOTNET_FRAMEWORK: netcoreapp2.0 + - TARGET_PLATFORM: x64 + command: ./build.sh --target CircleCI --configuration Debug + + - store_test_results: + path: ~/test-reports + - store_artifacts: + path: ~/test-reports + +workflows: + version: 2 + build: + jobs: + - test-mssql + - test-postgresql + - test-firebird \ No newline at end of file diff --git a/.circleci/images/nhibernate-build-dotnet-sdk/Dockerfile b/.circleci/images/nhibernate-build-dotnet-sdk/Dockerfile new file mode 100644 index 00000000000..07a2c279e60 --- /dev/null +++ b/.circleci/images/nhibernate-build-dotnet-sdk/Dockerfile @@ -0,0 +1,50 @@ +FROM buildpack-deps:jessie-scm + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + curl \ + unzip \ + libc6 \ + libcurl3 \ + libgcc1 \ + libgssapi-krb5-2 \ + libicu52 \ + liblttng-ust0 \ + libssl1.0.0 \ + libstdc++6 \ + libunwind8 \ + libuuid1 \ + zlib1g \ + && rm -rf /var/lib/apt/lists/* + +# Install .NET Core runtime - https://github.com/dotnet/dotnet-docker/blob/master/1.0/runtime/jessie/Dockerfile +ENV DOTNET_VERSION 1.0.5 +ENV DOTNET_DOWNLOAD_SHA 55481b0254a72d8c342ba6ccca3908ffb5c99d7eeb54f83dec6cc93c6b4cc3ae +ENV DOTNET_DOWNLOAD_URL https://dotnetcli.blob.core.windows.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-debian-x64.$DOTNET_VERSION.tar.gz + +RUN curl -SL $DOTNET_DOWNLOAD_URL --output dotnet.tar.gz \ + && echo "$DOTNET_DOWNLOAD_SHA dotnet.tar.gz" | sha256sum -c - \ + && mkdir -p /usr/share/dotnet \ + && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \ + && rm dotnet.tar.gz + +# Install .NET Core SDK - https://github.com/dotnet/dotnet-docker/blob/master/2.0/sdk/jessie/amd64/Dockerfile +ENV DOTNET_SDK_VERSION 2.0.0 +ENV DOTNET_SDK_DOWNLOAD_URL https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz +ENV DOTNET_SDK_DOWNLOAD_SHA E457F3A5685382F7F24851A2E76EDBE75B575948C8A7F43220F159BA29C329A5008BBE7220C18DFB31EAF0398FC72177B1948B65E19B34ED0D907EFB459CF4B0 + +RUN curl -SL $DOTNET_SDK_DOWNLOAD_URL --output dotnet.tar.gz \ + && echo "$DOTNET_SDK_DOWNLOAD_SHA dotnet.tar.gz" | sha512sum -c - \ + && mkdir -p /usr/share/dotnet \ + && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \ + && rm dotnet.tar.gz \ + && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet + +# Trigger the population of the local package cache +ENV NUGET_XMLDOC_MODE skip +RUN mkdir warmup \ + && cd warmup \ + && dotnet new \ + && cd .. \ + && rm -rf warmup \ + && rm -rf /tmp/NuGetScratch diff --git a/.circleci/images/nhibernate-build-firebird/Dockerfile b/.circleci/images/nhibernate-build-firebird/Dockerfile new file mode 100644 index 00000000000..1fda2233629 --- /dev/null +++ b/.circleci/images/nhibernate-build-firebird/Dockerfile @@ -0,0 +1,25 @@ +FROM debian:jessie + +ENV PREFIX=/usr/local/firebird +ENV DEBIAN_FRONTEND noninteractive +ENV FBURL=http://downloads.sourceforge.net/project/firebird/firebird/3.0.2-Release/Firebird-3.0.2.32703-0.tar.bz2 +ENV DBPATH=/databases + +ADD build.sh ./build.sh + +RUN chmod +x ./build.sh && \ + sync && \ + ./build.sh && \ + rm -f ./build.sh + +VOLUME ["/databases", "/var/firebird/run", "/var/firebird/etc", "/var/firebird/log", "/var/firebird/system", "/tmp/firebird"] + +EXPOSE 3050/tcp + +ADD docker-entrypoint.sh ${PREFIX}/docker-entrypoint.sh +RUN chmod +x ${PREFIX}/docker-entrypoint.sh + +ADD docker-entrypoint-async.sh ${PREFIX}/docker-entrypoint-async.sh +RUN chmod +x ${PREFIX}/docker-entrypoint-async.sh + +ENTRYPOINT ${PREFIX}/docker-entrypoint-async.sh ${PREFIX}/bin/fbguard diff --git a/.circleci/images/nhibernate-build-firebird/README.md b/.circleci/images/nhibernate-build-firebird/README.md new file mode 100644 index 00000000000..622acc5ba3d --- /dev/null +++ b/.circleci/images/nhibernate-build-firebird/README.md @@ -0,0 +1,67 @@ +# docker Firebird + +## Default password for `sysdba` +The default password for `sysdba` is randomly generated when you first launch the container, +look in the docker log for your container or pull /var/firebird/etc/SYSDBA.password. +Alternatively you may pass the environment variable ISC_PASSWORD to set the default password. + +## Description +This is a Firebird SQL Database container. + +## Default Login information +Username: SYSDBA +Password is either set by `ISC_PASSWORD` or randomized + +## Environment Variables: +### `TZ` +TimeZone. (i.e. America/Chicago) + +### `ISC_PASSWORD` +Default `sysdba` user password, if left blank a random 20 character password will be set instead. +The password used will be placed in /var/firebird/etc/SYSDBA.password. +If a random password is generated then it will be in the log for the container. + +### `FIREBIRD_DATABASE` +If this is set then a database will be created with this name under the `/databases` volume with the 'UTF8' +default character set and if `FIREBIRD_USER` is also set then `FIREBIRD_USER` will be given ownership. + +### `FIREBIRD_USER` +This user will be created and given ownership of `FIREBIRD_DATABASE`. +This variable is only used if `FIREBIRD_DATABASE` is also set. + +### `FIREBIRD_PASSWORD` +The password for `FIREBIRD_USER`, if left blank a random 20 character password will be set instead. +If a random password is generated then it will be in the log for the container. + +### `_FILE` +If set to the path to a file then the named variable minus the _FILE portion will contain the contents of that file. +This is useful for using docker secrets to manage your password. +This applies to all variables except `TZ` + +## Volumes: + +### `/databases/` +Default location to put database files + +### `/var/firebird/run` +guardian lock DIR + +### `/var/firebird/etc` +config files DIR +message files DIR + +### `/var/firebird/log` +log files DIR + +### `/var/firebird/system` +security database DIR + +### `/tmp/firebird` +Database lock directory + +## Exposes: +### 3050/tcp + +## Events +Please note for events to work properly you must either configure RemoteAuxPort and forward it with -p using a direct mapping where both sides internal and external use the same port or use --net=host to allow the random port mapping to work. +see: http://www.firebirdfaq.org/faq53/ for more information on event port mapping. diff --git a/.circleci/images/nhibernate-build-firebird/build.sh b/.circleci/images/nhibernate-build-firebird/build.sh new file mode 100644 index 00000000000..2f5eac1c390 --- /dev/null +++ b/.circleci/images/nhibernate-build-firebird/build.sh @@ -0,0 +1,64 @@ +#!/bin/bash +set -e +CPUC=$(awk '/^processor/{n+=1}END{print n}' /proc/cpuinfo) + +apt-get update +apt-get install -qy --no-install-recommends \ + libicu52 \ + libtommath0 +apt-get install -qy --no-install-recommends \ + bzip2 \ + ca-certificates \ + curl \ + g++ \ + gcc \ + libicu-dev \ + libncurses5-dev \ + libtommath-dev \ + make \ + zlib1g-dev +mkdir -p /home/firebird +cd /home/firebird +curl -o firebird-source.tar.bz2 -L \ + "${FBURL}" +tar --strip=1 -xf firebird-source.tar.bz2 +./configure \ + --prefix=${PREFIX}/ --with-fbbin=${PREFIX}/bin/ --with-fbsbin=${PREFIX}/bin/ --with-fblib=${PREFIX}/lib/ \ + --with-fbinclude=${PREFIX}/include/ --with-fbdoc=${PREFIX}/doc/ --with-fbudf=${PREFIX}/UDF/ \ + --with-fbsample=${PREFIX}/examples/ --with-fbsample-db=${PREFIX}/examples/empbuild/ --with-fbhelp=${PREFIX}/help/ \ + --with-fbintl=${PREFIX}/intl/ --with-fbmisc=${PREFIX}/misc/ --with-fbplugins=${PREFIX}/ \ + --with-fbconf=/var/firebird/etc/ --with-fbmsg=${PREFIX}/ \ + --with-fblog=/var/firebird/log/ --with-fbglock=/var/firebird/run/ \ + --with-fbsecure-db=/var/firebird/system +make -j${CPUC} +make silent_install +cd / +rm -rf /home/firebird +find ${PREFIX} -name .debug -prune -exec rm -rf {} \; +apt-get purge -qy --auto-remove \ + bzip2 \ + ca-certificates \ + curl \ + g++ \ + gcc \ + libicu-dev \ + libncurses5-dev \ + libtommath-dev \ + make \ + zlib1g-dev +rm -rf /var/lib/apt/lists/* + +# This allows us to initialize a random value for sysdba password +mv /var/firebird/system/security3.fdb ${PREFIX}/security3.fdb + +sed -i 's/^#DatabaseAccess/DatabaseAccess/g' /var/firebird/etc/firebird.conf +sed -i "s~^\(DatabaseAccess\s*=\s*\).*$~\1Restrict ${DBPATH}~" /var/firebird/etc/firebird.conf + +# Enable non-secured ADO.NET connector to connect. +echo $'WireCrypt = Enabled +AuthServer = Srp +AuthClient = Srp +UserManager = Srp +'\ +>> /var/firebird/etc/firebird.conf + diff --git a/.circleci/images/nhibernate-build-firebird/docker-entrypoint.sh b/.circleci/images/nhibernate-build-firebird/docker-entrypoint.sh new file mode 100644 index 00000000000..5441a2f8a01 --- /dev/null +++ b/.circleci/images/nhibernate-build-firebird/docker-entrypoint.sh @@ -0,0 +1,128 @@ +#!/bin/bash +set -e + +build() { + local var="$1" + local stmt="$2" + export $var+="$(printf "\n${stmt}")" +} + +run() { + echo "${!1}" | ${PREFIX}/bin/isql +} + +createNewPassword() { + # openssl generates random data. + openssl /dev/null 2>/dev/null + if [ $? -eq 0 ] + then + # We generate 40 random chars, strip any '/''s and get the first 20 + NewPasswd=`openssl rand -base64 40 | tr -d '/' | cut -c1-20` + fi + + # If openssl is missing... + if [ -z "$NewPasswd" ] + then + NewPasswd=`dd if=/dev/urandom bs=10 count=1 2>/dev/null | od -x | head -n 1 | tr -d ' ' | cut -c8-27` + fi + + # On some systems even this routines may be missing. So if + # the specific one isn't available then keep the original password. + if [ -z "$NewPasswd" ] + then + NewPasswd="masterkey" + fi + + echo "$NewPasswd" +} + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [ ! -f "/var/firebird/system/security3.fdb" ]; then + cp ${PREFIX}/security3.fdb /var/firebird/system/security3.fdb + file_env 'ISC_PASSWORD' + if [ -z ${ISC_PASSWORD} ]; then + ISC_PASSWORD=$(createNewPassword) + echo "setting 'SYSDBA' password to '${ISC_PASSWORD}'" + fi + + ${PREFIX}/bin/isql -user sysdba employee < /var/firebird/etc/SYSDBA.password < + diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000000..2a1f1a8512b --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,103 @@ +version: "{build}" + +# Skipping commits affecting specific files (GitHub only). +skip_commits: + files: + - doc/* + +# Build worker image (VM template) +image: Visual Studio 2017 + +# scripts that are called at very beginning, before repo cloning +init: + - cmd: |- + echo %APPVEYOR_BUILD_VERSION% + echo %NHIBERNATE_DATABASE_TEMPLATE% + echo %DOTNET_FRAMEWORK% + +# fetch repository as zip archive +#shallow_clone: true # default is "false" + +# set clone depth +clone_depth: 5 # clone entire repository history if not defined + +environment: + global: + # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + # Don't report back to the mothership + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + matrix: + - JOB_NAME: MSSQL x64 .Net 4.6.1 + NHIBERNATE_DATABASE_TEMPLATE: MSSQL.cfg.xml + NHIBERNATE_CONNECTION_STRING: Server=(local)\SQL2014;Database=master;User ID=sa;Password=Password12! + NHIBERNATE_DIALECT: NHibernate.Dialect.MsSql2012Dialect + DOTNET_FRAMEWORK: net461 + TARGET_PLATFORM: x64 + + - JOB_NAME: MSSQL x64 .NET Core 2.0 + NHIBERNATE_DATABASE_TEMPLATE: MSSQL.cfg.xml + NHIBERNATE_CONNECTION_STRING: Server=(local)\SQL2014;Database=master;User ID=sa;Password=Password12! + NHIBERNATE_DIALECT: NHibernate.Dialect.MsSql2012Dialect + DOTNET_FRAMEWORK: netcoreapp2.0 + TARGET_PLATFORM: x64 + + - JOB_NAME: MySQL x64 .NET Core 2.0 + NHIBERNATE_DATABASE_TEMPLATE: MySql.cfg.xml + NHIBERNATE_CONNECTION_STRING: Database=nhibernate;Server=localhost;Port=3306;User Id=root;Password=Password12!; + NHIBERNATE_DIALECT: NHibernate.Dialect.MySQL55InnoDBDialect + DOTNET_FRAMEWORK: netcoreapp2.0 + TARGET_PLATFORM: x64 + + - JOB_NAME: PostgreSQL x64 .NET Core 2.0 + NHIBERNATE_DATABASE_TEMPLATE: PostgreSQL.cfg.xml + NHIBERNATE_CONNECTION_STRING: Server=localhost;Port=5432;Database=nhibernate;User ID=postgres;Password=Password12!;Enlist=true; + NHIBERNATE_DIALECT: NHibernate.Dialect.PostgreSQL83Dialect + DOTNET_FRAMEWORK: netcoreapp2.0 + TARGET_PLATFORM: x64 + +# this is how to allow failing jobs in the matrix +matrix: + allow_failures: + - NHIBERNATE_DATABASE_TEMPLATE: MySql.cfg.xml + DOTNET_FRAMEWORK: netcoreapp2.0 + +# build cache to preserve files/folders between builds +cache: +# - '%LocalAppData%\NuGet\v3-cache' # NuGet v3.x http-cache +# - '%USERPROFILE%\.nuget\packages -> **\*.csproj' # global-packages cache + +# scripts that run after cloning repository +install: + - ps: |- + Invoke-WebRequest 'https://dotnetcli.blob.core.windows.net/dotnet/Sdk/2.0.0/dotnet-sdk-2.0.0-win-x64.exe' -OutFile "$env:appveyor_build_folder/dotnet-sdk-win-x64.exe" + & "$env:appveyor_build_folder/dotnet-sdk-win-x64.exe" /install /quiet /norestart + - echo max_prepared_transactions = 100 >> "C:\Program Files\PostgreSQL\9.6\data\postgresql.conf" + +# enable service required for build/tests +services: + - mssql2014 # start SQL Server 2014 Express + - mysql # start MySQL 5.6 service + - postgresql96 # start PostgreSQL 9.6 service + +nuget: + disable_publish_on_pr: true + +platform: Any CPU +configuration: Release + +# scripts to run before build +before_build: + - ps: |- + $env:MYSQL_PWD="Password12!" + & "C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql" -e "create database nhibernate;" --user=root + +build_script: + - ps: .\build.ps1 -Target "Appveyor" -configuration Debug + +# Run tests as part of build script instead of automatic tests +test: off + +artifacts: +- path: '**\Release\*.nupkg' +- path: '**\Debug\*.nupkg' \ No newline at end of file diff --git a/build.cake b/build.cake new file mode 100644 index 00000000000..634fdd342dd --- /dev/null +++ b/build.cake @@ -0,0 +1,251 @@ +string target = Argument("target", "Default"); +string configuration = Argument("configuration", "Release"); + +string baseSuffix = "Alpha1"; +string dbgSuffix = configuration == "Debug" ? "-dbg" : ""; +string versionSuffix = baseSuffix + dbgSuffix; + +string PROJECT_DIR = Context.Environment.WorkingDirectory.FullPath + "/"; + +string NHIBERNATE_DATABASE_TEMPLATE = EnvironmentVariable("NHIBERNATE_DATABASE_TEMPLATE") ?? "MSSQL.cfg.xml"; +string NHIBERNATE_DIALECT = EnvironmentVariable("NHIBERNATE_DIALECT"); // if null, don't change from default +string NHIBERNATE_CONNECTION_STRING = EnvironmentVariable("NHIBERNATE_CONNECTION_STRING"); // if null, don't change from default +string DOTNET_FRAMEWORK = EnvironmentVariable("DOTNET_FRAMEWORK") ?? "net461"; +string TARGET_PLATFORM = EnvironmentVariable("TARGET_PLATFORM") ?? "x86"; + +bool IsRunningOnCircleCI = EnvironmentVariable("CIRCLECI") != null; + +var ErrorDetail = new List(); + +bool isDotNetCoreInstalled = false; +Setup(context => +{ + string buildVersion = versionSuffix; + + if (BuildSystem.IsRunningOnAppVeyor) + { + var tag = AppVeyor.Environment.Repository.Tag; + + if (tag.IsTag) + { + versionSuffix = "" + dbgSuffix; + buildVersion = tag.Name + dbgSuffix; + } + else + { + var buildNumber = AppVeyor.Environment.Build.Number; + var branch = AppVeyor.Environment.Repository.Branch; + var isPullRequest = AppVeyor.Environment.PullRequest.IsPullRequest; + + CiNonTagBuildVersion(buildNumber, branch, isPullRequest ? AppVeyor.Environment.PullRequest.Number.ToString() : null); + buildVersion = versionSuffix; + } + + AppVeyor.UpdateBuildVersion(buildVersion); + } + else if(IsRunningOnCircleCI) + { + var tagName = EnvironmentVariable("CIRCLE_TAG"); + if (tagName != null) + { + versionSuffix = "" + dbgSuffix; + buildVersion = tagName + dbgSuffix; + } + else + { + var buildNumber = int.Parse(EnvironmentVariable("CIRCLE_BUILD_NUM")); + var branch = EnvironmentVariable("CIRCLE_BRANCH"); + var pullRequestNumber = EnvironmentVariable("CIRCLE_PR_NUMBER"); + var isPullRequest = pullRequestNumber != null; + + CiNonTagBuildVersion(buildNumber, branch, isPullRequest ? pullRequestNumber : null); + buildVersion = versionSuffix; + } + } + + Information("Building version {0} of NHibernate.", buildVersion); + isDotNetCoreInstalled = CheckIfDotNetCoreInstalled(); +}); + +Task("Restore") + .Does(() => {}); + +Task("Build") + .Description("Builds the .NET 4.61 and .NET Standard 2.0 versions of NHibernate") + .Does(() => + { + if(!isDotNetCoreInstalled) + { + Error("Was not built because .NET Core SDK is not installed"); + return; + } + BuildProject("src/NHibernate.sln", configuration); + }); + +Task("CopyConfiguration") + .Description("Setup Test Configuration") + .OnError(exception => { ErrorDetail.Add(exception.Message); }) + .Does(() => + { + var hibernateConfigPath = new FilePath(PROJECT_DIR + "current-test-configuration/hibernate.cfg.xml"); + CreateDirectory(PROJECT_DIR + "current-test-configuration"); + CopyFile(PROJECT_DIR + "src/NHibernate.Config.Templates/" + NHIBERNATE_DATABASE_TEMPLATE, hibernateConfigPath); + + + var pokeSettings = new XmlPokeSettings(); + pokeSettings.Namespaces["nhc"] = "urn:nhibernate-configuration-2.2"; + + if (!string.IsNullOrEmpty(NHIBERNATE_DIALECT)) + XmlPoke(hibernateConfigPath, "//*/nhc:property[@name='dialect']", NHIBERNATE_DIALECT, pokeSettings); + + if (!string.IsNullOrEmpty(NHIBERNATE_CONNECTION_STRING)) + XmlPoke(hibernateConfigPath, "//*/nhc:property[@name='connection.connection_string']", NHIBERNATE_CONNECTION_STRING, pokeSettings); + }); + +Task("Test") + .Description("Tests NHibernate") + .OnError(exception => { ErrorDetail.Add(exception.Message); }) + .Does(() => + { + var framework = DOTNET_FRAMEWORK; + Information("Testing framework: " + framework); + + var dir = PROJECT_DIR + "src/NHibernate.TestDatabaseSetup/"; + RunDotnetCoreTests(dir, "NHibernate.TestDatabaseSetup.csproj", framework, ref ErrorDetail); + + dir = PROJECT_DIR + "src/NHibernate.Test/"; + RunDotnetCoreTests(dir, "NHibernate.Test.csproj", framework, ref ErrorDetail); + + dir = PROJECT_DIR + "src/NHibernate.Test.VisualBasic/"; + RunDotnetCoreTests(dir, "NHibernate.Test.VisualBasic.vbproj", framework, ref ErrorDetail); + }); + +Teardown(context => CheckForError(ref ErrorDetail)); + +bool CheckIfDotNetCoreInstalled() +{ + try + { + Information("Checking if .NET Core SDK is installed"); + StartProcess("dotnet", new ProcessSettings + { + Arguments = "--version" + }); + } + catch(Exception) + { + Warning(".NET Core SDK is not installed. It can be installed from https://www.microsoft.com/net/core"); + return false; + } + return true; +} + +void CheckForError(ref List errorDetail) +{ + if(errorDetail.Count != 0) + { + var copyError = new List(); + copyError = errorDetail.Select(s => s).ToList(); + errorDetail.Clear(); + throw new Exception("One or more unit tests failed, breaking the build.\n" + + copyError.Aggregate((x,y) => x + "\n" + y)); + } +} + +void BuildProject(string projectPath, string configuration) +{ + int rc = StartProcess( + "dotnet", + new ProcessSettings() + .UseWorkingDirectory(PROJECT_DIR) + .WithArguments(args => args + .Append("build") + .AppendQuoted(projectPath) + .AppendSwitch("--configuration", configuration) + .Append("/property:VersionSuffix={0}", versionSuffix) + ) + ); +} + +void RunDotnetCoreTests(DirectoryPath workingDir, FilePath testProject, string framework, ref List errorDetail) +{ + string settingsPath = PROJECT_DIR + "src/NHibernate.Test/test-" + TARGET_PLATFORM + ".runsettings"; + int rc = StartProcess( + "dotnet", + new ProcessSettings() + .UseWorkingDirectory(workingDir.FullPath) + .WithArguments(args => { + args + .Append("test") + .AppendQuoted(testProject.FullPath) + .AppendSwitch("--configuration", configuration) + .AppendSwitch("--framework", framework) + .AppendSwitchQuoted("--settings", settingsPath) + .Append("/property:VersionSuffix={0}", versionSuffix); + + if (BuildSystem.IsRunningOnAppVeyor) + { + // Report results in real-time: https://github.com/Microsoft/vstest-docs/blob/master/docs/report.md + args.Append("--logger:Appveyor"); + } + else if (IsRunningOnCircleCI) + { + args.AppendQuoted("--logger:junit;LogFilePath=/root/test-reports/" + testProject.GetFilenameWithoutExtension() + ".xml"); + } + else + { +// args.Append("--logger:junit"); + } + }) + ); + + if (rc > 0) + errorDetail.Add(string.Format("{0}: {1} tests failed", framework, rc)); + else if (rc < 0) + errorDetail.Add(string.Format("{0} returned rc = {1}", testProject.GetFilename(), rc)); +} + +void CiNonTagBuildVersion(int buildNumber, string branch, string pullRequestNumber) +{ + string buildNumberFormatted = buildNumber.ToString("00000"); + bool isPullRequest = pullRequestNumber != null; + + if (branch == "master" && !isPullRequest) + { + versionSuffix = "dev-" + buildNumberFormatted + dbgSuffix; + } + else + { + var suffix = "ci-" + buildNumberFormatted + dbgSuffix; + + if (isPullRequest) + suffix += "-pr-" + pullRequestNumber; + else if (branch.StartsWith("release", StringComparison.OrdinalIgnoreCase)) + suffix += "-pre-" + buildNumberFormatted; + else + suffix += "-" + System.Text.RegularExpressions.Regex.Replace(branch, "[^0-9A-Za-z-]+", "-"); + + // Nuget limits "special version part" to 20 chars. Add one for the hyphen. + if (suffix.Length > 20) + suffix = suffix.Substring(0, 20); + + versionSuffix = suffix; + } +} + +Task("AppVeyor") + .Description("Builds, tests and packages on AppVeyor") + .IsDependentOn("Build") + .IsDependentOn("CopyConfiguration") + .IsDependentOn("Test"); + +Task("CircleCI") + .Description("Builds and tests on CircleCI") + .IsDependentOn("CopyConfiguration") + .IsDependentOn("Test"); + +Task("Default") + .Description("Builds all versions of NHibernate") + .IsDependentOn("Build"); + +RunTarget(target); diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 00000000000..2ed92ea4857 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,228 @@ +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +<# + +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. + +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. + +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER Experimental +Tells Cake to use the latest Roslyn release. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER Mono +Tells Cake to use the Mono scripting engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. + +.LINK +http://cakebuild.net + +#> + +[CmdletBinding()] +Param( + [string]$Script = "build.cake", + [string]$Target = "Default", + [ValidateSet("Release", "Debug")] + [string]$Configuration = "Release", + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity = "Verbose", + [switch]$Experimental, + [Alias("DryRun","Noop")] + [switch]$WhatIf, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } +} + +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} + +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" +$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" +$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" +$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" + +# Should we use mono? +$UseMono = ""; +if($Mono.IsPresent) { + Write-Verbose -Message "Using the Mono based scripting engine." + $UseMono = "-mono" +} + +# Should we use the new Roslyn? +$UseExperimental = ""; +if($Experimental.IsPresent -and !($Mono.IsPresent)) { + Write-Verbose -Message "Using experimental version of Roslyn." + $UseExperimental = "-experimental" +} + +# Is this a dry run? +$UseDryRun = ""; +if($WhatIf.IsPresent) { + $UseDryRun = "-dryrun" +} + +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } +} + +# Try download NuGet.exe if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Downloading NuGet.exe..." + try { + (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } +} + +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Get-ChildItem * -Exclude packages.config,nuget.exe,msbuild.cmd,.gitignore,BuildTool,ilrepack,nant,PEVerify,showdown | Remove-Item -Recurse + } + + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore addins from NuGet +if (Test-Path $ADDINS_PACKAGES_CONFIG) { + Push-Location + Set-Location $ADDINS_DIR + + Write-Verbose -Message "Restoring addins from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet addins." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore modules from NuGet +if (Test-Path $MODULES_PACKAGES_CONFIG) { + Push-Location + Set-Location $MODULES_DIR + + Write-Verbose -Message "Restoring modules from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet modules." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Make sure that Cake has been installed. +if (!(Test-Path $CAKE_EXE)) { + Throw "Could not find Cake.exe at $CAKE_EXE" +} + +# Start Cake +Write-Host "Running build script..." +Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" +exit $LASTEXITCODE diff --git a/build.sh b/build.sh new file mode 100755 index 00000000000..b65e70a6c2c --- /dev/null +++ b/build.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +########################################################################## +# This is the Cake bootstrapper script for Linux and OS X. +# This script assumes the dotnet core runtime 1.0.x is already installed. +########################################################################## + +# Define directories. +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +TOOLS_DIR=$SCRIPT_DIR/tools +if [ "$CAKE_VERSION" == "" ]; then + CAKE_VERSION=0.21.1 +fi + +CAKE_DLL=$TOOLS_DIR/Cake.CoreCLR/$CAKE_VERSION/Cake.dll + +# Define default arguments. +SCRIPT="build.cake" +TARGET="Default" +CONFIGURATION="Release" +VERBOSITY="verbose" +DRYRUN= +SHOW_VERSION=false +SCRIPT_ARGUMENTS=() + +# Parse arguments. +for i in "$@"; do + case $1 in + -s|--script) SCRIPT="$2"; shift ;; + -t|--target) TARGET="$2"; shift ;; + -c|--configuration) CONFIGURATION="$2"; shift ;; + -v|--verbosity) VERBOSITY="$2"; shift ;; + -d|--dryrun) DRYRUN="--dryrun" ;; + --version) SHOW_VERSION=true ;; + --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; + *) SCRIPT_ARGUMENTS+=("$1") ;; + esac + shift +done + +# Make sure the tools folder exist. +if [ ! -d "$TOOLS_DIR" ]; then + mkdir -p "$TOOLS_DIR" +fi + +# Restore tools from NuGet. +if [ ! -f "$CAKE_DLL" ]; then + mkdir -p "$TOOLS_DIR/Cake.CoreCLR/$CAKE_VERSION" + curl -Lsfo Cake.CoreCLR.zip "https://www.nuget.org/api/v2/package/Cake.CoreCLR/$CAKE_VERSION" && unzip -q Cake.CoreCLR.zip -d "$TOOLS_DIR/Cake.CoreCLR/$CAKE_VERSION" && rm -f Cake.CoreCLR.zip + if [ $? -ne 0 ]; then + echo "An error occured while installing Cake." + exit 1 + fi +fi + +# Make sure that Cake has been installed. +if [ ! -f "$CAKE_DLL" ]; then + echo "Could not find Cake.dll at '$CAKE_DLL'." + exit 1 +fi + +# Start Cake +if $SHOW_VERSION; then + exec dotnet "$CAKE_DLL" --version +else + exec dotnet "$CAKE_DLL" $SCRIPT --verbosity=$VERBOSITY --configuration=$CONFIGURATION --target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}" +fi \ No newline at end of file diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index ed88e6966d6..f7338ad0788 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -42,6 +42,8 @@ + + diff --git a/src/NHibernate.Test/test-x64.runsettings b/src/NHibernate.Test/test-x64.runsettings new file mode 100644 index 00000000000..90767ec5fa0 --- /dev/null +++ b/src/NHibernate.Test/test-x64.runsettings @@ -0,0 +1,11 @@ + + + + + 1 + + + x64 + + \ No newline at end of file diff --git a/src/NHibernate.Test/test-x86.runsettings b/src/NHibernate.Test/test-x86.runsettings new file mode 100644 index 00000000000..5ffd7908aa1 --- /dev/null +++ b/src/NHibernate.Test/test-x86.runsettings @@ -0,0 +1,11 @@ + + + + + 1 + + + x86 + + \ No newline at end of file diff --git a/src/NuGet.config b/src/NuGet.config new file mode 100644 index 00000000000..9f39ff25701 --- /dev/null +++ b/src/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file