Versionamento Semântico (ou SemVer, abreviadamente) é um esquema de versionamento de software que estipula números de versão em três partes na forma <principal>.<secundária>.<correção>
, como 1.0.2
, com um sufixo opcional de pré-lançamento na forma -<pré-lançamento>
, como em 1.0.2-beta
.
O SemVer é talvez o esquema de versionamento mais amplamente utilizado hoje. Por exemplo, tanto o Nuget quanto o npm recomendam e suportam-no, e o VS Code usado também.
Na maioria dos repositórios do GitHub que usam o recurso GitHub Releases para publicar lançamentos, você veria um número de versão SemVer no distintivo de lançamento mais recente na página inicial, como pode ser visto na captura de tela abaixo:
requentemente preciso definir um número de versão SemVer ao construir projetos de API ASP.NET Core e, em seguida, ler ou relatar isso em tempo de execução.
Por exemplo, se eu construir uma API mínima com sua versão definida como 1.0.2-beta
, isso seria relatado por um ponto de extremidade /version
exposto pela API, como mostrado na captura de tela abaixo do Hoppscotch (essa é uma ferramenta semelhante ao Postman com a conveniência de executar o navegador):
Verificar se a versão relatada pelos serviços implantados, como aplicações web e APIs, está correta é uma parte crucial do meu pipeline de CD e é um dos testes de fumaça que uso para determinar se uma implantação foi bem-sucedida.
Uma pequena complicação ao definir um número de versão SemVer em assemblies .NET é que o .NET originalmente usava números de versão de quatro partes, como 1.0.3.212
e os assemblies ainda os têm (assembly é o termo .NET para unidades de código compiladas para bytecode .NET, sendo as mais típicas dll’s e exe’s).
O outro é que o .NET não tem um, mas muitos números de versão, ligeiramente diferentes, que estão presentes no mesmo assembly.
Neste artigo, mostrarei como contornar essas peculiaridades e carimbar um número de versão SemVer em um assembly .NET durante a compilação. Ou seja, em um .exe ou .dll compilado, e como lê-lo em tempo de execução.
Tabela de conteúdos
Estrutura do Número de Versão SemVer
Considere um número de versão SemVer como 1.0.2
ou 1.0.2-beta
. Ele tem a forma <principal>
.<secundária>
.<correção>
–<pré-lançamento>
Isso é o que significam os vários componentes:
A componente <major>
do número da versão seria incrementada apenas se o novo lançamento quebrasse uma versão existente (mais recente).
No caso de um aplicativo de interface do usuário, os clientes podem ser tomados para significar clientes humanos. Portanto, se o novo lançamento quebrasse ativos existentes dos usuários, como definições de fluxo de trabalho, isso exigiria o incremento do número da versão principal. Neste evento, se a versão anterior era 1.0.2
, o novo lançamento deve ser 2.0.0
(todas as componentes inferiores do número da versão seriam redefinidas).
No caso de uma biblioteca, como um pacote de biblioteca no Nuget ou NPM, os clientes seriam outros códigos. Portanto, se o novo lançamento quebrasse o código do cliente existente, ou seja, não seria compatível com versões anteriores, então novamente a componente <major>
seria incrementada.
<minor>
é incrementada se novas funcionalidades foram adicionadas, mas a nova versão ainda é compatível com versões anteriores. Portanto, de 1.0.2
você iria para 1.1.0
.
<patch>
é incrementada quando um novo lançamento precisa ser feito, mesmo que não haja mudança de quebra e nenhuma nova funcionalidade tenha sido adicionada. Isso poderia acontecer, por exemplo, se houvesse uma correção de bug que precisava ser lançada.
-<prerelease>
é um sufixo opcional. Ele é geralmente adicionado a um número de versão em três partes quando o software precisa ser disponibilizado durante fases de pré-lançamento, como alpha e beta. Por exemplo, antes de lançar geralmente a versão 1.0.2
do seu software, você pode disponibilizá-la para seus testadores beta como 1.0.2-beta
.
O componente <prerelease>
pode ser praticamente qualquer string de sua escolha e o único requisito é que seja um identificador alfanumérico como beta
ou 12
ou alpha2
(sem caracteres além de números ou letras do alfabeto) ou múltiplos identificadores alfanuméricos separados por um ponto(.
) por exemplo, development.version
.
O Numero de Versões de uma Assembly .NET
Como explica o artigo de Andrew Lock sobre版本amento no .NET, uma assembly .NET não tem um, mas vários números de versão diferentes:
-
AssemblyVersion: Este é um número de versão de quatro partes, por exemplo,
1.0.2.0
. Ele é usado pelo tempo de execução ao carregar assemblies vinculadas. -
FileVersion: Este é o número de versão relatado para um arquivo .dll no Windows File Explorer quando você clica com o botão direito na assembly e selecciona Propriedades.
-
VersãoInformativa: Mais uma vez um número de versão e, como o FileVersion, pode ser visto no diálogo de Propriedades se você clicar com o botão direito na assembly no Windows e selecionar Propriedades. Isso pode conter strings e não apenas números inteiros e pontos que AssemblyVersion e FileVersion estão limitados.
-
VersãoDoPacote: Se o projeto é um pacote Nuget, este seria o número de versão do pacote do qual a assembly faz parte.
Todos esses números de versão são emitidos na assembly durante a compilação como metadados. Você pode vê-los se inspectar a assembly com JetBrains dotPeek (grátis) ou Red gate Reflector (não grátis) ou similar.
FileVersion e VersãoInformativa também podem ser vistos na guia Detalhes do diálogo de Propriedades que aparece quando você clica com o botão direito no arquivo da assembly no Windows File Explorer e seleciona Propriedades:
Na captura de tela acima, “Versão do produto” é o rótulo para InformationalVersion, enquanto “Versão do arquivo” é o rótulo para FileVersion.
Das quatro tipos de números de versão descritos acima, apenas os primeiros três se aplicam a qualquer assembly (ou seja, independentemente de o assembly fazer parte de um pacote Nuget).
desses três, AssemblyVersion sempre adiciona um 0
no quarto lugar se você tentar definir uma versão SemVer que só tem três números (mais um sufixo pré-lançamento opcional). Por exemplo, se você tentar definir uma versão SemVer de 1.0.2-beta
durante a construção e depois ler o valor AssemblyVersion em tempo de execução na assembly, ele seria 1.0.2.0
.
FileVersion faz o mesmo, como mostrado na captura de tela acima.
InformationalVersion é o único número de versão que seria definido exatamente para a versão do servidor que você define durante a construção, como mostra a captura de tela acima.
Portanto, InformationalVersion é a versão que deve ser lida em tempo de execução para recuperar a versão SemVer da assembly.
Como Definir um Número de Versão SemVer
Existem duas coisas que você precisa fazer para definir um número de versão SemVer em uma assembly durante a construção.
Primeiro, em um elemento <PropertyGroup>
no arquivo csproj
do projeto, adicione o elemento <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
:
<PropertyGroup>
...
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>
Como descrito em este problema, isso garante que InformationalVersion é definido exatamente para o número da versão SemVer que especificamos e não recebe um +<hash code>
adicionado no final.
Segundo, passe o número da versão como valor da propriedade Version
passada para o comando dotnet build
, por exemplo:
dotnet build --configuration Release -p Version=1.0.2-beta
Isso definiria InformationalVersion no assembly compilado (arquivo .exe ou .dll) como 1.0.2-beta
.
Incidentalmente, ele também definiria AssemblyVersion e FileVersion (um 0
extra seria adicionado ao final de 1.0.2
) mas não estamos interessados neles.
Observe que, em vez de passar o argumento Version
na linha de comando, você pode definir a propriedade MS Build <Version>1.0.2-beta</Version>
em um elemento <PropertyGroup>
no arquivo csproj. No entanto, passar um valor do parâmetro Version
para dotnet build
é mais simples porque o arquivo csproj não precisa ser modificado sempre que o número da versão é incrementado. Isso é útil em pipelines de CD. Além disso, por padrão, os arquivos csproj não têm nenhuma propriedade relacionada ao controle de versão.
Como ler a versão semVer de um assembly em tempo de execução
O código que lê InfromationalVersion em tempo de execução é o seguinte:
string? version = Assembly.GetEntryAssembly()?.
GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.
InformationalVersion;
Em minhas APIs com APIs mínimas, para adicionar um endpoint /version
como示ei na seção de Introdução acima, coloco o trecho acima em Program.cs
, e em seguida adiciono o seguinte trecho imediatamente após. Note que todo o conteúdo deve aparecer antes de builder.Build()
ser chamado:
//este objeto de um tipo anônimo será
//serializado como JSON no corpo da resposta
//quando retornado por um manipulador
var objVersion = new { Version = version ?? "" };
//OUTRO CÓDIGO
//var app = builder.Build()
Após builder.Build()
ser chamado, crio o manipulador para o endpoint /version
:
app.MapGet("/version", () => objVersion);
Agora, quando executo o projeto da API e chamo o endpoint /version
, obtenho o número da versão de volta em um objeto JSON no corpo da resposta HTTP:
{
"version": "1.0.2-beta"
}
Isso é o que a captura de tela do Hoppscotch na Introdução mostrou.
Conclusão
Este artigo mostrou como definir um número de versão SemVer em suas assemblies, bibliotecas ou aplicativos .NET.
Também mostrou como ler o número da versão em tempo de execução.
Source:
https://www.freecodecamp.org/news/set-semantic-versioning-for-net/