├── .dockerignore ├── .github └── workflows │ └── lint.yml ├── .gitignore ├── .terraform.lock.hcl ├── .tflint.hcl ├── README.md ├── libvirt-domain.xsl ├── main.tf ├── qemu-agent-guest-exec ├── renovate.json5 └── renovate.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !requirements.txt 3 | !requirements.yml 4 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: [push] 3 | jobs: 4 | lint: 5 | name: Lint 6 | runs-on: ubuntu-22.04 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Cache the plugins directory 10 | uses: actions/cache@v4 11 | with: 12 | path: ~/.tflint.d/plugins 13 | key: tflint-${{ hashFiles('.tflint.hcl') }} 14 | - uses: terraform-linters/setup-tflint@v4 15 | name: Setup 16 | with: 17 | # see https://github.com/terraform-linters/tflint/releases 18 | # renovate: datasource=github-releases depName=terraform-linters/tflint 19 | tflint_version: v0.52.0 20 | - name: Init 21 | run: tflint --init 22 | env: 23 | # https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting 24 | GITHUB_TOKEN: ${{ github.token }} 25 | - name: Lint 26 | run: tflint --format compact 27 | fmt: 28 | name: terraform fmt check 29 | runs-on: ubuntu-22.04 30 | steps: 31 | - uses: actions/checkout@v4 32 | - name: terraform fmt check 33 | run: terraform fmt -check -diff 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | .terraform/ 3 | *terraform.tfstate* 4 | tfplan 5 | -------------------------------------------------------------------------------- /.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/dmacvicar/libvirt" { 5 | version = "0.7.6" 6 | constraints = "0.7.6" 7 | hashes = [ 8 | "h1:mmbm4vTyC/DCGO4Ed/vbp5AKvy1gmVn/94fzB9VmR08=", 9 | "zh:0bde54f6f658b20b620b875daf106b5b25b1bae4d15408d6c5f06d58360e254d", 10 | "zh:0c97c6930015918b8a34b6d7a2b0c3d17a649c226fcd1874fcba5bbbc0f35972", 11 | "zh:1bdd7aa0011c5f024a09a124836ee9bc8e71b05a6ece810c61824275fd3f695f", 12 | "zh:2b0cc7c794e4caf395d84ffff0b380d17e4b3219a4696264271bfe5059450efe", 13 | "zh:2f8633f7fe07f76c188836ed6f93321ec5fbf5c004bc7699e1741d9b21ed5f37", 14 | "zh:5bf47eed286ce55ed10a5cf657de49a34ab21cc8677c56fef3aab69cdde41a27", 15 | "zh:7dca790fc5fd1d42bc4bc7170be003a7093602026d0f95c8aab84ad551fdf2a4", 16 | "zh:80476b68bc84e3d661d1390025f83879b88f9cdc836de9751af09bd5716089cb", 17 | "zh:82f3e2f3f50176cd6041c8ba36e295cbda1b289ef52ab75b5eceb0f921f64f7b", 18 | "zh:a179b165f3b9bb9a67ebbbf9d73157ded33f02d476b2f58906389dca03b653c9", 19 | "zh:acae54a5d0616f22b3180ddd8e8aad39af664e604394fdacf1f7b337bca2d5b4", 20 | "zh:da4406a2428a9a7e98272c032cb93431c3919253af2fe9934b532d26c0deab09", 21 | "zh:f63dbd8e579ab5268d01ffab4503b8a8e736b70d1a04e4f271559ba8dd133dcd", 22 | "zh:f85c1d9e51a94ecde137435c9d6b0fb7be590437ea8a725334d1577eebbc550c", 23 | ] 24 | } 25 | 26 | provider "registry.terraform.io/hashicorp/random" { 27 | version = "3.6.2" 28 | constraints = "3.6.2" 29 | hashes = [ 30 | "h1:wmG0QFjQ2OfyPy6BB7mQ57WtoZZGGV07uAPQeDmIrAE=", 31 | "zh:0ef01a4f81147b32c1bea3429974d4d104bbc4be2ba3cfa667031a8183ef88ec", 32 | "zh:1bcd2d8161e89e39886119965ef0f37fcce2da9c1aca34263dd3002ba05fcb53", 33 | "zh:37c75d15e9514556a5f4ed02e1548aaa95c0ecd6ff9af1119ac905144c70c114", 34 | "zh:4210550a767226976bc7e57d988b9ce48f4411fa8a60cd74a6b246baf7589dad", 35 | "zh:562007382520cd4baa7320f35e1370ffe84e46ed4e2071fdc7e4b1a9b1f8ae9b", 36 | "zh:5efb9da90f665e43f22c2e13e0ce48e86cae2d960aaf1abf721b497f32025916", 37 | "zh:6f71257a6b1218d02a573fc9bff0657410404fb2ef23bc66ae8cd968f98d5ff6", 38 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 39 | "zh:9647e18f221380a85f2f0ab387c68fdafd58af6193a932417299cdcae4710150", 40 | "zh:bb6297ce412c3c2fa9fec726114e5e0508dd2638cad6a0cb433194930c97a544", 41 | "zh:f83e925ed73ff8a5ef6e3608ad9225baa5376446349572c2449c0c0b3cf184b7", 42 | "zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af", 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | # NB the terraform plugin is built into tflint, so no need to declare it here. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Usage (Ubuntu 22.04 host) 2 | 3 | [![Lint](https://github.com/rgl/terraform-libvirt-ubuntu-example/actions/workflows/lint.yml/badge.svg)](https://github.com/rgl/terraform-libvirt-ubuntu-example/actions/workflows/lint.yml) 4 | 5 | Create and install the [base Ubuntu 22.04 vagrant box](https://github.com/rgl/ubuntu-vagrant). 6 | 7 | Install Terraform: 8 | 9 | ```bash 10 | wget https://releases.hashicorp.com/terraform/1.9.2/terraform_1.9.2_linux_amd64.zip 11 | unzip terraform_1.9.2_linux_amd64.zip 12 | sudo install terraform /usr/local/bin 13 | rm terraform terraform_*_linux_amd64.zip 14 | ``` 15 | 16 | Create the infrastructure: 17 | 18 | ```bash 19 | export CHECKPOINT_DISABLE=1 20 | export TF_LOG=TRACE 21 | export TF_LOG_PATH="$PWD/terraform.log" 22 | terraform init 23 | terraform plan -out=tfplan 24 | time terraform apply tfplan 25 | ``` 26 | 27 | **NB** if you have errors alike `Could not open '/var/lib/libvirt/images/terraform_example_root.img': Permission denied'` you need to reconfigure libvirt by setting `security_driver = "none"` in `/etc/libvirt/qemu.conf` and restart libvirt with `sudo systemctl restart libvirtd`. 28 | 29 | Show information about the libvirt/qemu guest: 30 | 31 | ```bash 32 | virsh dumpxml terraform_example 33 | virsh qemu-agent-command terraform_example '{"execute":"guest-info"}' --pretty 34 | virsh qemu-agent-command terraform_example '{"execute":"guest-network-get-interfaces"}' --pretty 35 | ./qemu-agent-guest-exec terraform_example id 36 | ./qemu-agent-guest-exec terraform_example uname -a 37 | ssh-keygen -f ~/.ssh/known_hosts -R "$(terraform output --raw ip)" 38 | ssh "vagrant@$(terraform output --raw ip)" 39 | ``` 40 | 41 | Destroy the infrastructure: 42 | 43 | ```bash 44 | time terraform destroy -auto-approve 45 | ``` 46 | 47 | List this repository dependencies (and which have newer versions): 48 | 49 | ```bash 50 | GITHUB_COM_TOKEN='YOUR_GITHUB_PERSONAL_TOKEN' ./renovate.sh 51 | ``` 52 | 53 | # Virtual BMC 54 | 55 | You can externally control the VM using the following terraform providers: 56 | 57 | * [vbmc terraform provider](https://registry.terraform.io/providers/rgl/vbmc) 58 | * exposes an [IPMI](https://en.wikipedia.org/wiki/Intelligent_Platform_Management_Interface) endpoint. 59 | * you can use it with [ipmitool](https://github.com/ipmitool/ipmitool). 60 | * for more information see the [rgl/terraform-provider-vbmc](https://github.com/rgl/terraform-provider-vbmc) repository. 61 | * [sushy-vbmc terraform provider](https://registry.terraform.io/providers/rgl/sushy-vbmc) 62 | * exposes a [Redfish](https://en.wikipedia.org/wiki/Redfish_(specification)) endpoint. 63 | * you can use it with [redfishtool](https://github.com/DMTF/Redfishtool). 64 | * for more information see the [rgl/terraform-provider-sushy-vbmc](https://github.com/rgl/terraform-provider-sushy-vbmc) repository. 65 | -------------------------------------------------------------------------------- /libvirt-domain.xsl: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | # see https://github.com/hashicorp/terraform 2 | terraform { 3 | required_version = "1.9.2" 4 | required_providers { 5 | # see https://registry.terraform.io/providers/hashicorp/random 6 | # see https://github.com/hashicorp/terraform-provider-random 7 | random = { 8 | source = "hashicorp/random" 9 | version = "3.6.2" 10 | } 11 | # see https://registry.terraform.io/providers/dmacvicar/libvirt 12 | # see https://github.com/dmacvicar/terraform-provider-libvirt 13 | libvirt = { 14 | source = "dmacvicar/libvirt" 15 | version = "0.7.6" 16 | } 17 | } 18 | } 19 | 20 | provider "libvirt" { 21 | uri = "qemu:///system" 22 | } 23 | 24 | variable "prefix" { 25 | type = string 26 | default = "terraform_example" 27 | } 28 | 29 | # see https://github.com/dmacvicar/terraform-provider-libvirt/blob/v0.7.6/website/docs/r/network.markdown 30 | resource "libvirt_network" "example" { 31 | name = var.prefix 32 | mode = "nat" 33 | domain = "example.test" 34 | addresses = ["10.17.3.0/24"] 35 | dhcp { 36 | enabled = false 37 | } 38 | dns { 39 | enabled = true 40 | local_only = false 41 | } 42 | } 43 | 44 | # create a cloud-init cloud-config. 45 | # NB this creates an iso image that will be used by the NoCloud cloud-init datasource. 46 | # see https://github.com/dmacvicar/terraform-provider-libvirt/blob/v0.7.6/website/docs/r/cloudinit.html.markdown 47 | # see journalctl -u cloud-init 48 | # see /run/cloud-init/*.log 49 | # see https://cloudinit.readthedocs.io/en/latest/topics/examples.html#disk-setup 50 | # see https://cloudinit.readthedocs.io/en/latest/topics/datasources/nocloud.html#datasource-nocloud 51 | # see createISO at https://github.com/dmacvicar/terraform-provider-libvirt/blob/v0.7.6/libvirt/cloudinit_def.go#L140-L169 52 | resource "libvirt_cloudinit_disk" "example_cloudinit" { 53 | name = "${var.prefix}_example_cloudinit.iso" 54 | user_data = < 0 ? libvirt_domain.example.network_interface[0].addresses[0] : "" 162 | } 163 | -------------------------------------------------------------------------------- /qemu-agent-guest-exec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | ''' 3 | Execute a command inside the guest. 4 | ''' 5 | 6 | import base64 7 | import json 8 | import libvirt 9 | import libvirt_qemu 10 | import logging 11 | import sys 12 | import time 13 | 14 | domain_name = sys.argv[1] 15 | command_path = sys.argv[2] 16 | command_args = sys.argv[3:] 17 | 18 | try: 19 | connection = libvirt.open(None) 20 | except libvirt.libvirtError: 21 | logging.exception('Failed to open connection to the hypervisor') 22 | exit(1) 23 | 24 | try: 25 | domain = connection.lookupByName(domain_name) 26 | except libvirt.libvirtError: 27 | logging.exception(f'Domain {domain_name} is not running') 28 | exit(1) 29 | 30 | # execute a command inside the guest. 31 | # see https://libvirt.org/html/libvirt-libvirt-qemu.html#virDomainQemuAgentCommand 32 | command = json.dumps({ 33 | 'execute': 'guest-exec', 34 | 'arguments': { 35 | 'path': command_path, 36 | 'arg': command_args, 37 | 'capture-output': True, 38 | } 39 | }) 40 | result = json.loads(libvirt_qemu.qemuAgentCommand(domain, command, -2, 0)) 41 | command = json.dumps({ 42 | 'execute': 'guest-exec-status', 43 | 'arguments': { 44 | 'pid': result['return']['pid'], 45 | } 46 | }) 47 | while True: 48 | result = json.loads(libvirt_qemu.qemuAgentCommand(domain, command, -2, 0)) 49 | if result['return']['exited']: 50 | print(base64.b64decode(result['return']['out-data']).decode('utf-8')) 51 | break 52 | time.sleep(0.1) 53 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | // see https://docs.renovatebot.com/templates/ 2 | // see https://docs.renovatebot.com/modules/manager/ 3 | // see https://docs.renovatebot.com/modules/manager/regex/ 4 | // see https://docs.renovatebot.com/configuration-options/ 5 | { 6 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 7 | "regexManagers": [ 8 | // default datasources. 9 | { 10 | "fileMatch": [ 11 | "\\.yml$", 12 | ".sh$", 13 | ], 14 | "matchStrings": [ 15 | "# renovate: datasource=(?[^:]+?) depName=(?.+?)( versioning=(?.+?))?( extractVersion=(?.+?))?( registryUrl=(?.+?))?\\s.+?[:=]\\s*[\"']?(?.+?)[\"']?\\s" 16 | ], 17 | "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver-coerced{{/if}}", 18 | "extractVersionTemplate": "{{#if extractVersion}}{{{extractVersion}}}{{else}}^v?(?.+)${{/if}}" 19 | }, 20 | ] 21 | } -------------------------------------------------------------------------------- /renovate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # this executes renovate against the local repository. 5 | # NB this uses a temporary gitea instance because running renovate against a 6 | # local directory not (yet?) supported. 7 | # see https://github.com/renovatebot/renovate/issues/3609 8 | 9 | export RENOVATE_USERNAME='renovate' 10 | export RENOVATE_NAME='Renovate Bot' 11 | export RENOVATE_PASSWORD='password' 12 | gitea_container_name="$(basename "$(dirname "$(realpath "${BASH_SOURCE[0]}")")")-renovate-gitea" 13 | 14 | # see https://hub.docker.com/r/gitea/gitea/tags 15 | # renovate: datasource=docker depName=gitea/gitea 16 | gitea_version='1.22.1' 17 | 18 | # see https://hub.docker.com/r/renovate/renovate/tags 19 | # renovate: datasource=docker depName=renovate/renovate extractVersion=(?.+)-slim$ 20 | renovate_version='37.431.4' 21 | 22 | # clean. 23 | echo 'Deleting existing Gitea...' 24 | docker rm --force "$gitea_container_name" >/dev/null 2>&1 25 | echo 'Deleting existing temporary files...' 26 | rm -f tmp/renovate-* 27 | install -d tmp 28 | 29 | # start gitea in background. 30 | # see https://docs.gitea.io/en-us/config-cheat-sheet/ 31 | # see https://github.com/go-gitea/gitea/releases 32 | # see https://github.com/go-gitea/gitea/blob/v1.22.1/docker/root/etc/s6/gitea/setup 33 | echo 'Starting Gitea...' 34 | docker run \ 35 | --detach \ 36 | --name "$gitea_container_name" \ 37 | -v /etc/timezone:/etc/timezone:ro \ 38 | -v /etc/localtime:/etc/localtime:ro \ 39 | -e SECRET_KEY=abracadabra \ 40 | -p 3000 \ 41 | "gitea/gitea:$gitea_version" \ 42 | >/dev/null 43 | gitea_addr="$(docker port "$gitea_container_name" 3000 | head -1)" 44 | gitea_url="http://$gitea_addr" 45 | export RENOVATE_ENDPOINT="$gitea_url" 46 | export GIT_PUSH_REPOSITORY="http://$RENOVATE_USERNAME:$RENOVATE_PASSWORD@$gitea_addr/$RENOVATE_USERNAME/test.git" 47 | 48 | # wait for gitea to be ready. 49 | echo "Waiting for Gitea to be ready at $gitea_url..." 50 | GITEA_URL="$gitea_url" bash -euc 'while [ -z "$(wget -qO- "$GITEA_URL/api/v1/version" | jq -r ".version | select(.!=null)")" ]; do sleep 5; done' 51 | 52 | # create user in gitea. 53 | echo "Creating Gitea $RENOVATE_USERNAME user..." 54 | docker exec --user git "$gitea_container_name" gitea admin user create \ 55 | --admin \ 56 | --email "$RENOVATE_USERNAME@example.com" \ 57 | --username "$RENOVATE_USERNAME" \ 58 | --password "$RENOVATE_PASSWORD" 59 | curl \ 60 | --silent \ 61 | --show-error \ 62 | --fail-with-body \ 63 | -u "$RENOVATE_USERNAME:$RENOVATE_PASSWORD" \ 64 | -X 'PATCH' \ 65 | -H 'Accept: application/json' \ 66 | -H 'Content-Type: application/json' \ 67 | -d "{\"full_name\":\"$RENOVATE_NAME\"}" \ 68 | "$gitea_url/api/v1/user/settings" \ 69 | | jq \ 70 | > /dev/null 71 | 72 | # create the user personal access token. 73 | # see https://docs.gitea.io/en-us/api-usage/ 74 | # see https://docs.gitea.io/en-us/oauth2-provider/#scopes 75 | # see https://try.gitea.io/api/swagger#/user/userCreateToken 76 | echo "Creating Gitea $RENOVATE_USERNAME user personal access token..." 77 | curl \ 78 | --silent \ 79 | --show-error \ 80 | --fail-with-body \ 81 | -u "$RENOVATE_USERNAME:$RENOVATE_PASSWORD" \ 82 | -X POST \ 83 | -H "Content-Type: application/json" \ 84 | -d '{"name": "renovate", "scopes": ["read:user", "write:issue", "write:repository"]}' \ 85 | "$gitea_url/api/v1/users/$RENOVATE_USERNAME/tokens" \ 86 | | jq -r .sha1 \ 87 | >tmp/renovate-gitea-token.txt 88 | 89 | # try the token. 90 | echo "Trying the Gitea $RENOVATE_USERNAME user personal access token..." 91 | RENOVATE_TOKEN="$(cat tmp/renovate-gitea-token.txt)" 92 | export RENOVATE_TOKEN 93 | curl \ 94 | --silent \ 95 | --show-error \ 96 | --fail-with-body \ 97 | -H "Authorization: token $RENOVATE_TOKEN" \ 98 | -H 'Accept: application/json' \ 99 | "$gitea_url/api/v1/version" \ 100 | | jq \ 101 | > /dev/null 102 | 103 | # create remote repository in gitea. 104 | echo "Creating Gitea $RENOVATE_USERNAME test repository..." 105 | curl \ 106 | --silent \ 107 | --show-error \ 108 | --fail-with-body \ 109 | -u "$RENOVATE_USERNAME:$RENOVATE_PASSWORD" \ 110 | -X POST \ 111 | -H 'Accept: application/json' \ 112 | -H 'Content-Type: application/json' \ 113 | -d '{"name": "test"}' \ 114 | "$gitea_url/api/v1/user/repos" \ 115 | | jq \ 116 | > /dev/null 117 | 118 | # push the code to local gitea repository. 119 | # NB running renovate locally is not yet supported. 120 | # see https://github.com/renovatebot/renovate/issues/3609 121 | echo "Pushing local repository to Gitea $RENOVATE_USERNAME test repository..." 122 | git push --force "$GIT_PUSH_REPOSITORY" 123 | 124 | # see https://docs.renovatebot.com/modules/platform/gitea/ 125 | # see https://docs.renovatebot.com/self-hosted-configuration/#dryrun 126 | # see https://github.com/renovatebot/renovate/blob/main/docs/usage/examples/self-hosting.md 127 | # see https://github.com/renovatebot/renovate/tree/main/lib/modules/datasource 128 | # see https://github.com/renovatebot/renovate/tree/main/lib/modules/versioning 129 | RENOVATE_TOKEN="$(cat tmp/renovate-gitea-token.txt)" 130 | export RENOVATE_TOKEN 131 | # NB these can also be passed as raw positional arguments to docker run. 132 | export RENOVATE_REPOSITORIES="$RENOVATE_USERNAME/test" 133 | # see https://docs.github.com/en/rest/rate-limit#get-rate-limit-status-for-the-authenticated-user 134 | # see https://github.com/settings/tokens 135 | # NB this is only used for authentication. the token should not have any scope enabled. 136 | #export GITHUB_COM_TOKEN='TODO-YOUR-TOKEN' 137 | # let renovate create all the required pull requests. 138 | # see https://docs.renovatebot.com/configuration-options/#prhourlylimit 139 | # see https://docs.renovatebot.com/configuration-options/#prconcurrentlimit 140 | export RENOVATE_PR_HOURLY_LIMIT='0' 141 | export RENOVATE_PR_CONCURRENT_LIMIT='0' 142 | echo 'Running renovate...' 143 | # NB use --dry-run=lookup for not modifying the repository (e.g. for not 144 | # creating pull requests). 145 | docker run \ 146 | --rm \ 147 | --tty \ 148 | --interactive \ 149 | --net host \ 150 | --env GITHUB_COM_TOKEN \ 151 | --env RENOVATE_ENDPOINT \ 152 | --env RENOVATE_TOKEN \ 153 | --env RENOVATE_REPOSITORIES \ 154 | --env RENOVATE_PR_HOURLY_LIMIT \ 155 | --env RENOVATE_PR_CONCURRENT_LIMIT \ 156 | --env LOG_LEVEL=debug \ 157 | --env LOG_FORMAT=json \ 158 | "renovate/renovate:$renovate_version-slim" \ 159 | --platform=gitea \ 160 | --git-url=endpoint \ 161 | >tmp/renovate-log.json 162 | 163 | echo 'Getting results...' 164 | # extract the errors. 165 | jq 'select(.err)' tmp/renovate-log.json >tmp/renovate-errors.json 166 | # extract the result from the renovate log. 167 | jq 'select(.msg == "packageFiles with updates") | .config' tmp/renovate-log.json >tmp/renovate-result.json 168 | # extract all the dependencies. 169 | jq 'to_entries[].value[] | {packageFile,dep:.deps[]}' tmp/renovate-result.json >tmp/renovate-dependencies.json 170 | # extract the dependencies that have updates. 171 | jq 'select((.dep.updates | length) > 0)' tmp/renovate-dependencies.json >tmp/renovate-dependencies-updates.json 172 | 173 | # helpers. 174 | function show-title { 175 | echo 176 | echo '#' 177 | echo "# $1" 178 | echo '#' 179 | echo 180 | } 181 | 182 | # show errors. 183 | if [ "$(jq --slurp length tmp/renovate-errors.json)" -ne '0' ]; then 184 | show-title errors 185 | jq . tmp/renovate-errors.json 186 | fi 187 | 188 | # show dependencies. 189 | function show-dependencies { 190 | show-title "$1" 191 | ( 192 | printf 'packageFile\tdatasource\tdepName\tcurrentValue\tnewVersions\tskipReason\twarnings\n' 193 | jq \ 194 | -r \ 195 | '[ 196 | .packageFile, 197 | .dep.datasource, 198 | .dep.depName, 199 | .dep.currentValue, 200 | (.dep | select(.updates) | .updates | map(.newVersion) | join(" | ")), 201 | .dep.skipReason, 202 | (.dep | select(.warnings) | .warnings | map(.message) | join(" | ")) 203 | ] | @tsv' \ 204 | "$2" \ 205 | | sort 206 | ) | column -t -s "$(printf \\t)" 207 | } 208 | show-dependencies 'Dependencies' tmp/renovate-dependencies.json 209 | show-dependencies 'Dependencies Updates' tmp/renovate-dependencies-updates.json 210 | 211 | # show the gitea project. 212 | show-title "See PRs at $gitea_url/$RENOVATE_USERNAME/test/pulls (you can login as $RENOVATE_USERNAME:$RENOVATE_PASSWORD)" 213 | --------------------------------------------------------------------------------