diff --git a/README.md b/README.md index 6232d26..1c9f023 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Sitecore.Ship +[![Join the chat at https://gitter.im/kevinobee/Sitecore.Ship](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/kevinobee/Sitecore.Ship?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Sitecore.Ship is a lightweight means to install Sitecore Update packages via HTTP requests. @@ -21,7 +23,9 @@ The latest release versions of the Sitecore.Ship packages can be found on the Nu ### Installing the Package -Ensure that the website project is set to run with .NET Framework 4.0 +Ensure that the website project is set to run with .NET Framework 4.5 + +Ensure that the web.config file for the target project if already existing is included into your project. Run the following powershell command in the package manager console of the Visual Studio solution for the target website: @@ -33,7 +37,7 @@ Installing the package will do the following: * Add a new `packageInstallation` section to your `web.config` file. You can set configuration options in this section to enable remote access to the installer and to enable the package streaming functionality. These options are safe by default, that is, no remote access and package streaming disabled. **Note:** the configuration settings are ignored in this branch of Sitecore.Ship. -* Register a single new HTTP handler section in `` and `` +* Register a single new HTTP handler section in ``. Support for classic mode in IIS has been removed. * Add a `ship.config` Sitecore include file to the `App_Config\include` folder. @@ -79,7 +83,7 @@ The body of a successfull request will contain details of the package contents i {"Entries":[{"ID":"110d559f-dea5-42ea-9c1c-8a5df7e70ef9","Path":"addeditems/master/sitecore/content/home"}]} The request also takes an optional `DisableIndexing` parameter in the x-www-form-urlencoded form-data which defaults to *false*. When the parameter is set to *true* updating of search indexes during the package installation will be suspended. Disabling the search index updates will increase the speed at which packages are installed into the CMS. You can read more about this approach on Alex Shyba's -[blog](http://sitecoreblog.alexshyba.com/2010/04/sitecore-installation-wizard-disable.html "Sitecore Installation Wizard – disable search index update during install") +[blog](http://sitecoreblog.alexshyba.com/2010/04/sitecore-installation-wizard-disable.html "Sitecore Installation Wizard � disable search index update during install") diff --git a/Sitecore.Ship.sln b/Sitecore.Ship.sln index 223ea6c..4e3b9fe 100644 --- a/Sitecore.Ship.sln +++ b/Sitecore.Ship.sln @@ -2,6 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 +VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F0717179-F14B-4667-8D5A-5980EC935F0F}" EndProject @@ -41,6 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "packaging", "packaging", "{ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{D11D4F10-B2C8-4E1C-BF78-B192D303D20D}" ProjectSection(SolutionItems) = preProject + apiary.apib = apiary.apib docs\Assembly Linkage.dgml = docs\Assembly Linkage.dgml README.md = README.md EndProjectSection diff --git a/apiary.apib b/apiary.apib new file mode 100644 index 0000000..7ab5c25 --- /dev/null +++ b/apiary.apib @@ -0,0 +1,18 @@ +FORMAT: 1A +HOST: http://docs.sitecoreship.apiary.io/ + +# Sitecore.Ship + +The package offers a simple API to help consumers install their packages into Sitecore over an internet connection. + +## Sitecore.Ship API Root [/services] + +Returns information on the currently installed Sitecore.Ship. + +### Retrieve information on the installed Sitecore.Ship [GET] + ++ Response 200 (application/json) + + { + "sitecore.ship.version": "0.4.0" + } \ No newline at end of file diff --git a/build/Build.proj b/build/Build.proj index 01eb207..459207b 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -24,7 +24,7 @@ - + $(ProjectRoot)\build\sitecore packages\SitecoreShip.zip $(ProjectRoot)\tests\acceptance-test\01-package.update @@ -68,7 +68,11 @@ - + + + + + \ No newline at end of file diff --git a/build/build.targets b/build/build.targets index cd4be11..7156601 100644 --- a/build/build.targets +++ b/build/build.targets @@ -97,6 +97,6 @@ - + \ No newline at end of file diff --git a/lib/Readme.md b/lib/Readme.md index 5bcc3b2..3f9e81a 100644 --- a/lib/Readme.md +++ b/lib/Readme.md @@ -7,4 +7,6 @@ The following files need to be placed in the folder: * Sitecore.Update.dll * Sitecore.Zip.dll -These files should be from a 6.x solution, NOT Sitecore 7 \ No newline at end of file +These files should be from a 8.x solution. + +Current testing based on Sitecore 8.0 rev. 141212 (8.0 RTM). \ No newline at end of file diff --git a/src/Sitecore.Ship.AspNet/Publish/InvokePublishingCommand.cs b/src/Sitecore.Ship.AspNet/Publish/InvokePublishingCommand.cs index 7eac7a6..cfe7c52 100644 --- a/src/Sitecore.Ship.AspNet/Publish/InvokePublishingCommand.cs +++ b/src/Sitecore.Ship.AspNet/Publish/InvokePublishingCommand.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Net; using System.Web; @@ -10,67 +11,98 @@ namespace Sitecore.Ship.AspNet.Publish { - public class InvokePublishingCommand : CommandHandler - { - private readonly IPublishService _publishService; - - public InvokePublishingCommand(IPublishService publishService) - { - _publishService = publishService; - } - - public InvokePublishingCommand() : this(new PublishService()) - { - } - - public override void HandleRequest(HttpContextBase context) - { - if (CanHandle(context)) - { - var publishParameters = GetRequest(context.Request); - - var now = DateTime.Now; - var date = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); - - _publishService.Run(publishParameters); - - var json = Json.Encode(new { date }); - - JsonResponse(json, HttpStatusCode.Accepted, context); - } - else if (Successor != null) - { - Successor.HandleRequest(context); - } - } - - private static bool CanHandle(HttpContextBase context) - { - return context.Request.Url != null && - IsPublishModeUrl(context.Request.Url.PathAndQuery.ToLowerInvariant()) && - context.Request.HttpMethod == "POST"; - } - - private static bool IsPublishModeUrl(string urlPath) - { - return urlPath.EndsWith("/services/publish/full") || - urlPath.EndsWith("/services/publish/smart") || - urlPath.EndsWith("/services/publish/incremental"); - } - - private static PublishParameters GetRequest(HttpRequestBase request) - { - if (request.Url == null) throw new InvalidOperationException("Missing Url"); - - var publishRequest = new PublishParameters - { - Mode = request.Url.PathAndQuery.Split(new[] {'/'}).Last(), - Source = request.Form["source"] ?? "master", - Targets = request.Form["targets"].CsvStringToStringArray(new[] { "web" }), - Languages = request.Form["languages"].CsvStringToStringArray(new[] { "en" }) - }; - - return publishRequest; - } - } + public class InvokePublishingCommand : CommandHandler + { + private readonly IPublishService _publishService; + + public InvokePublishingCommand(IPublishService publishService) + { + _publishService = publishService; + } + + public InvokePublishingCommand() : this(new PublishService()) + { + } + + public override void HandleRequest(HttpContextBase context) + { + if (CanHandle(context)) + { + var publishParameters = GetRequest(context.Request); + + var now = DateTime.Now; + var date = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); + + if (publishParameters.Mode.ToLowerInvariant() == "listofitems") + { + using (var reader = new StreamReader(context.Request.InputStream)) + { + var values = reader.ReadToEnd(); + + if (string.IsNullOrEmpty(values)) + { + JsonResponse(string.Empty, HttpStatusCode.NoContent, context); + } + else + { + var itemsToPublish = Json.Decode(values); + + if (itemsToPublish == null) + { + JsonResponse(string.Empty, HttpStatusCode.BadRequest, context); + } + else + { + _publishService.Run(itemsToPublish); + var json = Json.Encode(new { date }); + + JsonResponse(json, HttpStatusCode.Accepted, context); + } + } + } + } + else + { + _publishService.Run(publishParameters); + var json = Json.Encode(new { date }); + + JsonResponse(json, HttpStatusCode.Accepted, context); + } + } + else if (Successor != null) + { + Successor.HandleRequest(context); + } + } + + private static bool CanHandle(HttpContextBase context) + { + return context.Request.Url != null && + IsPublishModeUrl(context.Request.Url.PathAndQuery.ToLowerInvariant()) && + context.Request.HttpMethod == "POST"; + } + + private static bool IsPublishModeUrl(string urlPath) + { + return urlPath.EndsWith("/services/publish/full") || + urlPath.EndsWith("/services/publish/smart") || + urlPath.EndsWith("/services/publish/incremental") || + urlPath.EndsWith("/services/publish/listofitems"); + } + + private static PublishParameters GetRequest(HttpRequestBase request) + { + if (request.Url == null) throw new InvalidOperationException("Missing Url"); + + var publishRequest = new PublishParameters + { + Mode = request.Url.PathAndQuery.Split(new[] {'/'}).Last(), + Source = request.Form["source"] ?? "master", + Targets = request.Form["targets"].CsvStringToStringArray(new[] { "web" }), + Languages = request.Form["languages"].CsvStringToStringArray(new[] { "en" }) + }; + + return publishRequest; + } + } } \ No newline at end of file diff --git a/src/Sitecore.Ship.AspNet/Sitecore.Ship.AspNet.csproj b/src/Sitecore.Ship.AspNet/Sitecore.Ship.AspNet.csproj index d2a655e..ba6541a 100644 --- a/src/Sitecore.Ship.AspNet/Sitecore.Ship.AspNet.csproj +++ b/src/Sitecore.Ship.AspNet/Sitecore.Ship.AspNet.csproj @@ -24,6 +24,7 @@ prompt 4 false + true pdbonly diff --git a/src/Sitecore.Ship.AspNet/app.config b/src/Sitecore.Ship.AspNet/app.config index d497d8f..6df09bc 100644 --- a/src/Sitecore.Ship.AspNet/app.config +++ b/src/Sitecore.Ship.AspNet/app.config @@ -3,9 +3,9 @@ - - + + - + diff --git a/src/Sitecore.Ship.AspNet/content/web.config.transform b/src/Sitecore.Ship.AspNet/content/web.config.transform index 3b56747..02a23b3 100644 --- a/src/Sitecore.Ship.AspNet/content/web.config.transform +++ b/src/Sitecore.Ship.AspNet/content/web.config.transform @@ -4,11 +4,6 @@
- - - - - diff --git a/src/Sitecore.Ship.Core/Domain/InstallPackage.cs b/src/Sitecore.Ship.Core/Domain/InstallPackage.cs index 82ef554..57072b4 100644 --- a/src/Sitecore.Ship.Core/Domain/InstallPackage.cs +++ b/src/Sitecore.Ship.Core/Domain/InstallPackage.cs @@ -5,5 +5,10 @@ public class InstallPackage public string Path { get; set; } public bool DisableIndexing { get; set; } + + /// + /// Set to true to disable reporting of items contained in the package. + /// + public bool DisableManifest { get; set; } } } \ No newline at end of file diff --git a/src/Sitecore.Ship.Core/Domain/InstallUploadPackage.cs b/src/Sitecore.Ship.Core/Domain/InstallUploadPackage.cs index 6fa406c..82d096d 100644 --- a/src/Sitecore.Ship.Core/Domain/InstallUploadPackage.cs +++ b/src/Sitecore.Ship.Core/Domain/InstallUploadPackage.cs @@ -5,5 +5,10 @@ public class InstallUploadPackage public string PackageId { get; set; } public string Description { get; set; } public bool DisableIndexing { get; set; } + + /// + /// Set to true to disable reporting of items contained in the package. + /// + public bool DisableManifest { get; set; } } } \ No newline at end of file diff --git a/src/Sitecore.Ship.Core/Domain/ItemsToPublish.cs b/src/Sitecore.Ship.Core/Domain/ItemsToPublish.cs index 1da9126..dc91859 100644 --- a/src/Sitecore.Ship.Core/Domain/ItemsToPublish.cs +++ b/src/Sitecore.Ship.Core/Domain/ItemsToPublish.cs @@ -3,10 +3,17 @@ namespace Sitecore.Ship.Core.Domain { - public class ItemsToPublish - { - public List Items { get; set; } - public string[] TargetDatabases { get; set; } - public string[] TargetLanguages { get; set; } - } -} + public class ItemsToPublish + { + public List Items { get; set; } + public string[] TargetDatabases { get; set; } + public string[] TargetLanguages { get; set; } + + public ItemsToPublish() + { + Items = new List(); + TargetDatabases = new string[] { }; + TargetLanguages = new string[] { }; + } + } +} \ No newline at end of file diff --git a/src/Sitecore.Ship.Core/Sitecore.Ship.Core.csproj b/src/Sitecore.Ship.Core/Sitecore.Ship.Core.csproj index e5f6f36..d2ad243 100644 --- a/src/Sitecore.Ship.Core/Sitecore.Ship.Core.csproj +++ b/src/Sitecore.Ship.Core/Sitecore.Ship.Core.csproj @@ -22,6 +22,7 @@ prompt 4 false + true pdbonly diff --git a/src/Sitecore.Ship.Infrastructure/PublishService.cs b/src/Sitecore.Ship.Infrastructure/PublishService.cs index 3eda9c6..a036f49 100644 --- a/src/Sitecore.Ship.Infrastructure/PublishService.cs +++ b/src/Sitecore.Ship.Infrastructure/PublishService.cs @@ -12,78 +12,88 @@ namespace Sitecore.Ship.Infrastructure { - public class PublishService : IPublishService - { - private readonly Dictionary> _publishingActions; - - public PublishService() - { - _publishingActions = new Dictionary> - { - { "full", Publishing.PublishManager.Republish }, - { "smart", Publishing.PublishManager.PublishSmart }, - { "incremental", Publishing.PublishManager.PublishIncremental } - }; - } - - public void Run(ItemsToPublish itemsToPublish) - { - using (new SecurityModel.SecurityDisabler()) - { - var master = Sitecore.Configuration.Factory.GetDatabase("master"); - var languages = itemsToPublish.TargetLanguages.Select(LanguageManager.GetLanguage).ToArray(); - - foreach (var itemToPublish in itemsToPublish.Items) - { - var item = master.GetItem(new ID(itemToPublish)); - if (item != null) - { - Publishing.PublishManager.PublishItem(item, itemsToPublish.TargetDatabases.Select(Sitecore.Configuration.Factory.GetDatabase).ToArray(), languages, true, true); - } - } - } - } - - public void Run(PublishParameters publishParameters) - { - var publishingMode = publishParameters.Mode.ToLower(); - - if (!_publishingActions.ContainsKey(publishingMode)) - { - throw new InvalidOperationException(string.Format("Invalid publishing mode ({0})", publishingMode)); - } - - PublishingTask(_publishingActions[publishingMode], publishParameters); - } - - public DateTime GetLastCompletedRun(PublishLastCompleted completeParameters) - { - // please note http://stackoverflow.com/questions/12416141/get-the-date-time-that-sitecore-last-published - - var source = Sitecore.Configuration.Factory.GetDatabase(completeParameters.Source); - var target = Sitecore.Configuration.Factory.GetDatabase(completeParameters.Target); - - var language = LanguageManager.GetLanguage(completeParameters.Language); - - - Assert.IsNotNull(source, "Source database {0} cannot be found".Formatted(completeParameters.Source)); - Assert.IsNotNull(source, "Target database {0} cannot be found".Formatted(completeParameters.Target)); - Assert.IsNotNull(language, "Language {0} cannot be found".Formatted(completeParameters.Language)); - - var date = source.Properties.GetLastPublishDate(target, language); - return date; - } - - private static void PublishingTask(Func publishType, PublishParameters publishParameters) - { - using (new SecurityModel.SecurityDisabler()) - { - var master = Sitecore.Configuration.Factory.GetDatabase(publishParameters.Source); - var targetDBs = publishParameters.Targets.Select(Sitecore.Configuration.Factory.GetDatabase).ToArray(); - var languages = publishParameters.Languages.Select(LanguageManager.GetLanguage).ToArray(); - - publishType(master, targetDBs, languages); - } - } - } + public class PublishService : IPublishService + { + private readonly Dictionary> _publishingActions; + + public PublishService() + { + _publishingActions = new Dictionary> + { + { "full", Publishing.PublishManager.Republish }, + { "smart", Publishing.PublishManager.PublishSmart }, + { "incremental", Publishing.PublishManager.PublishIncremental } + }; + } + + public void Run(ItemsToPublish itemsToPublish) + { + if (itemsToPublish == null) + { + throw new ArgumentNullException("itemsToPublish"); + } + + if (itemsToPublish.Items.Count == 0) + { + return; + } + + using (new SecurityModel.SecurityDisabler()) + { + var master = Sitecore.Configuration.Factory.GetDatabase("master"); + var languages = itemsToPublish.TargetLanguages.Select(LanguageManager.GetLanguage).ToArray(); + + foreach (var itemToPublish in itemsToPublish.Items) + { + var item = master.GetItem(new ID(itemToPublish)); + if (item != null) + { + Publishing.PublishManager.PublishItem(item, itemsToPublish.TargetDatabases.Select(Sitecore.Configuration.Factory.GetDatabase).ToArray(), languages, true, true); + } + } + } + } + + public void Run(PublishParameters publishParameters) + { + var publishingMode = publishParameters.Mode.ToLower(); + + if (!_publishingActions.ContainsKey(publishingMode)) + { + throw new InvalidOperationException(string.Format("Invalid publishing mode ({0})", publishingMode)); + } + + PublishingTask(_publishingActions[publishingMode], publishParameters); + } + + public DateTime GetLastCompletedRun(PublishLastCompleted completeParameters) + { + // please note http://stackoverflow.com/questions/12416141/get-the-date-time-that-sitecore-last-published + + var source = Sitecore.Configuration.Factory.GetDatabase(completeParameters.Source); + var target = Sitecore.Configuration.Factory.GetDatabase(completeParameters.Target); + + var language = LanguageManager.GetLanguage(completeParameters.Language); + + + Assert.IsNotNull(source, "Source database {0} cannot be found".Formatted(completeParameters.Source)); + Assert.IsNotNull(source, "Target database {0} cannot be found".Formatted(completeParameters.Target)); + Assert.IsNotNull(language, "Language {0} cannot be found".Formatted(completeParameters.Language)); + + var date = source.Properties.GetLastPublishDate(target, language); + return date; + } + + private static void PublishingTask(Func publishType, PublishParameters publishParameters) + { + using (new SecurityModel.SecurityDisabler()) + { + var master = Sitecore.Configuration.Factory.GetDatabase(publishParameters.Source); + var targetDBs = publishParameters.Targets.Select(Sitecore.Configuration.Factory.GetDatabase).ToArray(); + var languages = publishParameters.Languages.Select(LanguageManager.GetLanguage).ToArray(); + + publishType(master, targetDBs, languages); + } + } + } } \ No newline at end of file diff --git a/src/Sitecore.Ship.Infrastructure/Sitecore.Ship.Infrastructure.csproj b/src/Sitecore.Ship.Infrastructure/Sitecore.Ship.Infrastructure.csproj index 989a3ef..64b21b0 100644 --- a/src/Sitecore.Ship.Infrastructure/Sitecore.Ship.Infrastructure.csproj +++ b/src/Sitecore.Ship.Infrastructure/Sitecore.Ship.Infrastructure.csproj @@ -22,6 +22,7 @@ prompt 4 false + true pdbonly diff --git a/src/Sitecore.Ship/DefaultBootstrapper.cs b/src/Sitecore.Ship/DefaultBootstrapper.cs index a3ba573..1df832b 100644 --- a/src/Sitecore.Ship/DefaultBootstrapper.cs +++ b/src/Sitecore.Ship/DefaultBootstrapper.cs @@ -33,8 +33,6 @@ protected override void ConfigureConventions(Nancy.Conventions.NancyConventions protected override void ConfigureApplicationContainer(TinyIoCContainer container) { - base.ConfigureApplicationContainer(container); - container.AutoRegister(new[] { typeof (IPackageRepository).Assembly, diff --git a/src/Sitecore.Ship/Package/Install/InstallerModule.cs b/src/Sitecore.Ship/Package/Install/InstallerModule.cs index 48b0e8c..08757f7 100644 --- a/src/Sitecore.Ship/Package/Install/InstallerModule.cs +++ b/src/Sitecore.Ship/Package/Install/InstallerModule.cs @@ -39,6 +39,12 @@ private dynamic InstallPackage(dynamic o) var manifest = _repository.AddPackage(package); _installationRecorder.RecordInstall(package.Path, DateTime.Now); + if (package.DisableManifest) + { + // Skip manifest reporting. Nancy will return an empty message body. + manifest = null; + } + return Response .AsJson(manifest, HttpStatusCode.Created) .WithHeader("Location", ShipServiceUrl.PackageLatestVersion); @@ -81,6 +87,12 @@ private dynamic InstallUploadPackage(dynamic o) _tempPackager.Dispose(); } + if (uploadPackage.DisableManifest) + { + // Skip manifest reporting. Nancy will return an empty message body. + manifest = null; + } + return Response .AsJson(manifest, HttpStatusCode.Created) .WithHeader("Location", ShipServiceUrl.PackageLatestVersion); diff --git a/src/Sitecore.Ship/Sitecore.Ship.csproj b/src/Sitecore.Ship/Sitecore.Ship.csproj index 02bb721..d8bad03 100644 --- a/src/Sitecore.Ship/Sitecore.Ship.csproj +++ b/src/Sitecore.Ship/Sitecore.Ship.csproj @@ -24,6 +24,7 @@ prompt 4 false + true pdbonly diff --git a/src/Sitecore.Ship/app.config b/src/Sitecore.Ship/app.config index d497d8f..6df09bc 100644 --- a/src/Sitecore.Ship/app.config +++ b/src/Sitecore.Ship/app.config @@ -3,9 +3,9 @@ - - + + - + diff --git a/src/Sitecore.Ship/content/web.config.transform b/src/Sitecore.Ship/content/web.config.transform index a1faff4..195d387 100644 --- a/src/Sitecore.Ship/content/web.config.transform +++ b/src/Sitecore.Ship/content/web.config.transform @@ -8,11 +8,6 @@ - - - - - diff --git a/src/Sitecore.Ship/packages.config b/src/Sitecore.Ship/packages.config index 5878cae..3f09925 100644 --- a/src/Sitecore.Ship/packages.config +++ b/src/Sitecore.Ship/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file