【问题标题】:ASP.NET Web Application (MVC) Deployment Automation and SubversionASP.NET Web 应用程序 (MVC) 部署自动化和 Subversion
【发布时间】:2010-12-28 22:37:24
【问题描述】:

我们正在尝试将构建过程自动化到我们的暂存服务器,但遇到了一个障碍,尽管它相当小。我们正在使用 VS2010 中内置的发布功能,提交到 Subversion,然后第 3 方应用程序 (Beanstalk) 会自动拉取更新的文件并将它们通过 FTP 传输到暂存服务器。

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

  • (二恶之少)如果我们选择使用“用本地副本替换匹配的文件”,这很好用,但有一个例外:此选项不会删除从项目中删除的任何文件。这将导致旧时凌乱的文件出现垃圾和/或安全问题。
  • 如果我们选择使用“在发布前删除所有现有文件”,这将删除整个文件夹结构,包括 Subversion 用于更新跟踪的 .SVN 隐藏文件夹等。从准确性的角度来看,这似乎是最好的解决方案,但它确实破坏了本地 SVN 环境,这是该自动化的中间人。

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

关于如何最好地做到这一点的任何想法?

【问题讨论】:

  • 完美的时机。我也在寻找解决方案。您是否尝试过解决解决方案配置和构建后事件?
  • 完全没有 - 到目前为止,所有部署都是手动的,如果更改集很大,这可能会非常耗费人力。我简直不敢相信没有更好的内置选项可以在不破坏文件夹的情况下为您提供准确的构建。

标签: asp.net svn automation web-deployment one-click-web-publishing


【解决方案1】:

您可能需要考虑将 NAnt 或类似的东西用于您希望自动化的任务,例如构建和发布到 Subversion。这是我为 WebApplication 项目构建文件的大部分内容。 MVC 可能会有所不同。如果是这样,我相信您可以以此为起点。我绝不是 NAnt 专家,所以可能存在一些缺陷,但这绝对适合我。

我必须向我想要发布的每个 .csproj 文件添加一个 PublishToFileSystem 目标。来源可以be found here

Build file also available on 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>

【讨论】:

  • 看起来很有希望,有机会我会研究一下。谢谢。
  • 开始使用 NAnt 和其他自动化工具可能会很耗时,但最终还是值得的。如果您有任何其他问题,请告诉我效果如何。
  • +1 不错的答案@Alex 为什么将它放在源文件夹中而不是 svn 中的单独位置?当有人进行 svn 更新时它会下载它,此外,您将配置共享给任何有权访问源 @Keith 的人您是否使用它,它是如何消失的,您最终有什么不同?
【解决方案2】:

我们也部署了 SVN 并遇到了同样的问题。我们的解决方案本质上是对项目进行“重大”升级的分支——我们添加和删除文件的情况,而不仅仅是修复小错误和进行通常可以通过 xcopy 处理的调整。 svn 布局如下:

--project
---production
----20100101
----20100213
[etc, etc]

就过程而言,它非常简单——如果有足够大的更改,请酌情签入构建工件。

您可能想尝试的另一件事,特别是如果您无法轻松地让您的生产位“切换”分支,那就是使用更高级的东西,例如 powershell 来执行删除文件命令,这可以过滤掉 *.svn文件夹。

【讨论】:

  • 分支的问题是它在我们希望完全自动化的过程中添加了一个手动步骤。感谢您的输入,但这绝对不是我们正在寻找的方向 - 我们现在宁愿手动删除文件,直到我们找到更好的东西。
  • Hrm,鉴于此以及您的其他答案,您可能想尝试一些自动跟踪更改的东西,而不是依赖于到处丢失跟踪的东西。我想到了 Mercurial。
【解决方案3】:

我会说“幸运”,这为自动化这个词带来了全新的含义:) 您所描述的是应用程序发布自动化,有时也称为部署自动化。如果您真的想知道谁做了什么,在哪里做了什么,结果如何等等,那么您正在寻找像 Nolio ASAP (http://www.noliosoft.com) 这样的产品。如果这有帮助,请告诉我,因为从你的描述来看,这似乎是一个完美的匹配。

+丹尼尔

【讨论】:

  • 不完全是我们正在寻找的,因为它似乎没有与 Subversion 集成(至少它没有直接提到它)。不过,它看起来确实是一款非常不错的产品,但我们已经有了一个完整的部署解决方案,只是上面列出了一个小问题。
【解决方案4】:

为什么要将站点发布到由 Subversion 处理的文件夹?

我这样做的方式是直接使用 SVN 处理的文件夹中的文件。我一提交任何东西,它就会被豆茎拉到暂存区。这样,删除的文件总是会从存储库中删除,您不必担心这一点。一切始终保持同步。

如果您觉得这会将太多文件放入暂存区,您仍然可以使用脚本和 Visual Studio 命令来发布站点。但我不确定 Beanstalk 与这种情况的集成情况如何。我知道 CC.net 和许多其他替代品都可以。

【讨论】:

  • 首先,我们使用暂存服务器“暂存”实际将部署到生产中的内容,即预编译代码...其次,我们使用配置转换来管理连接字符串和应用程序设置因环境而异。让 Beanstalk 直接从 SVN 拉取当前版本的 web.config 是行不通的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多