Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Basic implementation that satisfies acceptance tests for 2 of the
primary goals
  • Loading branch information
richardszalay committed Oct 9, 2017
0 parents commit dd94a0d
Show file tree
Hide file tree
Showing 18 changed files with 1,099 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
obj/
bin/
*.user
.vs/
**/packages/

*.dll
*.config
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2017 Richard Szalay

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
This is proof of concept prototype for seamlessly integrating the Helix solution structure with the Web Publishing Pipeline feature of .NET and Visual Studio. Specifically, it attempts to merge Helix modules from lower layers (foundation, features) with the top layer (project) when it comes to publishing.

The desire for this project comes from Helix itself. While the Helix recommendation states that

Design principles:

* Adding these targets to a Project should provide as much functionality as possible (ie. sensible defaults)
* Stick to WPP integration points wherever possible
* Everything should be extensible
* Everything should be test driven

Primary use cases that I'm looking to actively support:

* Packaging a project module
* Publishing a project module to a remote server
* Publishing a project/feature module to a local folder/website

Secondary use cases that I'll look to support later:

* Packaging a feature module
* Publishing a feature module to a remote server

Primary feature goals:

- [x] Include content / config from dependent modules
- [x] Allow modules to contribute Web Deploy parameter definitions
- [ ] Allow modules to contribute Web.config transforms
- [ ] Provide PowerShell Cmdlets for publishing that support publishing specific types of content (eg. content only, to avoid recycling the app pool)

Secondary feature goals:

- [ ] Maintain "Publish from Visual Studio compatibility"
- [ ] Provide content type skipping as MSBuild functionality so it can be supported without the PowerShell Cmdlets
- [ ] Decide on whether recursive "dependent module" support is feasible, or whether it should use folder structure conventions
- [ ] Allow modules to contribute any .config transform
113 changes: 113 additions & 0 deletions src/RichardSzalay.Helix.Build.Common.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<Project>
<PropertyGroup>
<SolutionDir Condition="'$(SolutionDir)'=='*Undefined*'">$(MSBuildProjectDirectory)\..\..\</SolutionDir>
<HelixModuleSourcePath></HelixModuleSourcePath>
</PropertyGroup>

<!-- Conventions -->
<PropertyGroup>
<HelixModuleFeaturesDirectory Condition="'$(HelixModuleFeaturesDirectory)' == ''">Features</HelixModuleFeaturesDirectory>
<HelixModuleFoundationDirectory Condition="'$(HelixModuleFoundationDirectory)' == ''">Foundation</HelixModuleFoundationDirectory>
<HelixModuleSourceDirectory Condition="'$(HelixModuleSourceDirectory)' == ''"></HelixModuleSourceDirectory>
<HelixModuleWebContentDirectory Condition="'$(HelixModuleWebContentDirectory)' == ''"></HelixModuleWebContentDirectory>
</PropertyGroup>

<Target Name="GatherDependentHelixModules">
<ItemGroup>
<HelixModulePaths Include="$([System.IO.Directory]::GetDirectories(`$(SolutionDir)$(HelixModuleFoundationDirectory)`))" />
<HelixModulePaths Include="$([System.IO.Directory]::GetDirectories(`$(SolutionDir)$(HelixModuleFeaturesDirectory)`))" />
</ItemGroup>
</Target>

<!-- Content -->
<PropertyGroup>
<PipelineCollectFilesPhaseDependsOn>
$(PipelineCollectFilesPhaseDependsOn);
CollectFilesFromHelixModules;
</PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>

<PropertyGroup>
<CollectFilesFromHelixModulesMode Condition="'$(CollectFilesFromHelixModules)'==''">FileSystemWhitelist</CollectFilesFromHelixModulesMode>
<CollectFilesFromHelixModulesDependsOn>
$(CollectFilesFromHelixModulesDependsOn);
GatherDependentHelixModules;
CollectFilesFromHelixModules$(CollectFilesFromHelixModulesMode);
</CollectFilesFromHelixModulesDependsOn>
</PropertyGroup>

<Target Name="CollectFilesFromHelixModules" DependsOnTargets="$(CollectFilesFromHelixModulesDependsOn)">
<ItemGroup>
<FilesForPackagingFromProject Include="@(FilesForPackagingFromHelixModules)" />
</ItemGroup>
</Target>

<!-- File System (Whitelist) implementation of CollectFilesFromHelixModules -->
<Target Name="CollectFilesFromHelixModulesFileSystemWhitelist">
<!-- TODO: Figure out how to do this dynamically from an item list of wildcard matches -->
<PropertyGroup>
<_HelixModuleContentPath>$(HelixModuleSourceDirectory)$(HelixModuleWebContentDirectory)</_HelixModuleContentPath>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\App_Config\**\*')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.cshtml')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.vbhtml')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.css')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.js')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.svg')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.png')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.jpg')</HelixModuleContentInclude>
<HelixModuleContentInclude>$(HelixModuleContentInclude);@(HelixModulePaths -> '%(FullPath)$(_HelixModuleContentPath)\**\*.jpeg')</HelixModuleContentInclude>
</PropertyGroup>

<ItemGroup>
<_HelixModuleContentSpecs Include="@(HelixModulePaths -> '%(FullPath)$(HelixModuleSourceDirectory)\**\*')">
<HelixModulePath>%(FullPath)$(HelixModuleSourceDirectory)</HelixModulePath>
</_HelixModuleContentSpecs>
</ItemGroup>

<CreateItem Include="@(_HelixModuleContentSpecs)" PreserveExistingMetadata="true">
<Output TaskParameter="Include" ItemName="_HelixModuleContent"/>
</CreateItem>

<ItemGroup>
<_HelixModuleExcludedContent Include="@(_HelixModuleContent)" Exclude="$(HelixModuleContentInclude)" />
<_HelixModuleIncludedContent Include="@(_HelixModuleContent)" Exclude="@(_HelixModuleExcludedContent)" />

<FilesForPackagingFromHelixModules Include="@(_HelixModuleIncludedContent)">
<DestinationRelativePath>$([MSBuild]::MakeRelative('%(_HelixModuleIncludedContent.HelixModulePath)', '%(FullPath)'))</DestinationRelativePath>
<FromTarget>CollectFilesFromHelixModuleContent</FromTarget>
</FilesForPackagingFromHelixModules>
</ItemGroup>
</Target>

<!-- Parameters -->
<PropertyGroup>
<ImportParametersFilesDependsOn>
$(ImportParametersFilesDependsOn);
GatherHelixParameterXMLFiles
</ImportParametersFilesDependsOn>
</PropertyGroup>
<PropertyGroup>
<GatherHelixParameterXMLFilesDependsOn>
$(GatherHelixParameterXMLFilesDependsOn);
GatherDependentHelixModules
</GatherHelixParameterXMLFilesDependsOn>
</PropertyGroup>
<Target Name="GatherHelixParameterXMLFiles" DependsOnTargets="$(GatherHelixParameterXMLFilesDependsOn)">
<ItemGroup>
<HelixModuleProjectPaths Include="@(HelixModulePaths -> '%(FullPath)\$(HelixModuleSourcePath)')" />
<HelixModuleParameterFiles Include="@(HelixModuleProjectPaths -> '%(FullPath)Parameters.xml')" />
<ParametersXMLFiles Include="@(HelixModuleParameterFiles)" Condition="'%(HelixModuleParameterFiles.Identity)' != ''" />
</ItemGroup>
</Target>

<PropertyGroup>
<DisableProjectReferenceDeployOnBuild Condition="'$(DisableProjectReferenceDeployOnBuild)'==''">true</DisableProjectReferenceDeployOnBuild>
</PropertyGroup>
<ItemGroup Condition="'$(DisableProjectReferenceDeployOnBuild)'=='true'">
<_ProjectReferenceTmp Include="@(ProjectReference)" />
<ProjectReference Remove="@(ProjectReference)" />
<ProjectReference Include="@(_ProjectReferenceTmp)">
<GlobalPropertiesToRemove>DeployOnBuild</GlobalPropertiesToRemove>
</ProjectReference>
</ItemGroup>
</Project>
76 changes: 76 additions & 0 deletions src/tests/Acceptance.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
. "$PSScriptRoot/utils/MSBuild.ps1"
. "$PSScriptRoot/utils/MSDeploy.ps1"

$fixtures = @{
default = @{
Solution = "$PSScriptRoot\fixtures/default/HelixBuild.Sample.Web.sln";
Project1 = "$PSScriptRoot\fixtures/default/Projects\HelixBuild.Sample.Web\HelixBuild.Sample.Web.csproj";
}

}

Describe "Default fixture" {

Context "building package with default settings" {
$projectPath = $fixtures.default.Project1
$projectDir = Split-Path $projectPath -Parent

Invoke-MSBuild -Project $projectPath -Properties @{
"DeployOnBuild" = "true";
"PublishProfile" = "Package";
"DeployAsIisApp" = "false";
}

$packageFilename = Join-Path $projectDir "obj\Debug\Package\HelixBuild.Sample.Web.zip"

$packageParameters = Get-MSDeployPackageParameters $packageFilename
$packageParameterNames = $packageParameters.Keys

$packageFiles = Get-MSDeployPackageFiles $packageFilename

$webConfigXml = [xml](Get-MSDeployPackageFileContent -PackagePath $packageFilename -FilePath "Web.config")

It "should include web deploy parameters from the packaged project" {
$packageParameterNames -contains "Project-Parameter1" | Should Be $true
}

It "should include web deploy parameters from all feature modules" {
$packageParameterNames -contains "Feature1-Parameter1" | Should Be $true
}

It "should include web deploy parameters from all foundation modules" {
$packageParameterNames -contains "Foundation1-Parameter1" | Should Be $true
}

It "should include content from the packaged project" {
$packageFiles -contains "App_Config\Include\HelixBuild.Sample.Web.config" | Should Be $true
}

It "should include content from the all feature modules" {
$packageFiles -contains "App_Config\Include\HelixBuild.Feature1.config" | Should Be $true
}

It "should include content from the all foundation modules" {
$packageFiles -contains "App_Config\Include\HelixBuild.Foundation1.config" | Should Be $true

}

It "should include Web.config from the packaged project" {
$result = Select-Xml -Xml $webConfigXml -XPath "//appSettings/add[@key='HelixProject']/@value"

$result | Should Be "Sample.Web"
}

It "should not include include Web.config from any feature modules" {
$result = Select-Xml -Xml $webConfigXml -XPath "//appSettings/add[@key='HelixBuild.Feature1']/@value"

$result | Should Be $null
}

It "should not include include Web.config from any foundation modules" {
$result = Select-Xml -Xml $webConfigXml -XPath "//appSettings/add[@key='HelixBuild.Foundation1']/@value"

$result | Should Be $null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\Projects\HelixBuild.Sample.Web\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.5\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\..\Projects\HelixBuild.Sample.Web\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.5\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
<Import Project="..\..\Projects\HelixBuild.Sample.Web\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\Projects\HelixBuild.Sample.Web\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{55ED6F62-650D-4C68-89D7-7CE71D76E2A7}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HelixBuild.Feature1</RootNamespace>
<AssemblyName>HelixBuild.Feature1</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<UseIISExpress>true</UseIISExpress>
<Use64BitIISExpress />
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.5\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
<None Include="App_Config\Include\HelixBuild.Feature1.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</None>
<None Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="Parameters.xml" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>64950</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:64950/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\Projects\HelixBuild.Sample.Web\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.5\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\Projects\HelixBuild.Sample.Web\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.5\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
Loading

0 comments on commit dd94a0d

Please sign in to comment.