在 Microsoft Team Foundation Server (TFS) 2018 和更低版本中,生成和发布管道被称为“定义”,运行被称为“生成”,服务连接被称为“服务终结点”,阶段被称为“环境”,而作业被称为“阶段” 。

每次成功生成后,可以自动将数据库更新部署到Azure SQL数据库。

DACPAC

部署数据库的最简单方法是创建 数据层包或 DACPAC 。 DACPAC 可用于打包和部署架构更改和数据。 可以在 Visual Studio 中使用 SQL 数据库项目 创建 DACPAC。

若要将 DACPAC 部署到Azure SQL数据库,请将以下代码片段添加到 azure-pipelines.yml 文件。

- task: SqlAzureDacpacDeployment@1
  displayName: Execute Azure SQL : DacpacTask
  inputs:
    azureSubscription: '<Azure service connection>'
    ServerName: '<Database server name>'
    DatabaseName: '<Database name>'
    SqlUsername: '<SQL user name>'
    SqlPassword: '<SQL user password>'
    DacpacFile: '<Location of Dacpac file in $(Build.SourcesDirectory) after compilation>'

TFS 不支持 YAML。

使用Azure SQL数据库部署任务时,另请参阅身份验证信息。

SQL 脚本

也可以使用 SQL 脚本来部署数据库,而不是使用 DACPAC。 下面是创建空数据库的 SQL 脚本的简单示例。

  USE [main]
  IF NOT EXISTS (SELECT name FROM main.sys.databases WHERE name = N'DatabaseExample')
  CREATE DATABASE [DatabaseExample]

若要在管道中运行 SQL 脚本,需要Azure PowerShell脚本在 Azure 中创建和删除防火墙规则。 如果没有防火墙规则,Azure Pipelines 代理无法与Azure SQL数据库通信。

以下 PowerShell 脚本创建防火墙规则。 可以将此脚本 SetAzureFirewallRule.ps1 签入存储库。

[CmdletBinding(DefaultParameterSetName = 'None')]
param
  [String] [Parameter(Mandatory = $true)] $ServerName,
  [String] [Parameter(Mandatory = $true)] $ResourceGroupName,
  [String] $FirewallRuleName = "AzureWebAppFirewall"
$agentIP = (New-Object net.webclient).downloadstring("https://api.ipify.org")
New-AzSqlServerFirewallRule -ResourceGroupName $ResourceGroupName -ServerName $ServerName -FirewallRuleName $FirewallRuleName -StartIPAddress $agentIp -EndIPAddress $agentIP
[CmdletBinding(DefaultParameterSetName = 'None')]
param
  [String] [Parameter(Mandatory = $true)] $ServerName,
  [String] [Parameter(Mandatory = $true)] $ResourceGroupName,
  [String] $FirewallRuleName = "AzureWebAppFirewall"
$ErrorActionPreference = 'Stop'
function New-AzureSQLServerFirewallRule {
  $agentIP = (New-Object net.webclient).downloadstring("https://api.ipify.org")
  New-AzureSqlDatabaseServerFirewallRule -StartIPAddress $agentIp -EndIPAddress $agentIp -FirewallRuleName $FirewallRuleName -ServerName $ServerName -ResourceGroupName $ResourceGroupName
function Update-AzureSQLServerFirewallRule{
  $agentIP= (New-Object net.webclient).downloadstring("https://api.ipify.org")
  Set-AzureSqlDatabaseServerFirewallRule -StartIPAddress $agentIp -EndIPAddress $agentIp -FirewallRuleName $FirewallRuleName -ServerName $ServerName -ResourceGroupName $ResourceGroupName
if ((Get-AzureSqlDatabaseServerFirewallRule -ServerName $ServerName -FirewallRuleName $FirewallRuleName -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue) -eq $null)
  New-AzureSQLServerFirewallRule
  Update-AzureSQLServerFirewallRule

以下 PowerShell 脚本删除防火墙规则。 可以在存储库中签入此脚本 RemoveAzureFirewallRule.ps1

[CmdletBinding(DefaultParameterSetName = 'None')]
param
  [String] [Parameter(Mandatory = $true)] $ServerName,
  [String] [Parameter(Mandatory = $true)] $ResourceGroupName,
  [String] $FirewallRuleName = "AzureWebAppFirewall"
Remove-AzSqlServerFirewallRule -ServerName $ServerName -FirewallRuleName $FirewallRuleName -ResourceGroupName $ResourceGroupName
[CmdletBinding(DefaultParameterSetName = 'None')]
param
  [String] [Parameter(Mandatory = $true)] $ServerName,
  [String] [Parameter(Mandatory = $true)] $ResourceGroupName,
  [String] $FirewallRuleName = "AzureWebAppFirewall"
$ErrorActionPreference = 'Stop'
if ((Get-AzureSqlDatabaseServerFirewallRule -ServerName $ServerName -FirewallRuleName $FirewallRuleName -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue))
  Remove-AzureSqlDatabaseServerFirewallRule -FirewallRuleName $FirewallRuleName -ServerName $ServerName -ResourceGroupName $ResourceGroupName

将以下内容添加到 azure-pipelines.yml 文件以运行 SQL 脚本。

variables:
  AzureSubscription: '<Azure service connection>'
  ServerName: '<Database server name>'
  ServerFqdn: '<SQL Database FQDN>'
  DatabaseName: '<Database name>'
  AdminUser: '<SQL user name>'
  AdminPassword: '<SQL user password>'
  SQLFile: '<Location of SQL file in $(Build.SourcesDirectory)>'
steps:
- task: AzurePowerShell@5
  displayName: Azure PowerShell script: FilePath
  inputs:
    azureSubscription: '$(AzureSubscription)'
    ScriptPath: '$(Build.SourcesDirectory)\scripts\SetAzureFirewallRule.ps1'
    ScriptArguments: '-ServerName $(ServerName) -ResourceGroupName $(ResourceGroupName)'
    azurePowerShellVersion: LatestVersion
- task: CmdLine@2
  displayName: Run Sqlcmd
  inputs:
    filename: Sqlcmd
  arguments: '-S $(ServerFqdn) -U $(AdminUser) -P $(AdminPassword) -d $(DatabaseName) -i $(SQLFile)'
- task: AzurePowerShell@5
  displayName: Azure PowerShell script: FilePath
  inputs:
    azureSubscription: '$(AzureSubscription)'
    ScriptPath: '$(Build.SourcesDirectory)\scripts\RemoveAzureFirewallRule.ps1'
    ScriptArguments: '-ServerName $(ServerName) -ResourceGroupName $(ResourceGroupName)'
    azurePowerShellVersion: LatestVersion

TFS 不支持 YAML。

设置生成管道时,请确保用于部署数据库的 SQL 脚本和用于配置防火墙规则的Azure PowerShell脚本是生成项目的一部分。

设置发布管道时,请选择“ 从空进程开始”,链接生成中的项目,然后使用以下任务:

  • 首先,使用Azure PowerShell任务在 Azure 中添加防火墙规则,以允许 Azure Pipelines 代理连接到Azure SQL数据库。 该脚本需要一个参数 - 创建的 SQL Server 的名称。
  • 其次,使用 命令行 任务使用 SQLCMD 工具运行 SQL 脚本。 -S {database-server-name}.database.windows.net -U {username}@{database-server-name} -P {password} -d {database-name} -i {SQL file}例如,当 SQL 脚本来自项目源时,{SQL 文件} 将采用以下形式: $(System.DefaultWorkingDirectory)/contoso-repo/DatabaseExample.sql
  • 第三,使用另一个Azure PowerShell任务删除 Azure 中的防火墙规则。
  • Azure 服务连接

    Azure SQL数据库部署任务是将数据库部署到 Azure 的主要机制。 此任务与其他内置 Azure 任务一样,需要 Azure 服务连接作为输入。 Azure 服务连接存储从 Azure Pipelines 或 TFS 连接到 Azure 的凭据。

    开始执行此任务的最简单方法是以拥有 Azure DevOps 组织和 Azure 订阅的用户身份登录。 在这种情况下,无需手动创建服务连接。 否则,若要了解如何创建 Azure 服务连接,请参阅 创建 Azure 服务连接

    若要了解如何创建 Azure 服务连接,请参阅 创建 Azure 服务连接

    有条件地部署

    可以选择仅将某些版本部署到 Azure 数据库。

    以下示例演示如何使用步骤条件仅部署源自主分支的生成。

    - task: SqlAzureDacpacDeployment@1
      condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
      inputs:
        azureSubscription: '<Azure service connection>'
        ServerName: '<Database server name>'
        DatabaseName: '<Database name>'
        SqlUsername: '<SQL user name>'
        SqlPassword: '<SQL user password>'
        DacpacFile: '<Location of Dacpac file in $(Build.SourcesDirectory) after compilation>'
    

    若要了解有关条件的详细信息,请参阅 指定条件

    TFS 不支持 YAML。

    更多 SQL 操作

    SQL Azure Dacpac 部署可能不支持要执行的所有 SQL Server 操作。 在这些情况下,只需使用 PowerShell 或命令行脚本来运行所需的命令。 本部分介绍调用 SqlPackage.exe工具的一些常见用例。 作为运行此工具的先决条件,必须使用自承载代理并在代理上安装该工具。

    如果从安装 SQLPackage 的文件夹执行 SQLPackage ,则必须为路径 & 加上前缀,并将其包装在双引号中。

    <Path of SQLPackage.exe> <Arguments to SQLPackage.exe>

    可以使用以下任一 SQL 脚本,具体取决于要执行的操作

    Extract

    从实时 SQL Server 或Microsoft Azure SQL 数据库创建数据库快照 (.dacpac) 文件。

    命令语法:

    SqlPackage.exe /TargetFile:"<Target location of dacpac file>" /Action:Extract
    /SourceServerName:"<ServerName>.database.windows.net"
    /SourceDatabaseName:"<DatabaseName>" /SourceUser:"<Username>" /SourcePassword:"<Password>"
    
    SqlPackage.exe /action:Extract /tf:"<Target location of dacpac file>"
    /SourceConnectionString:"Data Source=ServerName;Initial Catalog=DatabaseName;Integrated Security=SSPI;Persist Security Info=False;"
    
    SqlPackage.exe /TargetFile:"C:\temp\test.dacpac" /Action:Extract /SourceServerName:"DemoSqlServer.database.windows.net"
     /SourceDatabaseName:"Testdb" /SourceUser:"ajay" /SourcePassword:"SQLPassword"
    
    sqlpackage.exe /Action:Extract /?
    

    增量更新数据库架构以便匹配源 .dacpac 文件的架构。 如果服务器上不存在数据库,则发布操作将创建它。 否则,将更新现有数据库。

    命令语法:

    SqlPackage.exe /SourceFile:"<Dacpac file location>" /Action:Publish /TargetServerName:"<ServerName>.database.windows.net"
    /TargetDatabaseName:"<DatabaseName>" /TargetUser:"<Username>" /TargetPassword:"<Password> "
    
    SqlPackage.exe /SourceFile:"E:\dacpac\ajyadb.dacpac" /Action:Publish /TargetServerName:"DemoSqlServer.database.windows.net"
    /TargetDatabaseName:"Testdb4" /TargetUser:"ajay" /TargetPassword:"SQLPassword"
    
    sqlpackage.exe /Action:Publish /?
    

    将实时数据库(包括数据库架构和用户数据)从SQL Server或Microsoft Azure SQL 数据库导出到 BACPAC 包 (.bacpac 文件) 。

    命令语法:

    SqlPackage.exe /TargetFile:"<Target location for bacpac file>" /Action:Export /SourceServerName:"<ServerName>.database.windows.net"
    /SourceDatabaseName:"<DatabaseName>" /SourceUser:"<Username>" /SourcePassword:"<Password>"
    
    SqlPackage.exe /TargetFile:"C:\temp\test.bacpac" /Action:Export /SourceServerName:"DemoSqlServer.database.windows.net"
    /SourceDatabaseName:"Testdb" /SourceUser:"ajay" /SourcePassword:"SQLPassword"
    
    sqlpackage.exe /Action:Export /?
    

    将 BACPAC 包中的架构和表数据导入到SQL Server或Microsoft Azure SQL 数据库实例中的新用户数据库中。

    命令语法:

    SqlPackage.exe /SourceFile:"<Bacpac file location>" /Action:Import /TargetServerName:"<ServerName>.database.windows.net"
    /TargetDatabaseName:"<DatabaseName>" /TargetUser:"<Username>" /TargetPassword:"<Password>"
    
    SqlPackage.exe /SourceFile:"C:\temp\test.bacpac" /Action:Import /TargetServerName:"DemoSqlServer.database.windows.net"
    /TargetDatabaseName:"Testdb" /TargetUser:"ajay" /TargetPassword:"SQLPassword"
    
    sqlpackage.exe /Action:Import /?
    

    DeployReport

    创建将由发布操作完成的更改的 XML 报表。

    命令语法:

    SqlPackage.exe /SourceFile:"<Dacpac file location>" /Action:DeployReport /TargetServerName:"<ServerName>.database.windows.net"
    /TargetDatabaseName:"<DatabaseName>" /TargetUser:"<Username>" /TargetPassword:"<Password>" /OutputPath:"<Output XML file path for deploy report>"
    
    SqlPackage.exe /SourceFile:"E: \dacpac\ajyadb.dacpac" /Action:DeployReport /TargetServerName:"DemoSqlServer.database.windows.net"
    /TargetDatabaseName:"Testdb" /TargetUser:"ajay" /TargetPassword:"SQLPassword" /OutputPath:"C:\temp\deployReport.xml" 
    
    sqlpackage.exe /Action:DeployReport /?
    

    DriftReport

    创建自注册数据库注册以来已对其做出的更改的 XML 报表。

    命令语法:

    SqlPackage.exe /Action:DriftReport /TargetServerName:"<ServerName>.database.windows.net" /TargetDatabaseName:"<DatabaseName>"
    /TargetUser:"<Username>" /TargetPassword:"<Password>" /OutputPath:"<Output XML file path for drift report>"
    
    SqlPackage.exe /Action:DriftReport /TargetServerName:"DemoSqlServer.database.windows.net" /TargetDatabaseName:"Testdb"
    /TargetUser:"ajay" /TargetPassword:"SQLPassword" /OutputPath:"C:\temp\driftReport.xml"
    
    sqlpackage.exe /Action:DriftReport /?
    

    创建 Transact-SQL 增量更新脚本,该脚本可更新目标的架构以匹配源的架构。

    命令语法:

    SqlPackage.exe /SourceFile:"<Dacpac file location>" /Action:Script /TargetServerName:"<ServerName>.database.windows.net"
    /TargetDatabaseName:"<DatabaseName>" /TargetUser:"<Username>" /TargetPassword:"<Password>" /OutputPath:"<Output SQL script file path>"
    
    SqlPackage.exe /Action:Script /SourceFile:"E:\dacpac\ajyadb.dacpac" /TargetServerName:"DemoSqlServer.database.windows.net"
    /TargetDatabaseName:"Testdb" /TargetUser:"ajay" /TargetPassword:"SQLPassword" /OutputPath:"C:\temp\test.sql"
    /Variables:StagingDatabase="Staging DB Variable value"
    
    sqlpackage.exe /Action:Script /?