Managing AssemblyVersion I

I have written a macro that autoincrements the build number of the AssemblyVersion based on the code that is available at http://blogs.biasecurities.com/jim/archive/2003/10/08/166.aspx

My macro uses ProjectItem to look for the AssemblyInfo file, uses regular expressions and supports automatically checking out and checkingIn the assemblyInfo file. I have tested it for C# projects only but i am sure with a few modifications it would work with VB.Net projects as well.

Imports EnvDTE
Imports System.Diagnostics

Public Module BuildIncrementer

    ' This event will be triggered after every build of a project
    ' You can modify the code below to only update projects that are active
    ' It currently will scan all projects in the solution for AssemblyInfo.cs files
    ' to update.
    Sub IncrementBuildNumber()

        'Comment the follow 3 lines, if you want the build number to increment even if the build fails
        If DTE.Solution.SolutionBuild.LastBuildInfo() <> 0 Then
            Exit Sub
        End If

        Dim skippedProjects As Integer = 0
        Dim revisionNo As String = GenerateRevisionNumber()
        ' Change this, if you would only like to modify the AssemblyInfo file in active project files
        ' For Each proj As Project In DTE.ActiveSolutionProjects
        For Each project As Project In DTE.Solution.Projects

            'Try to get the AssemblyInfo item, if not then skip
            'this project
            Dim assemblyInfoItem As ProjectItem = GetAssemblyInfoItem(project)
            Dim skipProject As Boolean = False
            If assemblyInfoItem Is Nothing Then
                skipProject = True
            End If

            If Not skipProject Then
                Try
                    assemblyInfoItem.Open("{7651A701-06E5-11D1-8EBD-00A0C90F26EA}").Activate() 'vsViewKindCode
                    Dim build As TextRange
                    Dim revision As TextRange

                    Dim txtDoc As TextDocument = assemblyInfoItem.Document.Object("TextDocument")
                    GetBuildAndRevision(txtDoc, build, revision)
                    CheckoutActiveItem()
                    IncrementIfNotEmptyOrStar(build)
                    SetToTimeOfDayIfNotEmptyOrStar(revision, revisionNo)
                    assemblyInfoItem.Save()
                    CheckinActiveItem()
                    DTE.ActiveWindow.Close(vsSaveChanges.vsSaveChangesYes)

                Catch ex As System.Exception
                    MsgBox(ex.Message)
                End Try
            Else
                skippedProjects = skippedProjects + 1
            End If
        Next
        System.Diagnostics.Debug.WriteLine("Skipped " & skippedProjects.ToString() & "projects")
    End Sub

    'Returns the full path of the first file
    'in the project with the name AssemblyInfo
    Function GetAssemblyInfoItem(ByVal project As Project) As ProjectItem

        For Each projectItem As ProjectItem In project.ProjectItems
            Dim i As Integer
            For i = 1 To projectItem.FileCount
                Dim filepath As String
                filepath = projectItem.FileNames(i)

                Dim indexOfLastSep As Integer = 1
                indexOfLastSep = filepath.LastIndexOf("\")
                If indexOfLastSep < 1 Then indexOfLastSep = 1

                Dim fileName As String = filepath.Substring(indexOfLastSep)

                If fileName.IndexOf("AssemblyInfo") > 0 Then
                    Return projectItem
                End If
            Next
        Next

        Return Nothing

    End Function
    Sub GetBuildAndRevision(ByVal textDocument As TextDocument, ByRef build As TextRange, ByRef revision As TextRange)

        Dim txtrgs As TextRanges
        build = Nothing
        revision = Nothing

        'Regular Expressions use VC6 syntax and not the new .Net syntax
        If textDocument.StartPoint.CreateEditPoint().FindPattern("AssemblyVersion\("":d+\.:d+\.{(:d+|\*)}(\.{(:d+|\*)})*""", vsFindOptions.vsFindOptionsRegularExpression, Nothing, txtrgs) Then
            If (txtrgs.Count > 1) Then
                build = txtrgs.Item(2)
            ElseIf txtrgs.Count > 2 Then
                revision = txtrgs.Item(3)
            End If
        End If
    End Sub
   

    'Generates a revision number for this build by using the curent time
    Function GenerateRevisionNumber() As String
        Dim now As Date = DateAndTime.Now
        Dim hrs As String = now.Hour.ToString()
        Dim mins As String = now.Minute.ToString()
        Dim secs As String = now.Second.ToString()

        Return hrs & mins & secs
    End Function
   
    'Retrevies the text from a text range
    Function GetTextFromTextRange(ByVal textRange As TextRange) As String
        If textRange Is Nothing Then
            Return ""
        Else
            Return textRange.StartPoint.GetText(textRange.EndPoint)
        End If
    End Function
   
    'Retrieves the text from the range and if it star or empty then
    'returns otherwise increments it
    Sub IncrementIfNotEmptyOrStar(ByVal build As TextRange)
        'If build is * or empty then ignore
        If (Not build Is Nothing) AndAlso (Not GetTextFromTextRange(build).Equals("*")) Then
            Dim buildNo As Integer = CType(GetTextFromTextRange(build), Integer)
            buildNo = buildNo + 1
            build.StartPoint.ReplaceText(build.EndPoint, buildNo.ToString(), sEPReplaceTextOptions.vsEPReplaceTextAutoformat)
        End If
    End Sub
   
    'Retrieves the text from the range and if it star or empty then
    'returns otherwise sets it to the time of day
    Sub SetToTimeOfDayIfNotEmptyOrStar(ByVal revision As TextRange, ByVal revisionNo As String)
        'If revision is * or empty then ignore
        If (Not revision Is Nothing) AndAlso (Not GetTextFromTextRange(revision).Equals("*")) Then
            revision.StartPoint.ReplaceText(revision.EndPoint, revisionNo, vsEPReplaceTextOptions.vsEPReplaceTextAutoformat)
        End If
    End Sub
   
    Sub CheckoutActiveItem()
        Dim checkoutCmd As Command = DTE.Commands.Item("File.CheckOutDynamicSilent")
        'Check if the item is already checked out or not
        If Not checkoutCmd.IsAvailable Then
            System.Diagnostics.Debug.WriteLine("Checkout cmd not available")
            Return
        End If

        Dim customin, customout
        Try
            DTE.Commands.Raise(checkoutCmd.Guid, checkoutCmd.ID, customin, customout)
        Catch ex As System.Exception
            System.Diagnostics.Debug.WriteLine(ex)
        End Try
    End Sub
  
    Sub CheckinActiveItem()
        Dim checkinCmd As Command = DTE.Commands.Item("File.CheckInDynamicSilent")
        'Check if the item is already checked out or not
        If Not checkinCmd.IsAvailable Then
            System.Diagnostics.Debug.WriteLine("Checkin cmd not available, something is wrong")
            Return
        End If
        Dim customin, customout
        DTE.Commands.Raise(checkinCmd.Guid, checkinCmd.ID, customin, customout)
    End Sub
   

Also if you want this macro to be automatically executed when the build finishes add this code to the EnvironmentEvents module that gets automatically generated whenever you create a new Macro project

Private Sub BuildEvents_OnBuildDone(ByVal Scope As EnvDTE.vsBuildScope, ByVal Action As EnvDTE.vsBuildAction) Handles BuildEvents.OnBuildDone
        IncrementBuildNumber()
End Sub

3 Comments

  • Three errors --



    BuildIncrementer(24): 'project' is a type and cannot be used as an expression.



    BuildIncrementer(63): 'projectItem' is a type and cannot be used as an expression.



    BuildIncrementer(127): Name 'sEPReplaceTextOptions' is not declared.

  • Hey Craig,



    I get no errors when using this macro, are you sure you have &quot;option stict on&quot; in your macro code?

  • Also i think sEPReplaceTextOptions should be vsEPReplaceTextOptions

Comments have been disabled for this content.