ASP.NET Web应用程序(MVC)部署自动化和Subversion

Kei*_*ith 7 svn asp.net automation web-deployment one-click-web-publishing

我们正在尝试将构建过程自动化到我们的临时服务器,但是遇到了一个障碍,虽然相当小.我们使用VS2010内置的Publish功能,提交Subversion,然后第三方应用程序(Beanstalk)自动提取更新的文件并将它们FTP到Staging服务器.

我们遇到的问题是我们似乎只有以下选择:

  • (较小的2个邪恶)如果我们选择使用"将匹配的文件替换为本地副本",这很有效,但有一个例外:此选项不会删除从项目中删除的任何文件.从旧时代开始,这将导致乱蓬蓬的文件出现垃圾和/或安全问题.
  • 如果我们选择使用"在发布之前删除所有现有文件",则会删除整个文件夹结构,包括Subversion用于更新跟踪的.SVN隐藏文件夹等.从准确性的角度来看,这似乎是最佳解决方案,但它真正摧毁了本地SVN环境,这是这种自动化的中间人.

我的问题:是否有一个简单的解决方法,或者我们忽略的完全不同的部署选项(我们不希望从VS直接发布到服务器,因为我们想要跟踪部署发生的人/什么/何时)?我遇到的唯一问题是在发布之前手动删除文件内容,同时保持文件夹结构不变,然后使用"将匹配的文件替换为本地副本"进行部署.不幸的是,这带来了"自动化"这个词的全新含义.

关于如何最好地实现这一点的任何想法?

Ale*_*ton 4

您可能需要考虑使用 NAnt 或类似的工具来执行您希望自动化的任务,例如构建和发布到 Subversion。这是我的 Web 应用程序项目的大部分构建文件。对于 MVC 来说可能会有所不同。如果是这样,我相信您可以以此为起点。我绝不是 NAnt 专家,因此可能存在一些缺陷,但这绝对对我有用。

我必须向我想要发布的每个 .csproj 文件添加 PublishToFileSystem 目标。其来源可以在这里找到

Pastebin 上也提供了构建文件

<?xml version="1.0"?>
<project name="deploy" default="all">
    <property name="nant.settings.currentframework" value="net-4.0" />  
    <!-- Any of these can be passed through the command line -->
    <property name="sourceDirectory" value="${project::get-base-directory()}" />
    <property name="publishDirectory" value="${sourceDirectory}\build" />
    <property name="MSBuildPath" value="${framework::get-assembly-directory(framework::get-target-framework())}\msbuild.exe" />
    <!-- The build configuration to use when publishing and transforming the web.config file. This is useful when you have multiple environments for which you create builds -->
    <property name="buildConfiguration" value="Release" /> 
    <!-- Set these as needed -->
    <property name="svn.username" value="" />
    <property name="svn.password" value="" />

    <target name="SvnPrep">
        <property name="svn.dir" value="${publishDirectory}\.svn" />
        <property name="svn.update" value="true" readonly="false" />
        <echo>env.svn.path = svn</echo>
        <echo>svn.dir = ${svn.dir}</echo>
        <mkdir dir="${publishDirectory}" unless="${directory::exists(publishDirectory)}" />
        <!-- Check if there's a .svn dir already. If not: checkout, else: update. -->
        <if test="${not directory::exists(svn.dir)}">
            <exec program='svn.exe' workingdir="${publishDirectory}" verbose="true">
                <arg line='co ${svn.builduri} --username ${svn.username} --password ${svn.password} --non-interactive ./' />
            </exec>
            <property name="svn.update" value="false" readonly="false" />
        </if>
        <if test="${svn.update}">
            <exec program='svn.exe' workingdir="${publishDirectory}\" verbose="true">
                <arg line='up --username ${svn.username} --password ${svn.password} --non-interactive --force ./' />
            </exec>
        </if>
        <!-- Force any conflicts to be resolved with the most recent code -->
        <exec program='svn.exe' workingdir="${publishDirectory}\" verbose="true">
            <arg line='resolve --accept theirs-full -R ./' />
        </exec>
    </target>   

    <target name="DeleteFiles">
        <!-- Delete only the files (retain directory structure) in the directory to which you are going to publish/build. NAnt excludes svn directories by default. -->
        <delete includeemptydirs="false">
            <fileset basedir="${publishDirectory}">
                <include name="**/*.*" /> 
            </fileset>
        </delete>
    </target>
    <target name="Publish">
        <!-- I know there's an MSBuild task, I don't know why I didn't use it, but this works. -->
        <!-- Build and publish frontend -->
        <exec program="${MSBuildPath}">
            <arg line='"${sourceDirectory}\YourProject.csproj"' />
            <arg value='"/p:Platform=AnyCPU;Configuration=${buildConfiguration};PublishDestination=${publishDirectory}"' />
            <arg value="/target:PublishToFileSystem" />
        </exec>
        <!-- Transform the correct web.config and copy it to the build folder. PublishToFileSystem doesn't transform the web.config, unfortunately. -->
        <exec program="${MSBuildPath}">
            <arg line='"${sourceDirectory}\YourProject.csproj"' />
            <arg value='"/p:Platform=AnyCPU;Configuration=${buildConfiguration};PublishDestination=${publishDirectory}"' />
            <arg value="/target:TransformWebConfig" />
        </exec>
        <copy file="${sourceDirectory}\YourProject\obj\${buildConfiguration}\TransformWebConfig\transformed\Web.config" tofile="${publishDirectory}\YourProject\web.config" overwrite="true" />     
    </target>

    <target name="SvnCommit">       
        <!-- add any new files -->
        <exec program='svn.exe' workingdir="${publishDirectory}" verbose="true">
            <arg line='add --force .' />
        </exec>
        <!-- delete any missing files, a modification of this http://stackoverflow.com/questions/1071857/how-do-i-svn-add-all-unversioned-files-to-svn -->
        <!-- When there's nothing to delete it looks like this fails (to NAnt) but it is actually fine, that's why failonerror is false -->     
        <exec program='cmd.exe' workingdir="${publishDirectory}\" verbose="true" failonerror="false" 
            commandline='/C for /f "usebackq tokens=2*" %i in (`svn status ^| findstr /r "^\!"`) do svn del "%i %j"' >
        </exec>
        <exec program='svn.exe' workingdir="${publishDirectory}" verbose="true">
            <arg line='commit -m "Automated commit from build runner"' />
        </exec>
    </target>

    <target name="ShowProperties">
        <script language="C#" prefix="util" >
            <code>
                <![CDATA[
                public static void ScriptMain(Project project) 
                {
                    foreach (DictionaryEntry entry in project.Properties)
                    {
                        Console.WriteLine("{0}={1}", entry.Key, entry.Value);
                    }
                }
                ]]>
            </code>
        </script>
    </target>

    <target name="all">
        <call target="ShowProperties" />
        <call target="SvnPrep" />
        <call target="DeleteFiles" />
        <call target="Publish" />
        <call target="SvnCommit" />
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)