diff --git a/build/Publish.targets b/build/Publish.targets
new file mode 100644
index 0000000000..4fd0137ab3
--- /dev/null
+++ b/build/Publish.targets
@@ -0,0 +1,135 @@
+
+
+
+ $(RepositoryRoot).deps\assets\
+
+ aspnetcore_base_runtime.version
+ $(ArtifactsDir)$(BaseRuntimeVersionFileName)
+ latest.aspnetcore.version
+ $(ArtifactsDir)$(LatestRuntimeVersionFileName)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Runtime/$(PackageVersion)/
+ Runtime/$(SharedFxCliBlobChannel)/
+ nuGetPackagesArchive-$(PackageVersion).lzma
+ aspnetcore-runtime-$(PackageVersion)
+ aspnetcore-runtime-latest
+ aspnetcore-runtime-symbols-$(PackageVersion)
+ aspnetcore-runtime-internal-$(PackageVersion)
+
+
+
+
+
+ $(BlobBasePath)$(SymbolsArchiveBaseFileName)-%(RuntimeSymbolsArchive.Identity)%(RuntimeSymbolsArchive.FileExt)
+
+
+
+
+ $(BlobBasePath)$(PackageArchiveFileName)
+
+
+
+ $(BlobBasePath)$(IntermediateInstallerBaseFileName)-%(IntermediateInstaller.Identity)%(IntermediateInstaller.FileExt)
+
+
+
+ $(BlobBasePath)$(BaseRuntimeVersionFileName)
+ text/plain
+
+
+
+
+ $(BlobBasePath)$(InstallerBaseFileName)-%(NativeInstaller.Identity)%(NativeInstaller.FileExt)
+
+
+
+ $(AliasBlobBasePath)$(InstallerAliasBaseFileName)-%(NativeInstaller.Identity)%(NativeInstaller.FileExt)
+ true
+
+
+
+
+ $(AliasBlobBasePath)%(SharedFxVersionBadge.FileName)%(SharedFxVersionBadge.Extension)
+ no-cache, no-store, must-revalidate
+ image/svg+xml
+ true
+
+
+
+ $(AliasBlobBasePath)$(LatestRuntimeVersionFileName)
+ no-cache, no-store, must-revalidate
+ text/plain
+ true
+
+
+
+
+
+
+
+
+
+ <_MissingFiles Include="%(FilesToPublish.Identity)" Condition=" ! Exists(%(FilesToPublish.Identity))" />
+
+
+
+
+
+
+
+
+
+ $(AzureBlobRelativePathBase)/
+
+
+
+
+
+
+
+
+
+
diff --git a/build/SharedFx.targets b/build/SharedFx.targets
index eb0e738b2d..f396901da0 100644
--- a/build/SharedFx.targets
+++ b/build/SharedFx.targets
@@ -41,7 +41,7 @@
true
-
+
@@ -134,22 +134,6 @@
Overwrite="true" />
-
-
-
-
-
-
diff --git a/build/repo.props b/build/repo.props
index e628b52e47..ea5b24a29d 100644
--- a/build/repo.props
+++ b/build/repo.props
@@ -18,6 +18,37 @@
$(RepositoryRoot).deps\mirror\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -26,6 +57,10 @@
FeedCredential="$(DotNetAssetRootAccessTokenSuffix)" />
+
+ true
+
+
diff --git a/build/repo.targets b/build/repo.targets
index d16b901ae0..05e40b4a16 100644
--- a/build/repo.targets
+++ b/build/repo.targets
@@ -5,6 +5,7 @@
+
<_RepositoryBuildTargets Condition="'$(_RepositoryBuildTargets)'=='' AND '$(SkipTests)'=='true'">/t:Package /t:VerifyPackages
diff --git a/build/tasks/PublishToAzureBlob.cs b/build/tasks/PublishToAzureBlob.cs
new file mode 100644
index 0000000000..94da58dc8a
--- /dev/null
+++ b/build/tasks/PublishToAzureBlob.cs
@@ -0,0 +1,100 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Build.Framework;
+using Microsoft.WindowsAzure.Storage;
+using Microsoft.WindowsAzure.Storage.Blob;
+
+namespace RepoTasks
+{
+ ///
+ /// Publish files to an Azure storage blob
+ ///
+ public class PublishToAzureBlob : Microsoft.Build.Utilities.Task, ICancelableTask
+ {
+ private CancellationTokenSource _cts = new CancellationTokenSource();
+
+ ///
+ /// The files to publish.
+ ///
+ [Required]
+ public ITaskItem[] Files { get; set; }
+
+ ///
+ /// The Azure blob storage account name.
+ ///
+ [Required]
+ public string AccountName { get; set; }
+
+ ///
+ /// The SAS token used to write to Azure.
+ ///
+ [Required]
+ public string SharedAccessToken { get; set; }
+
+ ///
+ /// The Azure blob storage container name
+ ///
+ [Required]
+ public string ContainerName { get; set; }
+
+ public void Cancel() => _cts.Cancel();
+
+ public override bool Execute()
+ => ExecuteAsync().Result;
+
+ private async Task ExecuteAsync()
+ {
+ var connectionString = $"BlobEndpoint=https://{AccountName}.blob.core.windows.net;SharedAccessSignature={SharedAccessToken}";
+
+ var account = CloudStorageAccount.Parse(connectionString);
+ var client = account.CreateCloudBlobClient();
+ var container = client.GetContainerReference(ContainerName);
+
+ var ctx = new OperationContext();
+
+ foreach (var item in Files)
+ {
+ // normalize slashes
+ var dest = item.GetMetadata("RelativeBlobPath")
+ .Replace('\\', '/')
+ .Replace("//", "/");
+ var contentType = item.GetMetadata("ContentType");
+ var cacheControl = item.GetMetadata("CacheControl");
+
+ if (string.IsNullOrEmpty(dest))
+ {
+ Log.LogError($"Item {item.ItemSpec} is missing required metadata 'RelativeBlobPath'");
+ return false;
+ }
+
+ var blob = container.GetBlockBlobReference(dest);
+
+ if (!string.IsNullOrEmpty(cacheControl))
+ {
+ blob.Properties.CacheControl = cacheControl;
+ }
+
+ if (!string.IsNullOrEmpty(contentType))
+ {
+ blob.Properties.ContentType = contentType;
+ }
+
+ Log.LogMessage(MessageImportance.High, $"Publishing {item.ItemSpec} to https://{AccountName}.blob.core.windows.net/{ContainerName}/{dest}");
+
+ var accessCondition = bool.TryParse(item.GetMetadata("Overwrite"), out var overwrite) && overwrite
+ ? AccessCondition.GenerateEmptyCondition()
+ : AccessCondition.GenerateIfNotExistsCondition();
+
+ await blob.UploadFromFileAsync(item.ItemSpec, accessCondition, new BlobRequestOptions(), ctx, _cts.Token);
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/build/tasks/RepoTasks.csproj b/build/tasks/RepoTasks.csproj
index 2b538f7e0b..4c4e3556e8 100644
--- a/build/tasks/RepoTasks.csproj
+++ b/build/tasks/RepoTasks.csproj
@@ -8,6 +8,7 @@
+
diff --git a/build/tasks/RepoTasks.tasks b/build/tasks/RepoTasks.tasks
index 1b8dbe7e76..e1a43cf51f 100644
--- a/build/tasks/RepoTasks.tasks
+++ b/build/tasks/RepoTasks.tasks
@@ -3,12 +3,19 @@
<_RepoTaskAssembly>$(MSBuildThisFileDirectory)bin\publish\RepoTasks.dll
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/version.props b/version.props
index e5fd0676de..b4422a95c4 100644
--- a/version.props
+++ b/version.props
@@ -5,5 +5,7 @@
$(VersionPrefix)
$(VersionPrefix)-$(VersionSuffix)-final
$(VersionSuffix)-$(BuildNumber)
+
+ master