Skip to content

Commit

Permalink
support no-repository deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
suwatch committed Jun 3, 2013
1 parent 5ccdb70 commit 9f64e41
Show file tree
Hide file tree
Showing 19 changed files with 470 additions and 47 deletions.
3 changes: 3 additions & 0 deletions Kudu.Contracts/Deployment/DeployResult.cs
Expand Up @@ -53,6 +53,9 @@ public class DeployResult
[DataMember(Name = "is_temp")]
public bool IsTemporary { get; set; }

[DataMember(Name = "is_readonly")]
public bool IsReadOnly { get; set; }

[DataMember(Name = "url")]
public Uri Url { get; set; }

Expand Down
1 change: 1 addition & 0 deletions Kudu.Contracts/Deployment/IDeploymentStatusFile.cs
Expand Up @@ -18,6 +18,7 @@ public interface IDeploymentStatusFile
DateTime? LastSuccessEndTime { get; set; }
bool Complete { get; set; }
bool IsTemporary { get; set; }
bool IsReadOnly { get; set; }

void Save();
}
Expand Down
3 changes: 3 additions & 0 deletions Kudu.Contracts/Kudu.Contracts.csproj
Expand Up @@ -22,6 +22,9 @@
<Compile Include="..\Common\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="..\Common\Constants.cs">
<Link>Constants.cs</Link>
</Compile>
<Compile Include="Commands\CommandEvent.cs" />
<Compile Include="Commands\CommandEventType.cs" />
<Compile Include="Commands\CommandResult.cs" />
Expand Down
19 changes: 17 additions & 2 deletions Kudu.Contracts/Settings/DeploymentSettingsExtension.cs
Expand Up @@ -10,7 +10,6 @@ public static class DeploymentSettingsExtension
public static readonly TimeSpan DefaultCommandIdleTimeout = TimeSpan.FromMinutes(1);
public static readonly TimeSpan DefaultLogStreamTimeout = TimeSpan.FromMinutes(30);
public const TraceLevel DefaultTraceLevel = TraceLevel.Error;
public const string DefaultRepositoryPath = "repository";

public static string GetValue(this IDeploymentSettingsManager settings, string key)
{
Expand Down Expand Up @@ -112,7 +111,23 @@ public static bool IsScmEnabled(this IDeploymentSettingsManager settings)
public static string GetRepositoryPath(this IDeploymentSettingsManager settings)
{
string repositoryPath = settings.GetValue(SettingsKeys.RepositoryPath);
return !String.IsNullOrEmpty(repositoryPath) ? repositoryPath : DefaultRepositoryPath;
if (!String.IsNullOrEmpty(repositoryPath))
{
return repositoryPath;
}

// in case of no repository, we will default to webroot (preferring inplace).
if (settings.IsNullRepository())
{
return Constants.WebRoot;
}

return Constants.RepositoryPath;
}

public static bool IsNullRepository(this IDeploymentSettingsManager settings)
{
return settings.GetValue(SettingsKeys.NoRepository) == "1";
}
}
}
1 change: 1 addition & 0 deletions Kudu.Contracts/Settings/SettingsKeys.cs
Expand Up @@ -21,5 +21,6 @@ public static class SettingsKeys
public const string Project = "PROJECT";
public const string TargetPath = "SCM_TARGET_PATH";
public const string RepositoryPath = "SCM_REPOSITORY_PATH";
public const string NoRepository = "SCM_NO_REPOSITORY";
}
}
6 changes: 6 additions & 0 deletions Kudu.Contracts/SourceControl/ChangeSet.cs
Expand Up @@ -49,6 +49,12 @@ public bool IsTemporary
set;
}

public bool IsReadOnly
{
get;
set;
}

public override string ToString()
{
return String.Format("{0} {1} {2} {3}", Id, Timestamp, AuthorName, Message);
Expand Down
2 changes: 2 additions & 0 deletions Kudu.Core.Test/Deployment/DeploymentManagerFacts.cs
Expand Up @@ -92,6 +92,8 @@ public class TestDeploymentStatusFile : IDeploymentStatusFile

public bool IsTemporary { get; set; }

public bool IsReadOnly { get; set; }

public void Save()
{
// Do nothing.
Expand Down
2 changes: 2 additions & 0 deletions Kudu.Core.Test/Kudu.Core.Test.csproj
Expand Up @@ -44,6 +44,7 @@
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="XmlSettings, Version=0.1.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
Expand Down Expand Up @@ -77,6 +78,7 @@
<Compile Include="GitRepositoryTest.cs" />
<Compile Include="IniFileFacts.cs" />
<Compile Include="LockFileTests.cs" />
<Compile Include="NullRepositoryFacts.cs" />
<Compile Include="OperationLockTests.cs" />
<Compile Include="PathUtilityFacts.cs" />
<Compile Include="ProcessApiFacts.cs" />
Expand Down
121 changes: 121 additions & 0 deletions Kudu.Core.Test/NullRepositoryFacts.cs
@@ -0,0 +1,121 @@
using System;
using System.Collections;
using System.IO;
using System.Web;
using Kudu.Contracts.Settings;
using Kudu.Contracts.Tracing;
using Kudu.Core.SourceControl;
using Kudu.Core.Tracing;
using Moq;
using Xunit;
using Xunit.Extensions;

namespace Kudu.Core.Test
{
public class NullRepositoryFacts
{
[Theory]
[InlineData("wwwroot", null, "1")]
[InlineData("repository", null, "0")]
[InlineData("dummy", "dummy", "1")]
[InlineData("dummy", "dummy", null)]
public void NullRepositoryPathTests(string expected, string repositoryPath, string noRepository)
{
// arrange
var settings = MockSettings(repositoryPath, noRepository);

// Assert
Assert.Equal(expected, settings.Object.GetRepositoryPath());
}

[Fact]
public void NullRepositoryCommitTests()
{
// arrange
var settings = MockSettings();
var environment = MockEnviroment(@"x:\site", settings.Object);
var traceFactory = MockTraceFactory();
var httpContext = MockHttpContext();

// test
var repository = new NullRepository(environment.Object, traceFactory.Object, httpContext.Object);

// Assert
Assert.Equal(RepositoryType.None, repository.RepositoryType);
Assert.Equal(environment.Object.RepositoryPath, repository.RepositoryPath);
Assert.Null(repository.CurrentId);
Assert.Throws<InvalidOperationException>(() => repository.GetChangeSet("dummy"));
Assert.Throws<InvalidOperationException>(() => repository.GetChangeSet("master"));

// Simple commit
var message = "this is testing";
var author = "john doe";
var email = "john.doe@live.com";
var success = repository.Commit(message, author + " <" + email + ">");

// Assert
Assert.True(success);
Assert.NotNull(repository.CurrentId);

// Validate changeset
var changeSet = repository.GetChangeSet(repository.CurrentId);

// Assert
Assert.NotNull(changeSet);
Assert.Equal(message, changeSet.Message);
Assert.Equal(author, changeSet.AuthorName);
Assert.Equal(email, changeSet.AuthorEmail);
Assert.True(changeSet.IsReadOnly);
Assert.Equal(repository.CurrentId, changeSet.Id);
Assert.Throws<InvalidOperationException>(() => repository.GetChangeSet("dummy"));
Assert.Same(changeSet, repository.GetChangeSet("master"));
Assert.Same(changeSet, repository.GetChangeSet(repository.CurrentId));
}

private Mock<IDeploymentSettingsManager> MockSettings(string repositoryPath = null, string noRepository = "1")
{
var settings = new Mock<IDeploymentSettingsManager>(MockBehavior.Strict);

// setup
settings.Setup(s => s.GetValue(SettingsKeys.RepositoryPath, false))
.Returns(repositoryPath);
settings.Setup(s => s.GetValue(SettingsKeys.NoRepository, false))
.Returns(noRepository);

return settings;
}

private Mock<IEnvironment> MockEnviroment(string sitePath, IDeploymentSettingsManager settings)
{
var environment = new Mock<IEnvironment>(MockBehavior.Strict);

// setup
environment.SetupGet(e => e.RepositoryPath)
.Returns(() => Path.Combine(sitePath, settings.GetRepositoryPath()));

return environment;
}

private Mock<ITraceFactory> MockTraceFactory()
{
var traceFactory = new Mock<ITraceFactory>(MockBehavior.Strict);

// setup
traceFactory.Setup(t => t.GetTracer())
.Returns(Mock.Of<ITracer>());

return traceFactory;
}

private Mock<HttpContextBase> MockHttpContext()
{
var httpContext = new Mock<HttpContextBase>(MockBehavior.Strict);

// setup
httpContext.SetupGet(c => c.Items)
.Returns(new Hashtable());

return httpContext;
}
}
}
42 changes: 26 additions & 16 deletions Kudu.Core.Test/RepositoryFactoryFacts.cs
@@ -1,32 +1,42 @@
using System;
using System.Web;
using Kudu.Contracts.Settings;
using Kudu.Core.SourceControl;
using Kudu.Core.SSHKey;
using Kudu.Core.Tracing;
using Moq;
using Xunit;
using Xunit.Extensions;

namespace Kudu.Core.Test
{
public class RepositoryFactoryFacts
{
[Theory]
[InlineData(RepositoryType.Git, false, true, "Expected a 'Git' repository but found a 'Mercurial' repository at path ''.")]
[InlineData(RepositoryType.Mercurial, true, false, "Expected a 'Mercurial' repository but found a 'Git' repository at path ''.")]
public void EnsuringGitRepositoryThrowsIfDifferentRepositoryAlreadyExists(RepositoryType repoType, bool isGit, bool isMercurial, string message)
[Fact]
public void EnsuringGitRepositoryThrowsIfDifferentRepositoryAlreadyExists()
{
// Arrange
var repoFactory = new Mock<RepositoryFactory>(Mock.Of<IEnvironment>(), Mock.Of<IDeploymentSettingsManager>(), Mock.Of<ITraceFactory>()) { CallBase = true };
repoFactory.SetupGet(f => f.IsGitRepository)
.Returns(isGit);
repoFactory.SetupGet(f => f.IsHgRepository)
.Returns(isMercurial);

// Act and Assert
var ex = Assert.Throws<InvalidOperationException>(() => repoFactory.Object.EnsureRepository(repoType));
foreach (RepositoryType repoType in Enum.GetValues(typeof(RepositoryType)))
{
foreach (RepositoryType currentType in Enum.GetValues(typeof(RepositoryType)))
{
if (repoType == currentType)
{
continue;
}

Assert.Equal(message, ex.Message);
// Arrange
var repoFactory = new Mock<RepositoryFactory>(Mock.Of<IEnvironment>(), Mock.Of<IDeploymentSettingsManager>(), Mock.Of<ITraceFactory>(), Mock.Of<HttpContextBase>()) { CallBase = true };
repoFactory.SetupGet(f => f.IsNullRepository)
.Returns(currentType == RepositoryType.None);
repoFactory.SetupGet(f => f.IsGitRepository)
.Returns(currentType == RepositoryType.Git);
repoFactory.SetupGet(f => f.IsHgRepository)
.Returns(currentType == RepositoryType.Mercurial);

// Act and Assert
var ex = Assert.Throws<InvalidOperationException>(() => repoFactory.Object.EnsureRepository(repoType));

Assert.Equal(String.Format("Expected a '{0}' repository but found a '{1}' repository at path ''.", repoType, currentType), ex.Message);
}
}
}
}
}
3 changes: 3 additions & 0 deletions Kudu.Core/Deployment/DeploymentManager.cs
Expand Up @@ -254,6 +254,7 @@ public IDisposable CreateTemporaryDeployment(string statusText, out ChangeSet te
statusFile.Status = DeployStatus.Pending;
statusFile.StatusText = statusText;
statusFile.IsTemporary = changeSet.IsTemporary;
statusFile.IsReadOnly = changeSet.IsReadOnly;
statusFile.Save();
}

Expand Down Expand Up @@ -411,6 +412,7 @@ internal IDeploymentStatusFile GetOrCreateStatusFile(ChangeSet changeSet, ITrace
statusFile.Author = changeSet.AuthorName;
statusFile.Deployer = deployer;
statusFile.AuthorEmail = changeSet.AuthorEmail;
statusFile.IsReadOnly = changeSet.IsReadOnly;
statusFile.Save();

return statusFile;
Expand Down Expand Up @@ -440,6 +442,7 @@ private DeployResult GetResult(string id, string activeDeploymentId, bool isDepl
StatusText = file.StatusText,
Complete = file.Complete,
IsTemporary = file.IsTemporary,
IsReadOnly = file.IsReadOnly,
Current = file.Id == activeDeploymentId,
ReceivedTime = file.ReceivedTime,
LastSuccessEndTime = file.LastSuccessEndTime
Expand Down
13 changes: 12 additions & 1 deletion Kudu.Core/Deployment/DeploymentStatusFile.cs
Expand Up @@ -96,6 +96,14 @@ private void Initialize(XDocument document)
Boolean.TryParse(isTemporaryValue, out isTemporary);
}

bool isReadOnly = false;
string isReadOnlyValue = GetOptionalElementValue(document.Root, "is_readonly");

if (!String.IsNullOrEmpty(isReadOnlyValue))
{
Boolean.TryParse(isReadOnlyValue, out isReadOnly);
}

Id = document.Root.Element("id").Value;
Author = GetOptionalElementValue(document.Root, "author");
Deployer = GetOptionalElementValue(document.Root, "deployer");
Expand All @@ -110,6 +118,7 @@ private void Initialize(XDocument document)
LastSuccessEndTime = ParseDateTime(lastSuccessEndTimeValue);
Complete = complete;
IsTemporary = isTemporary;
IsReadOnly = isReadOnly;
}

public string Id { get; set; }
Expand All @@ -126,6 +135,7 @@ private void Initialize(XDocument document)
public DateTime? LastSuccessEndTime { get; set; }
public bool Complete { get; set; }
public bool IsTemporary { get; set; }
public bool IsReadOnly { get; set; }

public void Save()
{
Expand All @@ -148,7 +158,8 @@ public void Save()
new XElement("startTime", StartTime),
new XElement("endTime", EndTime),
new XElement("complete", Complete.ToString()),
new XElement("is_temp", IsTemporary.ToString())
new XElement("is_temp", IsTemporary.ToString()),
new XElement("is_readonly", IsReadOnly.ToString())
));

_statusLock.LockOperation(() =>
Expand Down
5 changes: 2 additions & 3 deletions Kudu.Core/Kudu.Core.csproj
Expand Up @@ -29,6 +29,7 @@
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="XmlSettings, Version=0.1.3.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
Expand All @@ -39,9 +40,6 @@
<Compile Include="..\Common\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="..\Common\Constants.cs">
<Link>Constants.cs</Link>
</Compile>
<Compile Include="Commands\CommandExecutor.cs" />
<Compile Include="Deployment\CascadeLogger.cs" />
<Compile Include="Deployment\DeploymentStatusFileExtensions.cs" />
Expand Down Expand Up @@ -89,6 +87,7 @@
<Compile Include="Settings\DeploymentSettingsManager.cs" />
<Compile Include="Settings\JsonSettings.cs" />
<Compile Include="Settings\SettingsProvidersPriority.cs" />
<Compile Include="SourceControl\NullRepository.cs" />
<Compile Include="SourceControl\Git\KnownEnvironment.cs" />
<Compile Include="SourceControl\RepositoryExtensions.cs" />
<Compile Include="SourceControl\RepositoryFactory.cs" />
Expand Down

0 comments on commit 9f64e41

Please sign in to comment.