486 строки
19 KiB
C#
486 строки
19 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
#addin nuget:?package=Cake.FileHelpers&version=3.0.0
|
|
#addin nuget:?package=Cake.Git&version=0.18.0
|
|
#addin nuget:?package=Cake.Incubator&version=2.0.2
|
|
#addin nuget:?package=Cake.SemVer&version=2.0.0
|
|
#addin nuget:?package=semver&version=2.0.4
|
|
#addin nuget:?package=Cake.Json&version=3.0.1
|
|
#load "scripts/utility.cake"
|
|
#load "scripts/configuration/config-parser.cake"
|
|
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Xml.Linq;
|
|
using System.Xml.XPath;
|
|
|
|
const string AndroidSdkRepoName = "microsoft/appcenter-sdk-android";
|
|
const string AppleSdkRepoName = "microsoft/appcenter-sdk-apple";
|
|
const string GitHubTagsUrlFormat = "repos/{0}/tags";
|
|
|
|
// Task TARGET for build
|
|
var TARGET = Argument("target", Argument("t", ""));
|
|
|
|
// Need to read versions before setting url values
|
|
VersionReader.ReadVersions();
|
|
|
|
Task("IncrementRevisionNumberWithHash").Does(() =>
|
|
{
|
|
IncrementRevisionNumber(true);
|
|
});
|
|
|
|
Task("IncrementRevisionNumber").Does(() =>
|
|
{
|
|
IncrementRevisionNumber(false);
|
|
});
|
|
|
|
Task("SetReleaseVersion").Does(() =>
|
|
{
|
|
var prereleaseSuffix = Argument<string>("PrereleaseSuffix", null);
|
|
|
|
// Get base version of .NET standard core
|
|
var releaseVersion = GetBaseSemanticVersion();
|
|
|
|
// Append suffix if any is provided for this release
|
|
if (prereleaseSuffix != null) {
|
|
releaseVersion = $"{releaseVersion}-{prereleaseSuffix}";
|
|
}
|
|
|
|
// Replace versions in all non-demo app files
|
|
var informationalVersionPattern = @"AssemblyInformationalVersion\(" + "\".*\"" + @"\)";
|
|
ReplaceRegexInFilesWithExclusion("**/AssemblyInfo.cs", informationalVersionPattern, "AssemblyInformationalVersion(\"" + releaseVersion + "\")", "Demo");
|
|
UpdateNewProjSdkVersion(releaseVersion, releaseVersion);
|
|
UpdateWrapperSdkVersion(releaseVersion);
|
|
UpdateConfigFileSdkVersion(releaseVersion);
|
|
});
|
|
|
|
Task("UpdateDemoVersion").Does(()=>
|
|
{
|
|
var newVersion = Argument<string>("DemoVersion");
|
|
|
|
// Replace version in all the demo application assemblies
|
|
var demoAssemblyInfoGlob = "Apps/**/*Demo*/**/AssemblyInfo.cs";
|
|
var informationalVersionPattern = @"AssemblyInformationalVersion\(" + "\".*\"" + @"\)";
|
|
ReplaceRegexInFiles(demoAssemblyInfoGlob, informationalVersionPattern, "AssemblyInformationalVersion(\"" + newVersion + "\")");
|
|
var newFileVersion = GetBaseVersion(newVersion) + "." + GetRevisionNumber(newVersion);
|
|
var fileVersionPattern = @"AssemblyFileVersion\(" + "\".*\"" + @"\)";
|
|
ReplaceRegexInFiles(demoAssemblyInfoGlob, fileVersionPattern, "AssemblyFileVersion(\"" + newFileVersion + "\")");
|
|
var csprojFiles = GetFiles("Apps/**/*Demo*/**/*.csproj");
|
|
foreach (var file in csprojFiles)
|
|
{
|
|
UpdateNewProjVersion(file, newVersion, newFileVersion);
|
|
}
|
|
|
|
// Replace android versions
|
|
var manifestGlob = "Apps/**/*Demo*/**/AndroidManifest.xml";
|
|
|
|
// Manifest version name tag
|
|
var versionNamePattern = "android:versionName=\"[^\"]+\"";
|
|
var newVersionName = "android:versionName=\"" + newVersion + "\"";
|
|
ReplaceRegexInFilesWithExclusion(manifestGlob, versionNamePattern, newVersionName, "/bin/", "/obj/");
|
|
|
|
// Manifest version code
|
|
var manifests = GetFiles("Apps/**/*Demo*/**/AndroidManifest.xml");
|
|
foreach (var manifest in manifests)
|
|
{
|
|
if (!manifest.FullPath.Contains("/bin/") &&
|
|
!manifest.FullPath.Contains("/obj/"))
|
|
{
|
|
IncrementManifestVersionCode(manifest);
|
|
}
|
|
}
|
|
|
|
// Replace UWP version
|
|
var uwpManifestGlob = "Apps/**/*Demo*/**/Package.appxmanifest";
|
|
var versionTagPattern = " Version=\"[^\"]+\"";
|
|
var newVersionTagText = " Version=\"" + newFileVersion + "\"";
|
|
ReplaceRegexInFiles(uwpManifestGlob, versionTagPattern, newVersionTagText);
|
|
|
|
// Replace iOS version
|
|
var bundleVersionPattern = @"<key>CFBundleVersion<\/key>\s*<string>[^<]*<\/string>";
|
|
var newBundleVersionString = "<key>CFBundleVersion</key>\n\t<string>" + newVersion + "</string>";
|
|
ReplaceRegexInFilesWithExclusion("Apps/**/*Demo*/**/Info.plist", bundleVersionPattern, newBundleVersionString, "/bin/", "/obj/");
|
|
var bundleShortVersionPattern = @"<key>CFBundleShortVersionString<\/key>\s*<string>[^<]*<\/string>";
|
|
var newBundleShortVersionString = "<key>CFBundleShortVersionString</key>\n\t<string>" + newVersion + "</string>";
|
|
ReplaceRegexInFilesWithExclusion("Apps/**/*Demo*/**/Info.plist", bundleShortVersionPattern, newBundleShortVersionString, "/bin/", "/obj/");
|
|
|
|
// Note: nuget update does not work with projects using project.json
|
|
// Replace version in all the demo application
|
|
ReplaceRegexInFiles("Apps/**/*Demo*/**/project.json", "(Microsoft.AppCenter[^\"]*\":[ ]+\")[^\"]+", "$1" + newVersion, RegexOptions.ECMAScript);
|
|
ReplaceRegexInFiles("Apps/**/*Demo*/**/*.csproj",
|
|
"<PackageReference Include=\"(Microsoft.AppCenter[^\"]*)\" Version=\"[^\"]+\" />",
|
|
"<PackageReference Include=\"$1\" Version=\"" + newVersion + "\" />", RegexOptions.ECMAScript);
|
|
});
|
|
|
|
Task("StartNewVersion").Does(() =>
|
|
{
|
|
var newVersion = Argument<string>("NewVersion");
|
|
StartNewVersion(newVersion);
|
|
});
|
|
|
|
// Fills Android and iOS versions in the build config file with the relevant ones.
|
|
Task("UpdateNativeVersionsToLatest")
|
|
.IsDependentOn("UpdateAndroidVersionToLatest")
|
|
.IsDependentOn("UpdateIosVersionToLatest");
|
|
|
|
Task("UpdateAndroidVersionToLatest").Does(() =>
|
|
{
|
|
var androidLatestVersion = GetLatestGitHubReleaseVersion(AndroidSdkRepoName);
|
|
Information($"Received latest android sdk release version {androidLatestVersion}. Verifying if it's a valid semver version...");
|
|
ParseSemVer(androidLatestVersion);
|
|
var versionsAreEqual = VersionReader.AndroidVersion.Equals(androidLatestVersion);
|
|
if (versionsAreEqual)
|
|
{
|
|
Information($"Nothing to replace. Exiting...");
|
|
return;
|
|
}
|
|
VersionReader.WriteAndroidVersion(androidLatestVersion);
|
|
}).OnError(HandleError);
|
|
|
|
Task("UpdateIosVersionToLatest").Does(() =>
|
|
{
|
|
var appleLatestVersion = GetLatestGitHubReleaseVersion(AppleSdkRepoName);
|
|
Information($"Received latest apple sdk release version {appleLatestVersion}. Verifying if it's a valid semver version...");
|
|
ParseSemVer(appleLatestVersion);
|
|
var versionsAreEqual = VersionReader.IosVersion.Equals(appleLatestVersion);
|
|
if (versionsAreEqual)
|
|
{
|
|
Information($"Nothing to replace. Exiting...");
|
|
return;
|
|
}
|
|
VersionReader.WriteIosVersion(appleLatestVersion);
|
|
}).OnError(HandleError);
|
|
|
|
Task("IncreasePatchVersion").Does(() =>
|
|
{
|
|
var sdkVersion = ParseSemVer(VersionReader.SdkVersion);
|
|
var patchVersion = sdkVersion.Patch;
|
|
patchVersion++;
|
|
sdkVersion = sdkVersion.Change(patch: patchVersion, prerelease: "", build: "");
|
|
Information($"Bumping {VersionReader.SdkVersion} SDK version to {sdkVersion.ToString()}...");
|
|
StartNewVersion(sdkVersion.ToString());
|
|
}).OnError(HandleError);
|
|
|
|
void StartNewVersion(string newVersion)
|
|
{
|
|
var snapshotVersion = newVersion + "-SNAPSHOT";
|
|
var newFileVersion = newVersion + ".0";
|
|
|
|
// Replace version in all but the demo application assemblies
|
|
var assemblyInfoGlob = "**/AssemblyInfo.cs";
|
|
var informationalVersionPattern = @"AssemblyInformationalVersion\(" + "\".*\"" + @"\)";
|
|
ReplaceRegexInFilesWithExclusion(assemblyInfoGlob, informationalVersionPattern, "AssemblyInformationalVersion(\"" + snapshotVersion + "\")", "Demo");
|
|
var fileVersionPattern = @"AssemblyFileVersion\(" + "\".*\"" + @"\)";
|
|
ReplaceRegexInFilesWithExclusion(assemblyInfoGlob, fileVersionPattern, "AssemblyFileVersion(\"" + newFileVersion + "\")", "Demo");
|
|
|
|
UpdateConfigFileSdkVersion(snapshotVersion);
|
|
UpdateNewProjSdkVersion(snapshotVersion, newFileVersion);
|
|
UpdateWrapperSdkVersion(snapshotVersion);
|
|
|
|
// Replace android manifest version name tag
|
|
var androidManifestGlob = "**/AndroidManifest.xml";
|
|
var versionNamePattern = "android:versionName=\"[^\"]+\"";
|
|
var newVersionName = "android:versionName=\"" + snapshotVersion + "\"";
|
|
ReplaceRegexInFilesWithExclusion(androidManifestGlob, versionNamePattern, newVersionName, "Demo", "/bin/", "/obj/");
|
|
|
|
// Replace android manifest version code
|
|
var manifests = GetFiles(androidManifestGlob);
|
|
foreach (var manifest in manifests)
|
|
{
|
|
if (!manifest.FullPath.Contains("Demo") &&
|
|
!manifest.FullPath.Contains("SDK") &&
|
|
!manifest.FullPath.Contains("externals") &&
|
|
!manifest.FullPath.Contains("/bin/") &&
|
|
!manifest.FullPath.Contains("/obj/"))
|
|
{
|
|
IncrementManifestVersionCode(manifest);
|
|
}
|
|
}
|
|
|
|
// Replace UWP version
|
|
var uwpManifestGlob = "**/Package.appxmanifest";
|
|
var versionTagPattern = " Version=\"[^\"]+\"";
|
|
var newVersionTagText = " Version=\""+newVersion+".0\"";
|
|
ReplaceRegexInFilesWithExclusion(uwpManifestGlob, versionTagPattern, newVersionTagText, "Demo");
|
|
|
|
// Replace iOS version
|
|
var bundleVersionPattern = @"<key>CFBundleVersion<\/key>\s*<string>[^<]*<\/string>";
|
|
var newBundleVersionString = "<key>CFBundleVersion</key>\n\t<string>" + newVersion + "</string>";
|
|
ReplaceRegexInFilesWithExclusion("**/Info.plist", bundleVersionPattern, newBundleVersionString, "/bin/", "/obj/", "Demo");
|
|
var bundleShortVersionPattern = @"<key>CFBundleShortVersionString<\/key>\s*<string>[^<]*<\/string>";
|
|
var newBundleShortVersionString = "<key>CFBundleShortVersionString</key>\n\t<string>" + newVersion + "</string>";
|
|
ReplaceRegexInFilesWithExclusion("**/Info.plist", bundleShortVersionPattern, newBundleShortVersionString, "/bin/", "/obj/", "Demo");
|
|
}
|
|
|
|
void IncrementRevisionNumber(bool useHash)
|
|
{
|
|
// Get base version of .NET standard core
|
|
var baseSemanticVersion = GetBaseSemanticVersion();
|
|
var nugetVer = GetLatestNuGetVersion();
|
|
var baseVersion = GetBaseVersion(nugetVer);
|
|
var newRevNum = baseSemanticVersion == baseVersion ? GetRevisionNumber(nugetVer) + 1 : 1;
|
|
var newRevString = GetPaddedString(newRevNum, 4);
|
|
var newVersion = baseSemanticVersion + "-r" + newRevString;
|
|
var newFileVersion = baseSemanticVersion + "." + newRevNum;
|
|
if (useHash)
|
|
{
|
|
newVersion += "-" + GetShortCommitHash();
|
|
}
|
|
|
|
// Replace AssemblyInformationalVersion in all AssemblyInfo files
|
|
var informationalVersionPattern = @"AssemblyInformationalVersion\(" + "\".*\"" + @"\)";
|
|
ReplaceRegexInFiles("**/AssemblyInfo.cs", informationalVersionPattern, "AssemblyInformationalVersion(\"" + newVersion + "\")");
|
|
|
|
// Increment revision number of AssemblyFileVersion
|
|
var fileVersionPattern = @"AssemblyFileVersion\(" + "\".*\"" + @"\)";
|
|
var files = FindRegexInFiles("**/AssemblyInfo.cs", fileVersionPattern);
|
|
foreach (var file in files)
|
|
{
|
|
var fileVersionTrimmedPattern = @"AssemblyFileVersion\("+ "\"" + @"([0-9]+.){3}";
|
|
var fullVersion = FindRegexMatchInFile(file, fileVersionPattern, RegexOptions.None);
|
|
var trimmedVersion = FindRegexMatchInFile(file, fileVersionTrimmedPattern, RegexOptions.None);
|
|
var newFileVersionTmp = trimmedVersion + newRevNum + "\")";
|
|
ReplaceTextInFiles(file.FullPath, fullVersion, newFileVersionTmp);
|
|
}
|
|
|
|
UpdateConfigFileSdkVersion(newVersion);
|
|
UpdateNewProjSdkVersion(newVersion, newFileVersion);
|
|
UpdateWrapperSdkVersion(newVersion);
|
|
}
|
|
|
|
string GetBaseSemanticVersion()
|
|
{
|
|
return GetBaseVersion(VersionReader.SdkVersion);
|
|
}
|
|
|
|
string GetShortCommitHash()
|
|
{
|
|
var lastCommit = GitLogTip(".");
|
|
return lastCommit.Sha.Substring(0, 7);
|
|
}
|
|
|
|
string GetLatestNuGetVersion()
|
|
{
|
|
//Since password and feed id are secret variables in VSTS (and thus cannot be accessed like other environment variables),
|
|
//provide the option to pass them as parameters to the cake script
|
|
var nugetUser = EnvironmentVariable("NUGET_USER");
|
|
var nugetPassword = Argument("NuGetPassword", EnvironmentVariable("NUGET_PASSWORD"));
|
|
var nugetFeedId = Argument("NuGetFeedId", EnvironmentVariable("NUGET_FEED_ID"));
|
|
var url = "https://msmobilecenter.pkgs.visualstudio.com/_packaging/" + nugetFeedId + "/nuget/v2/Search()?$filter=IsAbsoluteLatestVersion+and+Id+eq+'Microsoft.AppCenter'&includePrerelease=true";
|
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create (url);
|
|
request.Headers["X-NuGet-ApiKey"] = nugetPassword;
|
|
request.Credentials = new NetworkCredential(nugetUser, nugetPassword);
|
|
HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
|
|
var responseString = String.Empty;
|
|
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
|
|
{
|
|
responseString = reader.ReadToEnd();
|
|
}
|
|
var startTag = "<d:Version>";
|
|
var endTag = "</d:Version>";
|
|
int start = responseString.IndexOf(startTag);
|
|
int end = responseString.IndexOf(endTag);
|
|
if (start == -1 || end == -1) {
|
|
return "0.0.0";
|
|
}
|
|
var tag = responseString.Substring(start + startTag.Length, end - start - startTag.Length);
|
|
return tag;
|
|
}
|
|
|
|
void IncrementManifestVersionCode(FilePath manifest)
|
|
{
|
|
var versionCodePattern = "android:versionCode=\"[^\"]+\"";
|
|
var versionCodeText = FindRegexMatchInFile(manifest, versionCodePattern, RegexOptions.None);
|
|
var firstPart = "android:versionCode=\"";
|
|
var length = versionCodeText.Length - 1 - firstPart.Length;
|
|
var versionCode = int.Parse(versionCodeText.Substring(firstPart.Length, length));
|
|
var newVersionCodeText = firstPart + (versionCode + 1) + "\"";
|
|
ReplaceRegexInFiles(manifest.FullPath, versionCodePattern, newVersionCodeText);
|
|
}
|
|
|
|
string GetBaseVersion(string fullVersion)
|
|
{
|
|
var indexDash = fullVersion.IndexOf("-");
|
|
if (indexDash == -1)
|
|
{
|
|
return fullVersion;
|
|
}
|
|
return fullVersion.Substring(0, indexDash);
|
|
}
|
|
|
|
// Changes the Version field in WrapperSdk.cs to the given version
|
|
void UpdateWrapperSdkVersion(string newVersion)
|
|
{
|
|
var patternString = "Version = \"[^\"]+\";";
|
|
var newString = "Version = \"" + newVersion + "\";";
|
|
ReplaceRegexInFiles("SDK/AppCenter/Microsoft.AppCenter.Shared/WrapperSdk.cs", patternString, newString);
|
|
}
|
|
|
|
void UpdateNewProjSdkVersion(string newVersion, string newFileVersion)
|
|
{
|
|
var csprojFiles = GetFiles("**/*.csproj");
|
|
foreach (var file in csprojFiles)
|
|
{
|
|
if (!file.FullPath.Contains("Demo"))
|
|
{
|
|
UpdateNewProjVersion(file, newVersion, newFileVersion);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateNewProjVersion(FilePath file, string newVersion, string newFileVersion)
|
|
{
|
|
var csproj = XDocument.Load(file.FullPath);
|
|
var version = csproj.XPathSelectElement("/Project/PropertyGroup/Version");
|
|
version?.SetValue(newVersion);
|
|
var fileVersion = csproj.XPathSelectElement("/Project/PropertyGroup/FileVersion");
|
|
fileVersion?.SetValue(newFileVersion);
|
|
if (version != null || fileVersion != null)
|
|
{
|
|
csproj.Save(file.FullPath);
|
|
}
|
|
}
|
|
|
|
// Gets the revision number from a version string containing revision -r****
|
|
int GetRevisionNumber(string fullVersion)
|
|
{
|
|
var revStart = fullVersion.IndexOf("-r");
|
|
if (revStart == -1)
|
|
{
|
|
return 0;
|
|
}
|
|
var revEnd = fullVersion.IndexOf("-", revStart + 1);
|
|
if (revEnd == -1)
|
|
{
|
|
revEnd = fullVersion.Length;
|
|
}
|
|
var revString = fullVersion.Substring(revStart + 2, revEnd - revStart - 2);
|
|
try
|
|
{
|
|
return Int32.Parse(revString);
|
|
}
|
|
catch
|
|
{
|
|
return 0; //if the revision number could not be parsed, start new revision
|
|
}
|
|
}
|
|
|
|
// Returns the given integer as a string with a number of leading zeroes to
|
|
// pad the string to numDigits digits
|
|
string GetPaddedString(int num, int numDigits)
|
|
{
|
|
var numString = num.ToString();
|
|
while (numString.Length < numDigits)
|
|
{
|
|
numString = "0" + numString;
|
|
}
|
|
return numString;
|
|
}
|
|
|
|
// Run "ReplaceRegexInFiles" methods but exclude all file paths containing the strings in "excludeFilePathsContaining"
|
|
void ReplaceRegexInFilesWithExclusion(string globberPattern, string regEx, string replacement, params string[] excludeFilePathsContaining)
|
|
{
|
|
var files = GetFiles(globberPattern);
|
|
foreach (var file in files)
|
|
{
|
|
bool shouldReplace = true;
|
|
foreach (var excludeString in excludeFilePathsContaining)
|
|
{
|
|
if (file.FullPath.Contains(excludeString))
|
|
{
|
|
shouldReplace = false;
|
|
break;
|
|
}
|
|
}
|
|
if (shouldReplace)
|
|
{
|
|
ReplaceRegexInFiles(file.FullPath, regEx, replacement);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UpdateConfigFileSdkVersion(string newVersion)
|
|
{
|
|
ReplaceRegexInFiles(ConfigFile.Path, @"<sdkVersion>[\.|A-z|0-9|-]*<\/sdkVersion>", $"<sdkVersion>{newVersion}</sdkVersion>");
|
|
}
|
|
|
|
Task("UpdateCgManifest").Does(()=>
|
|
{
|
|
try
|
|
{
|
|
var manifestFilePath = "cgmanifest.json";
|
|
var content = ParseJsonFromFile(manifestFilePath);
|
|
var registrations = (JArray)content["Registrations"];
|
|
foreach (var registration in registrations.Children())
|
|
{
|
|
HanldeRegistration(registration);
|
|
}
|
|
|
|
SerializeJsonToPrettyFile(manifestFilePath, content);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Warning($"Can't update 'cgmanifest.json'. Error message: {e.Message}");
|
|
}
|
|
});
|
|
|
|
void HanldeRegistration(JToken registration)
|
|
{
|
|
var component = registration["component"];
|
|
if (component == null)
|
|
{
|
|
Warning("Current registration has no 'component' property.");
|
|
return;
|
|
}
|
|
|
|
var typeObject = component["type"];
|
|
if (typeObject == null || typeObject.Value<string>() != "git")
|
|
{
|
|
Warning("Current component has no field 'type' or 'type' is not 'git'.");
|
|
return;
|
|
}
|
|
|
|
UpdateCommitHash(component);
|
|
}
|
|
|
|
void UpdateCommitHash(JToken component)
|
|
{
|
|
var gitData = component["git"];
|
|
var repoUrl = gitData["repositoryUrl"].Value<string>();
|
|
var currentRepoName = repoUrl.Contains(AndroidSdkRepoName) ? AndroidSdkRepoName : AppleSdkRepoName;
|
|
var releaseTag = GetReleaseTag(currentRepoName);
|
|
if (string.IsNullOrEmpty(releaseTag))
|
|
{
|
|
Warning($"Repository url: {repoUrl}. Release tag '{releaseTag}' was not found.");
|
|
return;
|
|
}
|
|
|
|
var tagsRequest = CreateGitHubRequest(string.Format(GitHubTagsUrlFormat, currentRepoName));
|
|
var tagsListJson = GetResponseJsonArray(tagsRequest);
|
|
var tag = tagsListJson.Children().FirstOrDefault(t => t["name"].Value<string>() == releaseTag);
|
|
if (tag == null)
|
|
{
|
|
Warning($"Repository url: {repoUrl}. Tag '{tag}' was not found.");
|
|
return;
|
|
}
|
|
|
|
gitData["commitHash"] = tag["commit"]["sha"].Value<string>();
|
|
}
|
|
|
|
string GetReleaseTag(string currentRepoName)
|
|
{
|
|
switch (currentRepoName)
|
|
{
|
|
case AndroidSdkRepoName:
|
|
return VersionReader.AndroidVersion;
|
|
case AppleSdkRepoName:
|
|
return VersionReader.IosVersion;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
RunTarget(TARGET);
|