TF Docs and Bump Version Pipeline

4 minute read

Description:

So one pipeline I add to all module repos is to “bump version” and “update tf docs”. This is a single pipeline that developers run when they want to increment a git tag like mentioned in my changelog post. This pipeline solves 3 main things:

  • First, using semver, it will increment the module’s git tag to the next version.
  • Second, using plain bash it will update the changelog with the latest notes.
  • Last, it will use terraform-docs to update the README in the repo according to a config file.

See below for more details.

To Resolve:

  1. Below is an example pipeline:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    
    parameters:
       - name: increment
       displayName: Bump version
       type: string
       default: patch
       values:
          - major
          - minor
          - patch
    
    resources:
       repositories:
       - repository: module.example
          type: git
          name: my project/module.example
          ref: main
    
    trigger:
       - none
    
    stages:
    - stage: Bump_Version
       jobs:
       - job: bump_version
       displayName: 'Bump module version'
       condition: ne(variables['Build.Reason'], 'PullRequest')
       continueOnError: false
       pool:
          name: 'my-buildagent'
       steps:
             
          - checkout: self
             persistCredentials: true
    
          - checkout: module.example
    
          # Download terrform-docs and run it using config file under ./yaml/
          - task: Bash@3
             inputs:
             targetType: 'inline'
             script: |
                mkdir src
                cd src
                curl -SL https://github.com/terraform-docs/terraform-docs/releases/download/v0.16.0/terraform-docs-v0.16.0-$(uname)-amd64.tar.gz --output terraform-docs.tar.gz
                tar -xzf ./terraform-docs.tar.gz
                chmod +x ./terraform-docs
             displayName: 'Install Terraform-docs'
    
          - script: |
             git config --global user.email '$(Build.RequestedForEmail)'
             git config --global user.name '$(Build.RequestedFor)'
             displayName: 'Enable scripts to run git commands'
             failOnStderr: true
    
          # TF Docs custom config path => https://terraform-docs.io/user-guide/configuration/
          - task: Bash@3
             inputs:
             targetType: 'inline'
             failOnStderr: true
             script: |
                ./src/terraform-docs -c $(Build.SourcesDirectory)/my-repo/yaml/tf-docs-config.yml $(Build.SourcesDirectory)/my-repo
             displayName: 'Generate documentation from Terraform modules'
    
          - task: Bash@3
             inputs:
             targetType: 'inline'
             workingDirectory: $(Build.SourcesDirectory)/my-repo
             failOnStderr: true
             script: |
                git add -A && (git diff-index --quiet HEAD || git commit -am '[skip ci] generate docs')
             displayName: 'Commit changes'
             
          Step 2: Download semver and increment the input param by one
          - task: Bash@3
             inputs:
             targetType: 'inline'
             workingDirectory: $(Build.SourcesDirectory)
             script: |
                mkdir src
                cd src
                curl -SL https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver --output semver
                chmod +x ./semver
                ./semver --version
             displayName: 'Download semver tool'
    
          # Git tag cmd ref => https://gist.github.com/loisaidasam/b1e6879f3deb495c22cc
          - task: Bash@3
             inputs:
             targetType: 'inline'
             workingDirectory: $(Build.SourcesDirectory)/my-repo
             failOnStderr: true
             script: |
                old_version="$(git tag | tr - \~ | sort -V | tr \~ -| tail -1)"
                echo "vso[task.setvariable variable=Version.Old;isreadonly=true]$old_version"
    
                new_version="$(../src/semver bump ${/{ parameters.increment }} $old_version)"
                full_new_version=v$new_version
                echo "vso[task.setvariable variable=Version.New;isreadonly=true]$full_new_version"
    
                echo "vso[build.updatebuildnumber]$full_new_version"
             displayName: 'Bump version'
    
          - task: Bash@3
             inputs:
             targetType: 'inline'
             failOnStderr: true
             workingDirectory: $(Build.SourcesDirectory)/my-repo
             script: |
                unreleased_query="baseVersion=GBmain\&targetVersion=GT$(Version.New)\&_a=commits"
                unreleased_url="$(Build.Repository.Uri)/branchCompare?${unreleased_query}"
                unreleased_header=" [Unreleased]($unreleased_url)"
    
                released_query="baseVersion=GT$(Version.New)\&targetVersion=GT$(Version.Old)\&_a=commits"
                released_url="$(Build.Repository.Uri)/branchCompare?${released_query}"
                date="$(date '+%Y-%m-%d')"
                released_header=" [$(Version.New)]($released_url) - $date"
    
                sed -e "s|^ \[Unreleased\].*|$unreleased_header\n\n$released_header|" --follow-symlinks -i docs/changelog.md
             displayName: 'Update changelog'
    
          - task: Bash@3
             inputs:
             targetType: 'inline'
             failOnStderr: true
             workingDirectory: $(Build.SourcesDirectory)/my-repo
             script: |
                git config --global user.name "$(Build.RequestedFor)"
                git config --global user.email $(Build.RequestedForEmail)
    
                git commit -a -m "Bump version to $(Version.New)" -m '[skip ci]' --allow-empty
                git tag -a -m 'Release $(Version.New)' $(Version.New)
             displayName: 'Create release tag'
    
          Step 3: Push these changes to the repo
          - task: Bash@3
             inputs:
             targetType: 'inline'
             failOnStderr: true
             workingDirectory: $(Build.SourcesDirectory)/my-repo
             script: |
                git push --follow-tags --porcelain origin 'HEAD:$(Build.SourceBranchName)'
             displayName: 'Push release tag'
    
    
    • Couple things happening here… first, we download the contents of an other repo because the checkout stage will name the folders correctly only if you checkout another repo (see the text “Each designated repository is checked out to a folder named after the repository, unless a different path is specified in the checkout step. To check out self as one of the repositories, use checkout: self as one of the checkout steps.”)

    • Next, we set trigger to none because we don’t want this running unless we run it manually.

    • Next, we download the tf-docs executable from Github and then run it against $(Build.SourcesDirectory)/my-repo using its config file at $(Build.SourcesDirectory)/my-repo/yaml/tf-docs-config.yml

    • Next, we download the semver tool and run it against the output from a generic bash script that gets the latest tag in the repo. This gives us a new incremented version that we will do 2 things with:

      • First, we will use it to update our changelog.
      • Next, we will use it to create a new tag for the repo and push it.
    • The last few steps do just that, update the changelog using some sed commands and then push the latest tag to the repo.

  2. As discussed, the ./yaml directory has this file called ./yaml/tf-docs-config.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    formatter: markdown document
    
    version: ">= 0.14.0, < 1.0.0"
    
    sections:
    show:
       - inputs
       - outputs
    
    output:
    file: README.md
    mode: inject
    
    sort:
    enabled: false
    
    settings:
    html: false
    indent: 3
    
  3. Finally, you just create a pipeline in Azure Devops pointing to this file for your module and you can run it on demand.

  4. Here is an example that doesn’t use semver or tf-docs and only increments using bash.

Tags:

Updated:

Comments