Skip to content

Commit 6f6df43

Browse files
authored
v7.6.0
2 parents ee27f1c + 2899de8 commit 6f6df43

21 files changed

Lines changed: 545 additions & 272 deletions

.editorconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ indent_style = tab
99
indent_size = 2
1010
tab_width = 2
1111

12-
1312
[*.py]
1413
indent_style = tab
1514
indent_size = 2

.github/workflows/ApplicationTesting.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ jobs:
114114
requirementsFile = Path(requirements)
115115
116116
if not requirementsFile.exists():
117-
print(f"::error title=FileNotFoundError::{requirementsFile}")
117+
print(f"::error title=FileNotFoundError::Requirements file '{requirementsFile}' doesn't exist.")
118118
exit(1)
119119
120120
print(f"requirements file: {requirementsFile.as_posix()}")

.github/workflows/CompletePipeline.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ on:
123123
required: false
124124
default: 'true'
125125
type: string
126+
documentation_steps:
127+
description: 'Create documentation.'
128+
required: false
129+
default: 'html pages' # none, html, latex, pdf, pages, asset, all
130+
type: string
131+
miktex_image:
132+
description: 'Name of MiKTeX docker image.'
133+
required: false
134+
default: 'pytooling/miktex:sphinx'
135+
type: string
126136
secrets:
127137
PYPI_TOKEN:
128138
description: "Token for pushing releases to PyPI."
@@ -152,6 +162,7 @@ jobs:
152162
include_list: ${{ inputs.unittest_include_list }}
153163
exclude_list: ${{ inputs.unittest_exclude_list }}
154164
disable_list: ${{ inputs.unittest_disable_list }}
165+
documentation_steps: ${{ inputs.documentation_steps }}
155166

156167
# AppTestingParams:
157168
# uses: pyTooling/Actions/.github/workflows/Parameters.yml@main
@@ -176,6 +187,7 @@ jobs:
176187
include_list: ${{ inputs.unittest_include_list }}
177188
exclude_list: ${{ inputs.unittest_exclude_list }}
178189
disable_list: ${{ inputs.unittest_disable_list }}
190+
documentation_steps: 'none'
179191

180192
VersionCheck:
181193
name: ''
@@ -210,15 +222,15 @@ jobs:
210222
211223
versionFile = Path("${{ needs.UnitTestingParams.outputs.package_version_file }}")
212224
if not versionFile.exists():
213-
print(f"::error title=CompletePipeline::Version file '{versionFile}' not found.")
225+
print(f"::error title=CompletePipeline::Version file '{versionFile}' doesn't exist.")
214226
exit(1)
215227
216228
versionInformation = extractVersionInformation(versionFile)
217229
print(f"expected: {expectedVersion}")
218230
print(f"from code: {versionInformation.Version}")
219231
220232
if expectedVersion != versionInformation.Version:
221-
print(f"::error title=CompletePipeline::Expected version does not version in Python code.")
233+
print(f"::error title=CompletePipeline::Expected version ({expectedVersion}) doesn't match the version in Python code ({versionInformation.Version}).")
222234
exit(2)
223235
224236
# Write jobs to special file
@@ -262,6 +274,7 @@ jobs:
262274
uses: pyTooling/Actions/.github/workflows/CheckCodeQuality.yml@main
263275
needs:
264276
- UnitTestingParams
277+
- PublishTestResults # artificial dependency to delay start when pipeline has free job resources
265278
with:
266279
python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
267280
package_directory: ${{ needs.UnitTestingParams.outputs.package_directory }}
@@ -273,6 +286,7 @@ jobs:
273286
uses: pyTooling/Actions/.github/workflows/CheckDocumentation.yml@main
274287
needs:
275288
- UnitTestingParams
289+
- StaticTypeCheck # artificial dependency to delay start when pipeline has free job resources
276290
with:
277291
python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
278292
directory: ${{ needs.UnitTestingParams.outputs.package_directory }}
@@ -390,6 +404,7 @@ jobs:
390404
latex_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).documentation_latex }}
391405
pdf_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).documentation_pdf }}
392406
can-fail: 'true'
407+
miktex_image: ${{ inputs.miktex_image }}
393408

394409
PublishToGitHubPages:
395410
uses: pyTooling/Actions/.github/workflows/PublishToGitHubPages.yml@main

.github/workflows/ExtractConfiguration.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,13 @@ jobs:
126126
toolSection = pyProjectSettings["tool"]
127127
if "pytest" in toolSection:
128128
section = toolSection["pytest"]
129+
# TODO: will be dropped in @r8
129130
if "junit_xml" in section:
130131
unittestXMLFile = Path(section["junit_xml"])
132+
elif "addopts" in section:
133+
options = {k: v for k, v in (option.split("=") for option in section["addopts"] if "=" in option)}
134+
if "--junitxml" in options:
135+
unittestXMLFile = Path(options["--junitxml"])
131136
132137
if "pyedaa-reports" in toolSection:
133138
section = toolSection["pyedaa-reports"]
@@ -153,7 +158,7 @@ jobs:
153158
typingHTMLDirectory = Path(section["html_report"])
154159
else:
155160
print(f"File '{pyProjectFile}' not found.")
156-
print(f"::error title=FileNotFoundError::File '{pyProjectFile}' not found.")
161+
print(f"::error title=FileNotFoundError::Python project file '{pyProjectFile}' doesn't exist.")
157162
exit(1)
158163
159164
# Read output paths from '.coveragerc' file
@@ -170,7 +175,7 @@ jobs:
170175
coverageJSONFile = Path(coverageRCSettings["json"]["output"])
171176
else:
172177
print(f"File '{coverageRCFile}' not found.")
173-
print(f"::error title=FileNotFoundError::File '{coverageRCFile}' not found.")
178+
print(f"::error title=FileNotFoundError::Coverage RC file '{coverageRCFile}' doesn't exist.")
174179
exit(1)
175180
176181
unittest_report_xml = {

.github/workflows/LaTeXDocumentation.yml

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,15 @@ on:
3737
description: 'LaTeX root document without *.tex extension.'
3838
required: true
3939
type: string
40+
miktex_image:
41+
description: 'Name of MiKTeX docker image.'
42+
required: false
43+
default: 'pytooling/miktex:sphinx'
44+
type: string
4045
processor:
4146
description: 'Name of the used LaTeX processor.'
4247
required: false
43-
default: 'xelatex'
48+
default: 'lualatex'
4449
type: string
4550
halt-on-error:
4651
description: 'Halt on first error, otherwise continue as long as possible.'
@@ -64,9 +69,7 @@ jobs:
6469
runs-on: "ubuntu-${{ inputs.ubuntu_image_version }}"
6570
continue-on-error: ${{ inputs.can-fail == 'true' }}
6671
container:
67-
image: pytooling/miktex:sphinx
68-
volumes:
69-
- ${{ github.workspace }}/latex:/latex
72+
image: ${{ inputs.miktex_image }}
7073
steps:
7174
- name: 📥 Download artifacts '${{ inputs.latex_artifact }}' from 'SphinxDocumentation' job
7275
uses: pyTooling/download-artifact@v8
@@ -75,15 +78,28 @@ jobs:
7578
path: latex
7679
investigate: 'true'
7780

81+
- name: Update
82+
run: |
83+
sudo miktex --admin packages update-package-database
84+
sudo miktex --admin packages update
85+
sudo initexmf --admin --update-fndb
86+
7887
- name: Build LaTeX document using 'pytooling/miktex:sphinx'
7988
if: inputs.pdf_artifact != ''
8089
run: |
90+
set -o pipefail
91+
8192
if [[ "${{ inputs.halt-on-error }}" == "true" ]]; then
8293
HALT_ON_ERROR="--halt-on-error"
8394
fi
8495
8596
cd latex
86-
latexmk --${{ inputs.processor }} --interaction=nonstopmode -file-line-error -max-print-line=250 ${HALT_ON_ERROR} "${{ inputs.document }}.tex"
97+
latexmk \
98+
--${{ inputs.processor }} \
99+
--interaction=nonstopmode \
100+
--file-line-error \
101+
${HALT_ON_ERROR} \
102+
"${{ inputs.document }}.tex" | filter.latexmk.sh
87103
88104
- name: 📤 Upload 'PDF Documentation' artifact
89105
uses: pyTooling/upload-artifact@v7

.github/workflows/Parameters.yml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ on:
110110
required: false
111111
default: 'macos-15'
112112
type: string
113+
documentation_steps:
114+
description: 'Create documentation.'
115+
required: false
116+
default: 'all' # none, html, latex, pdf, pages, asset, all
117+
type: string
113118
pipeline-delay:
114119
description: 'Slow down this job, to delay the startup of the GitHub Action pipline.'
115120
required: false
@@ -234,9 +239,12 @@ jobs:
234239
from pathlib import Path
235240
from textwrap import dedent
236241
237-
package_namespace = "${{ inputs.package_namespace }}".strip()
238-
package_name = "${{ inputs.package_name }}".strip()
239-
artifact_basename = "${{ steps.variables.outputs.artifact_basename }}"
242+
package_namespace = "${{ inputs.package_namespace }}".strip()
243+
package_name = "${{ inputs.package_name }}".strip()
244+
artifact_basename = "${{ steps.variables.outputs.artifact_basename }}"
245+
documentationSteps = [step for step in "${{ inputs.documentation_steps }}".split(" ") if step != ""]
246+
if "none" in documentationSteps:
247+
documentationSteps = []
240248
241249
artifact_names = {
242250
"unittesting_xml": f"{artifact_basename}-UnitTestReportSummary-XML",
@@ -256,6 +264,15 @@ jobs:
256264
"documentation_latex": f"{artifact_basename}-Documentation-LaTeX",
257265
"documentation_pdf": f"{artifact_basename}-Documentation-PDF",
258266
}
267+
if "html" not in documentationSteps and "all" not in documentationSteps:
268+
print(f"Disabled HTML artifact: {artifact_names["documentation_html"]}")
269+
artifact_names["documentation_html"] = ""
270+
if "latex" not in documentationSteps and "all" not in documentationSteps:
271+
print(f"Disabled LaTeX artifact: {artifact_names["documentation_latex"]}")
272+
artifact_names["documentation_latex"] = ""
273+
if "pdf" not in documentationSteps and "all" not in documentationSteps:
274+
print(f"Disabled PDF artifact: {artifact_names["documentation_pdf"]}")
275+
artifact_names["documentation_pdf"] = ""
259276
260277
print("Artifacts Names ({len(artifact_names)}):")
261278
for id, artifactName in artifact_names.items():

.github/workflows/PrepareJob.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ jobs:
404404
export GH_TOKEN=${{ github.token }}
405405
406406
printf "Read second parent of current SHA (%s) ... " "${{ github.ref }}"
407-
FATHER_SHA=$(git rev-parse ${{ github.ref }}^2)
407+
FATHER_SHA=$(git rev-parse ${{ github.ref }}^2 2> /dev/null)
408408
if [[ $? -ne 0 || "{FATHER_SHA}" == "" ]]; then
409409
printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n"
410410
printf "${ANSI_LIGHT_RED}Couldn't read second parent (father) of '%s'.${ANSI_NOCOLOR}\n" "${{ github.ref }}^2"

.github/workflows/PublishReleaseNotes.yml

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -689,14 +689,14 @@ jobs:
689689
# Search PR with that SHA
690690
# Load description of that PR
691691
printf "Read second parent of current SHA (%s) ... " "${{ github.ref }}"
692-
FATHER_SHA=$(git rev-parse ${{ github.ref }}^2 -- 2> /dev/null)
692+
FATHER_SHA=$(git rev-parse ${{ github.ref }}^2 2> /dev/null)
693693
if [[ $? -ne 0 || "{FATHER_SHA}" == "" ]]; then
694694
printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n"
695695
printf "→ ${ANSI_LIGHT_YELLOW}Skipped readout of pull request description. This is not a merge commit.${ANSI_NOCOLOR}\n"
696696
else
697697
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
698698
699-
printf "Search Pull Request to '%s' and branch containing SHA %s ... " "${{ inputs.release_branch }}" "${FATHER_SHA}"
699+
printf "Search pull-request to '%s' and branch containing SHA %s ... " "${{ inputs.release_branch }}" "${FATHER_SHA}"
700700
PULL_REQUESTS=$(gh pr list --base "${{ inputs.release_branch }}" --search "${FATHER_SHA}" --state "merged" --json "title,number,mergedBy,mergedAt,body")
701701
if [[ $? -ne 0 || "${PULL_REQUESTS}" == "" ]]; then
702702
printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n"
@@ -719,7 +719,9 @@ jobs:
719719
printf " %s\n" "MergedAt: ${PR_MERGED_AT} ($(date -d"${PR_MERGED_AT}" '+%d.%m.%Y - %H:%M:%S'))"
720720
fi
721721
722+
printf "Write pull-request body of '%s' to '__PULLREQUEST__.md' ... " "${PR_TITLE}"
722723
printf "%s\n" "${PR_BODY}" > __PULLREQUEST__.md
724+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
723725
fi
724726
725727
# Check if a release description file should be used and exists.
@@ -757,51 +759,64 @@ jobs:
757759
NOTES=$(<__NOTES__.md)
758760
759761
# Inline description
762+
printf -- "Inline '__DESCRIPTION__.md' ... "
760763
if [[ -s __DESCRIPTION__.md ]]; then
761-
NOTES="${NOTES//%%DESCRIPTION%%/$(<__DESCRIPTION__.md)}"
764+
NOTES="${NOTES//%%DESCRIPTION%%/$(cat __DESCRIPTION__.md | sed 's/&/\\&/g')}"
765+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
762766
else
763767
NOTES="${NOTES//%%DESCRIPTION%%/}"
768+
printf "${ANSI_LIGHT_YELLOW}[SKIPPED]${ANSI_NOCOLOR}\n"
764769
fi
765770
766771
# Inline PullRequest and increase headline levels
772+
printf -- "Inline '__PULLREQUEST__.md' ... "
767773
if [[ -s __PULLREQUEST__.md ]]; then
768774
while [[ "${NOTES}" =~ %%(PULLREQUEST(\+[0-3])?)%% ]]; do
769775
case "${BASH_REMATCH[1]}" in
770776
"PULLREQUEST+0" | "PULLREQUEST")
771-
NOTES="${NOTES//${BASH_REMATCH[0]}/$(<__PULLREQUEST__.md)}"
777+
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed 's/&/\\&/g')}"
772778
;;
773779
"PULLREQUEST+1")
774-
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed -E 's/^(#+) /\1# /gm;t')}"
780+
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed -E 's/^(#+) /\1# /gm;t' | sed 's/&/\\&/g')}"
775781
;;
776782
"PULLREQUEST+2")
777-
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed -E 's/^(#+) /\1### /gm;t')}"
783+
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed -E 's/^(#+) /\1## /gm;t' | sed 's/&/\\&/g')}"
778784
;;
779785
"PULLREQUEST+3")
780-
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed -E 's/^(#+) /\1### /gm;t')}"
786+
NOTES="${NOTES//${BASH_REMATCH[0]}/$(cat __PULLREQUEST__.md | sed -E 's/^(#+) /\1### /gm;t' | sed 's/&/\\&/g')}"
781787
;;
782788
esac
783789
done
790+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
784791
else
785792
while [[ "${NOTES}" =~ %%(PULLREQUEST(\+[0-3])?)%% ]]; do
786793
NOTES="${NOTES//${BASH_REMATCH[0]}/}"
787794
done
795+
printf "${ANSI_LIGHT_YELLOW}[SKIPPED]${ANSI_NOCOLOR}\n"
788796
fi
789797
790798
# Inline Files table
799+
printf -- "Inline '__ASSETS__.md' ... "
791800
if [[ -s __ASSETS__.md ]]; then
792-
NOTES="${NOTES//%%ASSETS%%/$(<__ASSETS__.md)}"
801+
NOTES="${NOTES//%%ASSETS%%/$(cat __ASSETS__.md | sed 's/&/\\&/g')}"
802+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
793803
else
794804
NOTES="${NOTES//%%ASSETS%%/}"
805+
printf "${ANSI_LIGHT_YELLOW}[SKIPPED]${ANSI_NOCOLOR}\n"
795806
fi
796807
797808
# Inline Footer
809+
printf -- "Inline '__FOOTER__.md' ... "
798810
if [[ -s __FOOTER__.md ]]; then
799-
NOTES="${NOTES//%%FOOTER%%/$(<__FOOTER__.md)}"
811+
NOTES="${NOTES//%%FOOTER%%/$(cat __FOOTER__.md | sed 's/&/\\&/g')}"
812+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
800813
else
801814
NOTES="${NOTES//%%FOOTER%%/}"
815+
printf "${ANSI_LIGHT_YELLOW}[SKIPPED]${ANSI_NOCOLOR}\n"
802816
fi
803817
804818
# Apply replacements
819+
printf -- "Apply replacements ... "
805820
while IFS=$'\r\n' read -r patternLine; do
806821
# skip empty lines
807822
[[ "$patternLine" == "" ]] && continue
@@ -810,12 +825,14 @@ jobs:
810825
replacement="${patternLine#*=}"
811826
NOTES="${NOTES//$pattern/$replacement}"
812827
done <<<'${{ inputs.replacements }}'
828+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
813829
814830
# Workarounds for stupid GitHub variables
815831
owner_repo="${{ github.repository }}"
816832
repo=${owner_repo##*/}
817833
818834
# Replace special identifiers
835+
printf -- "Replace GitHub variables ... "
819836
NOTES="${NOTES//%%gh_server%%/${{ github.server_url }}}"
820837
NOTES="${NOTES//%%gh_workflow_name%%/${{ github.workflow }}}"
821838
NOTES="${NOTES//%%gh_owner%%/${{ github.repository_owner }}}"
@@ -828,9 +845,12 @@ jobs:
828845
NOTES="${NOTES//%%date%%/$(date '+%Y-%m-%d')}"
829846
NOTES="${NOTES//%%time%%/$(date '+%H:%M:%S %Z')}"
830847
NOTES="${NOTES//%%datetime%%/$(date '+%Y-%m-%d %H:%M:%S %Z')}"
848+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
831849
832850
# Write final release notes to file
851+
printf "Write final release note '__NOTES__.md' ... "
833852
printf "%s\n" "${NOTES}" > __NOTES__.md
853+
printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n"
834854
835855
# Display partial contents for debugging
836856
if [[ -s __DESCRIPTION__.md ]]; then

.github/workflows/UnitTesting.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ jobs:
235235
requirementsFile = Path(requirements)
236236
237237
if not requirementsFile.exists():
238-
print(f"::error title=FileNotFoundError::{requirementsFile}")
238+
print(f"::error title=FileNotFoundError::Requirements file '{requirementsFile}' doesn't exist.")
239239
exit(1)
240240
241241
print(f"requirements file: {requirementsFile.as_posix()}")

0 commit comments

Comments
 (0)