mirror of https://github.com/istio/istio.io.git
616 lines
26 KiB
Python
Executable File
616 lines
26 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# Copyright Istio Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import collections
|
|
import linecache
|
|
import string
|
|
import sys
|
|
import os
|
|
import re
|
|
import requests
|
|
|
|
from ruamel import yaml
|
|
|
|
#
|
|
# This script generates the installation option differences between the
|
|
# current release and the previous release. It generates the index.md content for
|
|
# the current release from the values.yaml files under the charts and subcharts
|
|
# directory and compares the configuration options against the index.md from
|
|
# the previous release (It gets the previous release version from the github api:
|
|
# https://api.github.com/repos/istio/istio/branches).
|
|
#
|
|
|
|
#
|
|
# Reads a documented Helm values.yaml file and produces a
|
|
# MD formatted table. pip install ruamel to obtain the proper
|
|
# YAML decoder. ruamel maintains ordering and comments. The
|
|
# comments are needed in order to decode the commented helm
|
|
# values.yaml file
|
|
#
|
|
ISTIO_CONFIG_DIR = "istio/install/kubernetes/helm/istio"
|
|
YAML_CONFIG_DIR = ISTIO_CONFIG_DIR + "/charts"
|
|
VALUES_YAML = "values.yaml"
|
|
ISTIO_IO_DIR = os.path.abspath(__file__ + "/../../")
|
|
CONFIG_INDEX_DIR = "content/en/docs/reference/config/installation-options/index.md"
|
|
CONFIG_INDEX_DIFF_DIR = "content/en/docs/reference/config/installation-options-changes/index.md"
|
|
CONFIG_IGNORE_LIST = ["global.hub"]
|
|
|
|
|
|
def endOfTheList(context, lineNum, lastLineNum, totalNum):
|
|
flag = 0
|
|
valueList = []
|
|
nextLineNum = lineNum + 1
|
|
currentLine = context[lastLineNum]
|
|
whitespaces = (len(currentLine) - len(currentLine.lstrip())) / 2
|
|
|
|
if lineNum != lastLineNum:
|
|
return False, valueList
|
|
|
|
for nextLineNum in range(lineNum + 1, totalNum):
|
|
nextLine = context[nextLineNum]
|
|
|
|
if len(nextLine.lstrip()) != 0 and '#' != nextLine.lstrip()[0] and ':' in nextLine:
|
|
if whitespaces >= (len(nextLine) - len(nextLine.lstrip())) / 2:
|
|
if flag == 0:
|
|
valueList.append(currentLine.split(':', 1)[1].strip())
|
|
return True, valueList
|
|
else:
|
|
return True, valueList
|
|
elif len(nextLine.lstrip()) != 0 and '#' != nextLine.lstrip()[0] and ':' not in nextLine and len(nextLine.strip()) != 0:
|
|
value = nextLine.replace(' ', '')
|
|
valueList.append(value.lstrip('-').strip())
|
|
flag += 1
|
|
nextLineNum += 1
|
|
|
|
if lastLineNum == totalNum - 1 and len(currentLine.lstrip()) != 0 and '#' != currentLine.lstrip()[0]:
|
|
valueList.append(currentLine.split(':', 1)[1].strip())
|
|
|
|
return True, valueList
|
|
|
|
|
|
# ordered dictionary to store the configuration options for the subcomponents of Istio. This
|
|
# will be used to populate a new index.md
|
|
prdict = collections.defaultdict(list)
|
|
# ordered dictionary to store the differences of configuration options between the new
|
|
# index.md and the previous version (i.e, configurations options already listed in the index.md).
|
|
od_diff = collections.defaultdict(list)
|
|
od_diff_new = collections.defaultdict(list)
|
|
od_diff_removed = collections.defaultdict(list)
|
|
od_diff_unchanged = collections.defaultdict(list)
|
|
|
|
|
|
def decode_helm_yaml(s):
|
|
ret_val = ''
|
|
#
|
|
# Iterate through all the directories under /istio/install/kubernetes/heml/subcharts
|
|
# and process the configuration options from the respective values.yaml. The
|
|
# configuration option name is the name of the directory that contains values.yaml.
|
|
# This name will be passed in to the the function process_helm_yaml
|
|
#
|
|
subchart_dir = os.path.join(ISTIO_IO_DIR, YAML_CONFIG_DIR)
|
|
for cfile in os.listdir(subchart_dir):
|
|
values_yaml_dir = os.path.join(subchart_dir, cfile)
|
|
values_yaml_file = os.path.join(values_yaml_dir, VALUES_YAML)
|
|
process_helm_yaml(values_yaml_file, cfile)
|
|
|
|
#
|
|
# Process configuration options in values.yaml under istio/install/kubernetes/helm/istio.
|
|
# The configuration option names are present in the values.yaml, hence we do not need to
|
|
# pass it to process_helm_yaml.
|
|
#
|
|
istio_yaml_config_dir = os.path.join(ISTIO_IO_DIR, ISTIO_CONFIG_DIR)
|
|
values_yaml_file = os.path.join(istio_yaml_config_dir, VALUES_YAML)
|
|
process_helm_yaml(values_yaml_file, '')
|
|
|
|
return ret_val
|
|
|
|
|
|
def process_helm_yaml(values_yaml, option):
|
|
ret_val = ''
|
|
storekey = ''
|
|
desc = ''
|
|
newkey = ''
|
|
whitespaces = 0
|
|
flag = 0
|
|
lineNum = 0
|
|
newConfigList = []
|
|
loaded = None
|
|
|
|
context = linecache.getlines(values_yaml)
|
|
totalNum = len(context)
|
|
lastLineNum = 0
|
|
key = option
|
|
|
|
count = 0
|
|
with open(values_yaml, 'r') as f_v:
|
|
d_v = f_v.read()
|
|
loaded = yaml.round_trip_load(d_v)
|
|
|
|
for lineNum in range(0, totalNum):
|
|
if context[lineNum].strip().startswith('- '):
|
|
pass
|
|
elif '#' in context[lineNum] and '#' == context[lineNum].lstrip()[0]:
|
|
if "Description: " in context[lineNum]:
|
|
desc = context[lineNum].strip()
|
|
elif ':' in context[lineNum] and '#' != context[lineNum].lstrip()[0]:
|
|
lastLineNum = lineNum
|
|
if flag == 1:
|
|
whitespaces = (len(context[lineNum]) - len(context[lineNum].lstrip())) / 2
|
|
periods = key.count('.')
|
|
if (option == ''):
|
|
while (whitespaces <= periods):
|
|
key = key.rstrip(string.ascii_letters[::-1] + string.digits + '_' + '-' + '/').rstrip('.')
|
|
whitespaces += 1
|
|
else:
|
|
while (whitespaces < periods):
|
|
key = key.rstrip(string.ascii_letters[::-1] + string.digits + '_' + '-' + '/').rstrip('.')
|
|
whitespaces += 1
|
|
flag = 0
|
|
|
|
key = key + '.' + context[lineNum].split(':', 1)[0].strip()
|
|
isEnd, ValueList = endOfTheList(context, lineNum, lastLineNum, totalNum)
|
|
if isEnd:
|
|
flag = 1
|
|
|
|
storekey = key
|
|
sk = storekey.split('.', 2)
|
|
if len(sk) > 1:
|
|
storekey = '.'.join(sk[:1]).lstrip('.')
|
|
else:
|
|
storekey = '.'.join(sk[:0]).lstrip('.')
|
|
|
|
#
|
|
# If we are processing the configurations options within the values.yaml under istio,
|
|
# if the options have already been processed (from the subcharts directory), then we
|
|
# do not want to process it again. If the configuration option has not been processed
|
|
# before, then it is a new configuration option which needs to be processed (for e.g,
|
|
# global, istiocoredns)
|
|
#
|
|
# option == '' - This condition means that we are looking at the values.yaml under the
|
|
# istio directory. Hence, the configuration option names will be inside
|
|
# the values.yaml file. (On the other hand, for the values.yaml file under
|
|
# the subcharts directory, we get the name of the configuration option
|
|
# from the name of the directories under the subcharts directory.)
|
|
# newConfigList - This list is used to track configuration options in istio/values.yaml
|
|
# that haven't been processed before (or that does not have a corresponding
|
|
# directory under subcharts directory with values.yaml. E.g: global,
|
|
# istiocoredns)
|
|
#
|
|
# This first condition checks that if this is the values.yaml file under istio directory,
|
|
# and the configuration option to process (storekey) has not already been processed (this
|
|
# conditions: "prdict.get(storekey) != None and (storekey in newConfigList)" together
|
|
# makes sure that the condition where some parameters for a new configuration option like
|
|
# 'global' has been processed and entered into the dictionary 'prdict' is still processed
|
|
# because it is in the newConfigList. If a configuration option was processed from
|
|
# the values.yaml under the subcharts directory, it will not be in the newConfigList.
|
|
# subcharts directory), then go ahead and process the parameters for this option.
|
|
#
|
|
if option == '' and prdict.get(storekey) is not None and (storekey in newConfigList):
|
|
pass
|
|
#
|
|
# This second condition checks if this is the values.yaml file under istio directory, and
|
|
# the configuration option to process (storekey) has not been processed (this could
|
|
# happen the first time we read a configuration option from the istio/values.yaml file),
|
|
# then add this configuration option to the newConfigList to mark it as an option that
|
|
# needs to be processed.
|
|
#
|
|
elif option == '' and prdict.get(storekey) is None:
|
|
newConfigList.append(storekey)
|
|
#
|
|
# This third condition checks if this is the values.yaml file under istio directory,
|
|
# and the configuration option to process (storekey) has already been processed and if
|
|
# this is not a new configuration option, (this could happen if we have already
|
|
# processed the corresponding values.yaml under the subcharts directory), then ignore
|
|
# this configuration option and do not process the values in this file.
|
|
#
|
|
elif option == '' and prdict.get(storekey) is not None:
|
|
continue
|
|
|
|
if len(context[lastLineNum].lstrip()) != 0 and '#' != context[lastLineNum].lstrip()[0]:
|
|
isEnd, ValueList = endOfTheList(context, lineNum, lastLineNum, totalNum)
|
|
|
|
if (isEnd):
|
|
flag = 1
|
|
keysplit = key.split('.')
|
|
for kv in keysplit:
|
|
if kv != '':
|
|
newkey = newkey + '.' + kv
|
|
|
|
newkey = newkey.lstrip('.')
|
|
|
|
# Filling Description Fields
|
|
if ("." in newkey):
|
|
plist = newkey.split('.')
|
|
da = None
|
|
for item in plist:
|
|
desc = ''
|
|
# If this is the same as the configuration option name, then
|
|
# continue to the next key in the list
|
|
if item.rstrip() == option.rstrip():
|
|
continue
|
|
if da is None:
|
|
if loaded.ca.items:
|
|
if item in loaded.ca.items:
|
|
desc = processComments(loaded.ca.items[item])
|
|
da = loaded[item]
|
|
elif isinstance(da, dict):
|
|
if item in da.keys()[0]:
|
|
commentTokens = da.ca.comment
|
|
if commentTokens is not None:
|
|
desc = processComments(commentTokens)
|
|
|
|
if da.ca.items:
|
|
if item in da.ca.items:
|
|
desc = desc + processComments(da.ca.items[item])
|
|
da = da[item]
|
|
else:
|
|
if item in da.keys():
|
|
da = da.get(item)
|
|
else:
|
|
da = da.values()[0]
|
|
|
|
ValueStr = (' ').join(ValueList)
|
|
if ValueStr:
|
|
if (desc in ValueStr):
|
|
ValueStr = ValueStr.replace("#" + desc, "")
|
|
desc = desc.replace('`', '')
|
|
desc = sanitizeValueStr(desc)
|
|
if desc.strip():
|
|
desc = '`' + desc.strip() + '`'
|
|
prdict[storekey].append("| `%s` | `%s` | %s |" % (newkey, ValueStr.rstrip(), desc))
|
|
desc = ''
|
|
|
|
key = newkey
|
|
newkey = ''
|
|
|
|
lineNum += 1
|
|
return ret_val
|
|
|
|
|
|
def processComments(comments):
|
|
description = ''
|
|
for c in comments:
|
|
if c is None:
|
|
pass
|
|
elif isinstance(c, list):
|
|
for comment in c:
|
|
if (comment is None):
|
|
pass
|
|
else:
|
|
# We want to avoid including commented out key: value pairs in the values.yaml as
|
|
# part of the description/comments. For example:
|
|
# # minAvailable: 1
|
|
# # maxUnavailable: 1
|
|
# # - secretName: grafana-tls
|
|
# sessionAffinityEnabled: false
|
|
# We do not want the commented out key-value pairs (minAvailable,maxUnavailable, secretName)
|
|
# to be included as part of the description for 'sessionAffinityEnabled'
|
|
#
|
|
pattern = re.compile(r"#\s[-\s]*[\S]+:(?:\s(?!\S+:)\S+)*")
|
|
groups = pattern.match(comment.value)
|
|
if groups:
|
|
description = ''
|
|
break
|
|
if comment.value.endswith('\n\n'):
|
|
description = ''
|
|
else:
|
|
if comment.value.rstrip() == '#':
|
|
continue
|
|
else:
|
|
description = description + comment.value.replace('`', '').replace("#", '').rstrip()
|
|
elif isinstance(c, yaml.Token):
|
|
description = description + c.value.rstrip().replace("#", '')
|
|
|
|
return description
|
|
|
|
|
|
def sanitizeValueStr(value):
|
|
# We can include more special characters later if they need to
|
|
# be escaped. For now just including the 'pipe' symbol appearing
|
|
# in the value of a configuration option.
|
|
# e.g: | `global.tracer.lightstep.secure` | `true # example: true\|false` | |
|
|
#
|
|
# Without escaping the 'pipe' character, it was interpreting it as the end/start
|
|
# of table column. Using the example above, without escaping the pipe symbol, it
|
|
# was interpreting it as:
|
|
# | `global.tracer.lightstep.secure` | `true # example: true |false` | |
|
|
#
|
|
regex = re.compile(r"\|")
|
|
if value is not None and regex.search(value) is not None:
|
|
value = value.replace("|", r"\|")
|
|
return value
|
|
|
|
# Compares the configuration option value from the newly discovered set of values (stored
|
|
# in prdict dictionary) and its previous version (stored in index.md). If there is no
|
|
# change in the configuration option value between the 2 versions, it will be ignored. If
|
|
# there are any differences, we will store the differences (will track differences for key,
|
|
# value and description of a configuration option) in the 'od_diff' dictionary. The values
|
|
# stored in this dictionary will later be written to CONFIG_INDEX_DIFF_DIR.
|
|
#
|
|
# The difference between the configuration option values is stored in the CONFIG_INDEX_DIFF_DIR
|
|
# in the format:
|
|
# | KEY | OLD DEFAULT VALUE | NEW DEFAULT VALUE | OLD DESCRIPTION | NEW DESCRIPTION |
|
|
# | ------ | ------------ | ------------ | ------------ | ------------ |
|
|
# | Key | oldValue | newValue | oldDesc | newDesc |
|
|
#
|
|
# If a configuration option is present only in the latest version, then the oldKey, oldValue
|
|
# and oldDescription will be represented as 'n/a' (vice-versa applies to newKey, newValue and
|
|
# newDescription).
|
|
#
|
|
# oValue - configuration option from the existing index.md
|
|
# nValue - configuration option from the current processing of configuration options to be
|
|
# stored in a new version of index.md
|
|
# k - istio component name for which these configuration options are being processed. This is
|
|
# used to populate the contents of 'od_diff' dictionary.
|
|
#
|
|
|
|
|
|
def compareValues(oValue, nValue, k):
|
|
# oValue and nVAlue contains configuration option in the format:
|
|
# '| `<Key>` | `<Value>` | `<Description>` |
|
|
# This needs to be split in order to get the Key, Value and Description values to compare.
|
|
oldKey = ''
|
|
oldValue = ''
|
|
oldDesc = ''
|
|
|
|
newKey = ''
|
|
newValue = ''
|
|
newDesc = ''
|
|
|
|
key = None
|
|
|
|
if nValue is not None:
|
|
groups = re.search(r"\| \`(.*)\` \| \`(.*)\` \| (.*) |", nValue.strip())
|
|
if groups:
|
|
newKey = groups.group(1)
|
|
newValue = groups.group(2)
|
|
newDesc = groups.group(3)
|
|
|
|
if oValue is not None and nValue is not None:
|
|
if len(oValue) == 1:
|
|
item = oValue[0]
|
|
|
|
if item == nValue:
|
|
key = newKey
|
|
oValue.remove(item)
|
|
od_diff_unchanged[k].append("| `%s` | `%s` | %s |" % (newKey, newValue.rstrip(), newDesc))
|
|
else:
|
|
groups = re.search(r"\| \`(.*)\` \| \`(.*)\` \|\s*(.*)\s*\|", item.strip())
|
|
if groups:
|
|
oldKey = groups.group(1)
|
|
oldValue = groups.group(2)
|
|
oldDesc = groups.group(3)
|
|
key = oldKey
|
|
|
|
if oldKey in CONFIG_IGNORE_LIST:
|
|
oValue.remove(item)
|
|
return key
|
|
|
|
if oldValue != newValue:
|
|
if oldValue is None:
|
|
oldValue = 'n/a'
|
|
if newValue is None:
|
|
newValue = 'n/a'
|
|
|
|
if oldDesc.strip() != newDesc.strip():
|
|
if (newDesc is None or newDesc == '') and (oldDesc is None or oldDesc == ''):
|
|
pass
|
|
if oldDesc is None:
|
|
oldDesc = 'n/a'
|
|
if newDesc is None or newDesc == '':
|
|
newDesc = 'n/a'
|
|
oValue.remove(item)
|
|
od_diff[k].append("| `%s` | `%s` | `%s` | %s | %s |" % (newKey, oldValue.rstrip(), newValue.rstrip(), oldDesc, newDesc))
|
|
else:
|
|
# This is the case where values are the same but descriptions are different. Right now, there is nothing more to do since
|
|
# we do not care about displaying values that haven't changed between releases.
|
|
oValue.remove(item)
|
|
|
|
#od_diff_unchanged[k].append("| `%s` | `%s` | %s |" % (newKey, newValue.rstrip(), newDesc))
|
|
else:
|
|
foundItem = 'false'
|
|
for item in oValue:
|
|
if item == nValue:
|
|
key = newKey
|
|
oValue.remove(item)
|
|
od_diff_unchanged[k].append("| `%s` | `%s` | %s |" % (newKey, newValue.rstrip(), newDesc))
|
|
foundItem = 'true'
|
|
break
|
|
else:
|
|
groups = re.search(r"\| \`(.*)\` \| \`(.*)\` \|\s*(.*)\s*\|", item.strip())
|
|
if groups:
|
|
oldKey = groups.group(1)
|
|
oldValue = groups.group(2)
|
|
oldDesc = groups.group(3)
|
|
|
|
if oldKey == newKey:
|
|
if oldValue == newValue and oldDesc != newDesc:
|
|
key = newKey
|
|
od_diff[k].append("| `%s` | `%s` | `%s` | %s | %s |" % (newKey, oldValue.rstrip(), newValue.rstrip(), oldDesc, newDesc))
|
|
oValue.remove(item)
|
|
foundItem = 'true'
|
|
break
|
|
|
|
if foundItem == 'false':
|
|
od_diff_new[k].append("| `%s` | `%s` | %s |" % (newKey, newValue.rstrip(), newDesc))
|
|
elif oValue is None:
|
|
key = newKey
|
|
od_diff_new[k].append("| `%s` | `%s` | %s |" % (newKey, newValue.rstrip(), newDesc))
|
|
elif nValue is None:
|
|
for item in oValue:
|
|
groups = re.search(r"\| \`(.*)\` \| \`(.*)\` \|\s*(.*)\s*\|", item.strip())
|
|
if groups:
|
|
oldKey = groups.group(1)
|
|
oldValue = groups.group(2)
|
|
oldDesc = groups.group(3)
|
|
|
|
key = oldKey
|
|
od_diff_removed[k].append("| `%s` | `%s` | %s |" % (oldKey, oldValue.rstrip(), oldDesc))
|
|
|
|
return key
|
|
|
|
#
|
|
# Get the previous release number so that we can retrieve the index.md for that
|
|
# release. The release branches are tagged in the following format: release-<number>
|
|
#
|
|
|
|
|
|
def getPreviousRelease():
|
|
req = requests.get("https://api.github.com/repos/istio/istio/branches")
|
|
jsonData = req.json()
|
|
previousRelease = 0.0
|
|
|
|
for x in jsonData:
|
|
releaseName = x['name']
|
|
if releaseName.startswith('release-'):
|
|
releaseNum = releaseName.split('release-')
|
|
if releaseNum[1] > previousRelease:
|
|
previousRelease = releaseNum[1]
|
|
return previousRelease
|
|
|
|
#
|
|
# Get the index.md for the previous release.
|
|
#
|
|
|
|
|
|
def getContentFromPreviousRelease(releaseName):
|
|
istio_url = 'https://raw.githubusercontent.com/istio/istio.io/release-' + releaseName + '/content/en/docs/reference/config/installation-options/index.md'
|
|
req = requests.get(istio_url)
|
|
content = req.text
|
|
indexMap = collections.defaultdict(list)
|
|
|
|
# store all the configurations options from the index.md file into the indexMap
|
|
# dictionary. This will be used to compare the values with the latest version
|
|
# of configuration options.
|
|
data = content.split('\n')
|
|
for d in data:
|
|
if d.rstrip() != '' and d != '| Key | Default Value | Description |' and d != '| --- | --- | --- |' and d[0:1] == '|' and d[-1] == '|':
|
|
groups = re.search(r"\| \`(.*)\` \| \`(.*)\` \| (.*) |", d.strip())
|
|
if groups:
|
|
key = groups.group(1)
|
|
if key in indexMap:
|
|
value = indexMap.get(key)
|
|
value.append(d.strip())
|
|
else:
|
|
indexMap[key].append(d.strip())
|
|
return indexMap
|
|
|
|
|
|
def writeVersionDiffs(index_diff_file):
|
|
meta = ""
|
|
|
|
for d in index_diff_file:
|
|
meta = meta + d
|
|
if "<!-- AUTO-GENERATED-START -->" in d:
|
|
break
|
|
|
|
index_diff_file.seek(0)
|
|
index_diff_file.write(meta)
|
|
|
|
'''
|
|
if od_diff_unchanged:
|
|
index_diff_file.write('\n## Unmodified configuration options\n')
|
|
|
|
for k, v in od_diff_unchanged.items():
|
|
index_diff_file.write("\n### Unmodified `%s` key/value pairs\n\n" % k)
|
|
index_diff_file.write('| Key | Default Value | Description |\n')
|
|
index_diff_file.write('| --- | --- | --- |\n')
|
|
|
|
for value in v:
|
|
index_diff_file.write('%s\n' % (value))
|
|
'''
|
|
|
|
if od_diff:
|
|
index_diff_file.write('\n## Modified configuration options\n')
|
|
|
|
for k, v in od_diff.items():
|
|
index_diff_file.write("\n### Modified `%s` key/value pairs\n\n" % k)
|
|
index_diff_file.write('| Key | Old Default Value | New Default Value | Old Description | New Description |\n')
|
|
index_diff_file.write('| --- | --- | --- | --- | --- |\n')
|
|
|
|
for value in v:
|
|
index_diff_file.write('%s\n' % (value))
|
|
|
|
if od_diff_new:
|
|
index_diff_file.write('\n## New configuration options\n')
|
|
|
|
for k, v in od_diff_new.items():
|
|
index_diff_file.write("\n### New `%s` key/value pairs\n\n" % k)
|
|
index_diff_file.write('| Key | Default Value | Description |\n')
|
|
index_diff_file.write('| --- | --- | --- |\n')
|
|
|
|
for value in v:
|
|
index_diff_file.write('%s\n' % (value))
|
|
|
|
if od_diff_removed:
|
|
index_diff_file.write('\n## Removed configuration options\n')
|
|
|
|
for k, v in od_diff_removed.items():
|
|
index_diff_file.write("\n### Removed `%s` key/value pairs\n\n" % k)
|
|
index_diff_file.write('| Key | Default Value | Description |\n')
|
|
index_diff_file.write('| --- | --- | --- |\n')
|
|
|
|
for value in v:
|
|
index_diff_file.write('%s\n' % (value))
|
|
|
|
index_diff_file.write("\n<!-- AUTO-GENERATED-END -->\n")
|
|
index_diff_file.truncate()
|
|
|
|
|
|
with open(os.path.join(ISTIO_IO_DIR, CONFIG_INDEX_DIR), 'r') as f:
|
|
endReached = False
|
|
key = ''
|
|
# A list used to track the configuration options that has been compared and processed when going
|
|
# through the configurations processed in the latest version
|
|
indexList = []
|
|
previousRelease = getPreviousRelease()
|
|
indexMap = getContentFromPreviousRelease(previousRelease)
|
|
|
|
# transform values.yaml into a encoded string dictionary
|
|
pyaml = yaml.YAML()
|
|
pyaml.explicit_start = True
|
|
pyaml.dump('', sys.stdout, transform=decode_helm_yaml)
|
|
|
|
# Order the encoded string dictionary
|
|
od = collections.OrderedDict(sorted(prdict.items(), key=lambda t: t[0]))
|
|
|
|
# Print encoded string dictionary
|
|
for k, v in od.items():
|
|
for value in v:
|
|
# Compare configuration option values from the latest version
|
|
# with the older version.
|
|
groups = re.search(r"\| \`(.*)\` \| \`(.*)\` \| (.*) |", value.strip())
|
|
if groups:
|
|
key = groups.group(1)
|
|
indexValue = indexMap.get(key)
|
|
|
|
indexList.append(compareValues(indexValue, value, k))
|
|
|
|
# We want to include any configuration options that was discovered in
|
|
# the older version but not available in the current version
|
|
for k in indexMap.keys():
|
|
key = k.split('.')[0]
|
|
indexList.append(compareValues(indexMap.get(k), None, key))
|
|
|
|
# This index.md file is used to track the differences of configuration
|
|
# option values between the current and previous release. All the
|
|
# differences in configuration option values between the current
|
|
# and previous release (tracked in the 'od_diff' dictionary) will be
|
|
# written to the index.md file
|
|
index_diff_file = open(os.path.join(ISTIO_IO_DIR, CONFIG_INDEX_DIFF_DIR), 'r+')
|
|
writeVersionDiffs(index_diff_file)
|
|
index_diff_file.close()
|