Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deploying an existing package using publish profiles

I'm trying to use the new publish profile support (available in VS2012 and in VS2010 via an update) to create a continuous delivery "deployment pipeline", whereby a package/zip is made in the first "stage" and the same package is deployed to various environments using different configurations.

What tasks/properties are involved in deploying an existing package using settings defined in a pubxml file, from the command line, and without causing a build? Put another way, I'd like to "publish" to a package, then later "publish" that same package to another profile without rebuilding it.

(I know I can use MSDeploy directly, but I'd prefer to have less plumbing on each project if possible)

like image 378
Richard Szalay Avatar asked Jul 27 '12 07:07

Richard Szalay


People also ask

What is a publish profile?

A publish profile is a file that contains information and settings that Visual Studio uses to deploy applications and services to Azure. In the Azure portal, open the Azure App Service. Go to Get publish profile and save the profile locally.

Where are publish profiles stored?

Publish profile files are named <profilename>. pubxml and are located in the PublishProfiles folder. The PublishProfiles folder is under Properties in a C# web application project, under My Project in a VB web application project, or under App_Data in a web site project.

How do I install a Pubxml file?

In order to create a new profile once you have already defined one, you have to open the "Publish" window (righ click on the project), click on the "Profile" tab and select the <New...> option from the drop-down list; this will create a new pubxml file (see screenshot).


1 Answers

UPDATE 2014-01-28

Keeping my custom script up to date with the changing versions of VS / Azure SDK ended up being too much hard work, so I've actually reverted to using the generated deploy.cmd script, with one minor difference:

I've started leaving all my parameter values out of the ProfileName.pubxml file and instead putting them in a ProfileName.paramters.xml (example generated in .SetParameters.xml with package, docs here). These will automatically be picked up by Visual Studio / MSBuild by convention and I can use them at runtime by passing in -setParamFile:path\to\ProfileName.parameters.xml when calling deploy.cmd

UPDATE - A newer version of this script is now being maintained (and documented) on GitHub - https://github.com/richardszalay/msdeploy-package-publish

After much digging, I found that several issues in Microsoft.Web.Publishing.targets (v10.5) that prevents this from working. To workaround these issues, I've created the following MSBuild script that can be placed in the same directory as the Web Application's csproj. I've added comments related to fixes and implementation details.

The script uses Microsoft.Web.Publishing.targets, so most of the standard properties should still work. Here are some ways you can use it:

# Convention based
msbuild PackageDeploy.build /p:PublishProfile=Stage;WebPublishPipelineProjectName=Name_of_your_web_application

# Absolute paths to profile + package
msbuild PackageDeploy.build /p:PublishProfile=Path\To\Profile.pubxml;PackageFileName=Path\To\Package.zip;WebPublishPipelineProjectName==Name_of_your_web_application

If you're using VS2012, make sure you declare VisualStudioVersion=v11.0 to import the correct publishing file.

Using this script, you shouldn't need to recheck out your web application in subsequent stages in your deployment pipeline. You'll just need to keep the following artifacts after the build/package stage:

  • PackageDeploy.build (below)
  • Your publish profiles
  • The web application package zip

Here's the source for PackageDeploy.build:

<!--
This build script supports deployment of a website package to a publish profile without rebuilding the project or package

If placed in the same directory as a web project that uses publish profiles, the following arguments will need to be defined:

Convention based required arguments:
  PublishProfile: the name of the publish profile (or a path to a pubxml file if using non-convention based)
  Configuration: Debug/Release

Convention based optional arguments:
  VisualStudioVersion: Property specific to this build script that determines which WPP version to use (v10.5 [default] for VS2010+Azure updates, v11.0 for VS2012)
  WebPublishPipelineProjectName:
  WebPublishPipelineProjectDirectory: The root to the web project directory if this build script isn't there and PublishProfile isn't a path (to auto-detect publish profile directory)

Non-convention based optional arguments:
  PackageFileName: The full path to the website package zip
  UseDeclareParametersXMLInMsDeploy: true to save the parameters to a file and then use that file; false to inline the parameters
  UseMsDeployExe: true to use msdeploy.exe; false to use the VS MSBuild task

-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="DeployFromPackage">

  <PropertyGroup>
    <!-- IMPL: Set this to v11.0 to use VS2012 -->
    <VisualStudioVersion>v10.5</VisualStudioVersion>
  </PropertyGroup>

  <PropertyGroup>
    <!-- IMPL: Declared in Microsoft.Web.Publishing.targets, but we need to declare PublishProfileRootFolder before it's imported -->
    <WebPublishPipelineProjectDirectory Condition="'$(WebPublishPipelineProjectDirectory)'==''">$(MSBuildProjectDirectory)</WebPublishPipelineProjectDirectory>

    <!-- IMPL: Usually detected by ".csproj" vs ".vbproj", but PackageDeploy.build is neither -->
    <PublishProfileRootFolder Condition="'$(PublishProfileRootFolder)' == '' and Exists('My Project\PublishProfiles')">$(WebPublishPipelineProjectDirectory)\My Project\PublishProfiles</PublishProfileRootFolder>
    <PublishProfileRootFolder Condition="'$(PublishProfileRootFolder)' == '' and Exists('Properties\PublishProfiles')">$(WebPublishPipelineProjectDirectory)\Properties\PublishProfiles</PublishProfileRootFolder>
  </PropertyGroup>

  <!-- IMPL: Select the correct version of Microsoft.Web.Publishing.targets (usually done by the csproj via WebApplication.targets) -->
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets" />

  <!-- FIX: MSDeployPublish depends on building the package (can be skipped by clearing MSDeployPublishDependsOn) -->
  <!-- IMPL: ImportPublishingParameterValues transforms all the MSDeployParameterValue+ParameterValue to MsDeployDeclareParameters+Value -->
  <Target Name="DeployFromPackage" Condition="'$(PublishProfile)' != ''" DependsOnTargets="ImportPublishingParameterValues">

    <PropertyGroup>
      <_PublishMsDeployServiceUrl>$(MsDeployServiceUrl)</_PublishMsDeployServiceUrl>
      <_PublishMsDeployServiceUrl Condition="('$(MSDeployPublishMethod)'=='INPROC')"></_PublishMsDeployServiceUrl>
    </PropertyGroup>

    <ItemGroup>
      <!-- IMPL: Always uses "package" source -->
      <MsDeploySourceProviderSetting Remove="@(MsDeploySourceProviderSetting)" />
      <MsDeploySourceProviderSetting Include="package">
        <Path>@(_MSDeployPackageFile->'%(FullPath)')</Path>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <WebServerAppHostConfigDirectory>$(_MSDeploySourceWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeploySourceWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeploySourceWebServerDirectory)</WebServerDirectory>
      </MsDeploySourceProviderSetting>

      <MsDeployDestinationProviderSetting Remove="@(MsDeployDestinationProviderSetting)" />
      <MsDeployDestinationProviderSetting Include="auto">
        <Path></Path>
        <ComputerName>$(_PublishMsDeployServiceUrl)</ComputerName>
        <UserName>$(UserName)</UserName>
        <Password>$(Password)</Password>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <IncludeAcls>False</IncludeAcls>
        <AuthType>$(AuthType)</AuthType>
        <WebServerAppHostConfigDirectory>$(_MSDeployDestinationWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeployDestinationWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeployDestinationWebServerDirectory)</WebServerDirectory>
      </MsDeployDestinationProviderSetting>
    </ItemGroup>

    <!--Debug/Diagnostic message is not localized-->
    <Message Text="MSDeployPublish MsDeploySourceProviderSetting is @(MsDeploySourceProviderSetting)" Condition="$(EnablePackageProcessLoggingAndAssert)" />
    <Message Text="MSDeployPublish MsDeployDestinationProviderSetting is @(MsDeployDestinationProviderSetting)" Condition="$(EnablePackageProcessLoggingAndAssert)"/>

    <ExportParametersFile
      Condition="!$(UseDeclareParametersXMLInMsDeploy) And $(EnablePackageProcessLoggingAndAssert)"
      Parameters="@(MsDeployDeclareParameters)"
      DeclareSetParameterFile="$(PackageLogDir)\MSDeployPublish.parameters.xml"
      GenerateFileEvenIfEmpty="True"
      />

    <!--First delete the ParameterFile-->
    <Delete Files="$(PublishParametersFile)"  Condition="Exists($(PublishParametersFile))" ContinueOnError="true"/>

    <!-- FIX: Use SetParameterFile (rather than DeclareSetParameterFile), which isn't used anywehere in Microsoft.Web.Publishing.targets -->
    <ExportParametersFile
      Parameters="@(MsDeployDeclareParameters)"
      SetParameterFile="$(PublishParametersFile)"
      GenerateFileEvenIfEmpty="True"
      Condition="$(UseDeclareParametersXMLInMsDeploy)"
      />

    <PropertyGroup>
      <_VsPublishParametersFile></_VsPublishParametersFile>
      <_VsPublishParametersFile Condition="$(UseDeclareParametersXMLInMsDeploy) and '$(_VsPublishParametersFile)'==''">$(PublishParametersFile)</_VsPublishParametersFile>
    </PropertyGroup>

    <ItemGroup Condition="!$(UseDeclareParametersXMLInMsDeploy)">
      <_VsPublish_MsDeployDeclareParameters Remove="@(_VsPublish_MsDeployDeclareParameters)" />
      <_VsPublish_MsDeployDeclareParameters Include="@(MsDeployDeclareParameters)" />

      <!-- IMPL: Utilising the real version of this has way too much baggage (simplifying it could have repercussions, though) -->
      <_VsPublish_MsDeployDeclareParameters Include="$(DeployParameterIISAppName)" Condition="'$(DeployIisAppPath)' != ''">
        <Value>$(DeployIisAppPath)</Value>
      </_VsPublish_MsDeployDeclareParameters>
    </ItemGroup>

    <!-- FIX: Microsoft.Web.Publishing.targets uses "SetParameterItems", which doens't appear to work. This uses SimpleSetParameterItems instead  -->
    <VSMSDeploy
      Condition="!$(UseMsdeployExe)"
      MSDeployVersionsToTry="$(_MSDeployVersionsToTry)"
      Source="@(MsDeploySourceProviderSetting)"
      Destination="@(MsDeployDestinationProviderSetting)"
      DisableLink="$(PublishDisableLinks)"
      EnableLink="$(PublishEnableLinks)"
      AllowUntrustedCertificate="$(AllowUntrustedCertificate)"
      BuildingInsideVisualStudio="$(BuildingInsideVisualStudio)"
      SkipExtraFilesOnServer="$(SkipExtraFilesOnServer)"
      SkipRuleItems="@(MsDeploySkipRules)"
      OptimisticParameterDefaultValue="$(EnableOptimisticParameterDefaultValue)"
      SimpleSetParameterItems="@(_VsPublish_MsDeployDeclareParameters)"
      ImportSetParametersItems="$(_VsPublishParametersFile)"
      RetryAttempts="$(RetryAttemptsForDeployment)"
      InvokedByPublish="true"
    >
      <Output TaskParameter="Result" PropertyName="_PublishResult" />
    </VSMSDeploy>

    <!-- FIX: Microsoft.Web.Publishing.targets uses "SetParameterItems", which doens't appear to work. This uses SimpleSetParameterItems instead  -->
    <MSdeploy
          Condition="$(UseMsdeployExe)"
          Verb="sync"
          Source="@(MsDeploySourceProviderSetting)"
          Destination="@(MsDeployDestinationProviderSetting)"
          DisableLink="$(PublishDisableLinks)"
          EnableLink="$(PublishEnableLinks)"
          EnableRule="$(MsDeployDoNotDeleteRule)"
          AllowUntrusted="$(AllowUntrustedCertificate)"
          SkipRuleItems="@(MsDeploySkipRules)"
          OptimisticParameterDefaultValue="$(EnableOptimisticParameterDefaultValue)"
          SimpleSetParameterItems="@(_VsPublish_MsDeployDeclareParameters)"
          ImportSetParametersItems="$(_VsPublishParametersFile)"
          RetryAttempts="$(RetryAttemptsForDeployment)"
          ExePath="$(MSDeployPath)" />
  </Target>

</Project>
like image 175
Richard Szalay Avatar answered Sep 18 '22 13:09

Richard Szalay