Skip to content

Commit 5603948

Browse files
Merge pull request #4 from pyTooling/dev
v1.0.0
2 parents 8542632 + 54c1aa6 commit 5603948

16 files changed

Lines changed: 1582 additions & 7 deletions

File tree

‎.editorconfig‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
# end_of_line = lf
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
indent_style = tab
9+
indent_size = 2
10+
tab_width = 2
11+
12+
[*.{yml,yaml}]
13+
indent_style = space
14+
indent_size = 2
15+
16+
[*.md]
17+
trim_trailing_whitespace = false

‎.github/CODEOWNERS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
* @Paebbels
2+
3+
/.github/ @Paebbels
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright © 2026 The pyTooling Authors
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6+
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
7+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8+
# persons to whom the Software is furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11+
# Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17+
name: Check-Outputs
18+
description: Check the output parameters of the 'SynchronizeForks' action against their expected values.
19+
inputs:
20+
synchronized:
21+
description: Actual number of synchronized branches.
22+
type: string
23+
required: true
24+
created:
25+
description: Actual number of created branches.
26+
type: string
27+
required: true
28+
created-tags:
29+
description: Actual number of created tags.
30+
type: string
31+
required: true
32+
skipped:
33+
description: Actual number of skipped entries.
34+
type: string
35+
required: true
36+
errors:
37+
description: Actual number of errors.
38+
type: string
39+
required: true
40+
expected-synchronized:
41+
description: Expected number of synchronized branches.
42+
type: string
43+
required: true
44+
expected-created:
45+
description: Expected number of created branches.
46+
type: string
47+
required: true
48+
expected-created-tags:
49+
description: Expected number of created tags.
50+
type: string
51+
required: true
52+
expected-skipped:
53+
description: Expected number of skipped entries.
54+
type: string
55+
required: true
56+
expected-errors:
57+
description: Expected number of errors.
58+
type: string
59+
required: true
60+
61+
runs:
62+
using: composite
63+
steps:
64+
- name: 📋 Verify output parameters
65+
shell: bash
66+
env:
67+
SYNCHRONIZED: ${{ inputs.synchronized }}
68+
CREATED: ${{ inputs.created }}
69+
CREATED_TAGS: ${{ inputs.created-tags }}
70+
SKIPPED: ${{ inputs.skipped }}
71+
ERRORS: ${{ inputs.errors }}
72+
EXPECTED_SYNCHRONIZED: ${{ inputs.expected-synchronized }}
73+
EXPECTED_CREATED: ${{ inputs.expected-created }}
74+
EXPECTED_CREATED_TAGS: ${{ inputs.expected-created-tags }}
75+
EXPECTED_SKIPPED: ${{ inputs.expected-skipped }}
76+
EXPECTED_ERRORS: ${{ inputs.expected-errors }}
77+
run: |
78+
# 📋 Verify output parameters
79+
set +e
80+
81+
ANSI_LIGHT_RED=$'\x1b[91m'
82+
ANSI_LIGHT_GREEN=$'\x1b[92m'
83+
ANSI_NOCOLOR=$'\x1b[0m'
84+
85+
errors=0
86+
checkOutput() {
87+
local name="${1}" actual="${2}" expected="${3}"
88+
89+
printf "%s" "Checking output parameter '${name}' ... "
90+
if [[ "${actual}" == "${expected}" ]]; then
91+
printf "%s\n" "${ANSI_LIGHT_GREEN}[PASSED]${ANSI_NOCOLOR} (${actual})"
92+
else
93+
printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR} (expected '${expected}', got '${actual}')"
94+
printf "::error title=%s::%s\n" "check-outputs" "Output parameter '${name}' is '${actual}', but '${expected}' was expected."
95+
errors=$((errors + 1))
96+
fi
97+
}
98+
99+
checkOutput "synchronized" "${SYNCHRONIZED}" "${EXPECTED_SYNCHRONIZED}"
100+
checkOutput "created" "${CREATED}" "${EXPECTED_CREATED}"
101+
checkOutput "created-tags" "${CREATED_TAGS}" "${EXPECTED_CREATED_TAGS}"
102+
checkOutput "skipped" "${SKIPPED}" "${EXPECTED_SKIPPED}"
103+
checkOutput "errors" "${ERRORS}" "${EXPECTED_ERRORS}"
104+
105+
printf "%s\n" ""
106+
if [[ ${errors} -ne 0 ]]; then
107+
printf "%s\n" "${ANSI_LIGHT_RED}Counted ${errors} errors.${ANSI_NOCOLOR}"
108+
exit 1
109+
else
110+
printf "%s\n" "${ANSI_LIGHT_GREEN}No errors found.${ANSI_NOCOLOR}"
111+
fi

‎.github/dependabot.yml‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
version: 2
2+
updates:
3+
# Maintain GitHub Action runners
4+
- package-ecosystem: "github-actions"
5+
directory: "/"
6+
target-branch: dev
7+
commit-message:
8+
prefix: "[Dependabot]"
9+
labels:
10+
- Dependencies
11+
assignees:
12+
- Paebbels
13+
schedule:
14+
interval: "daily" # Checks on Monday trough Friday.

‎.github/pull_request_template.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# New Features
2+
3+
* tbd
4+
* tbd
5+
6+
# Changes
7+
8+
* tbd
9+
* tbd
10+
11+
# Bug Fixes
12+
13+
* tbd
14+
* tbd
15+
16+
# Documentation
17+
18+
* tbd
19+
* tbd
20+
21+
# Unit Tests
22+
23+
* tbd
24+
* tbd
25+
26+
----------
27+
# Related Issues and Pull-Requests
28+
29+
* tbd
30+
* tbd

‎.github/workflows/Pipeline.yml‎

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright © 2026 The pyTooling Authors
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6+
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
7+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8+
# persons to whom the Software is furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11+
# Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17+
name: Pipeline
18+
run-name: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
19+
20+
on:
21+
push:
22+
# 'TagReleaseCommit' dispatches this workflow on the tag it created; a tag pushed by the automatic GITHUB_TOKEN
23+
# doesn't trigger a workflow on its own.
24+
workflow_dispatch:
25+
26+
jobs:
27+
Prepare:
28+
uses: pyTooling/Actions/.github/workflows/PrepareJob.yml@r8
29+
30+
DryRun:
31+
name: 🐧 Dry-run with a valid configuration
32+
runs-on: ubuntu-26.04
33+
34+
steps:
35+
- name: ⏬ Checkout repository to use the local action
36+
uses: actions/checkout@v7
37+
38+
- name: 🔄 Synchronize forked repositories
39+
id: synchronize
40+
uses: ./
41+
with:
42+
github-token: ${{ github.token }}
43+
target-organisation: Paebbels
44+
directory: tests/Valid
45+
dry-run: true
46+
47+
- name: 📋 Verify output parameters
48+
uses: ./.github/actions/check-outputs
49+
with:
50+
synchronized: ${{ steps.synchronize.outputs.synchronized }}
51+
created: ${{ steps.synchronize.outputs.created }}
52+
created-tags: ${{ steps.synchronize.outputs.created-tags }}
53+
skipped: ${{ steps.synchronize.outputs.skipped }}
54+
errors: ${{ steps.synchronize.outputs.errors }}
55+
# 1 branch of 'ghdl' + 1 branch of 'progit2' + 2 branches of 'itertree'
56+
expected-synchronized: 4
57+
# 1 commented out organisation + 1 commented out repository
58+
# Dry-run reads no repository, so no branch is created.
59+
expected-created: 0
60+
# Dry-run reads no repository, so no tag is created.
61+
expected-created-tags: 0
62+
expected-skipped: 2
63+
expected-errors: 0
64+
65+
ErrorHandling:
66+
name: 🐧 Error handling with an invalid configuration
67+
runs-on: ubuntu-26.04
68+
69+
steps:
70+
- name: ⏬ Checkout repository to use the local action
71+
uses: actions/checkout@v7
72+
73+
- name: 🔄 Synchronize forked repositories
74+
id: synchronize
75+
uses: ./
76+
with:
77+
github-token: ${{ github.token }}
78+
target-organisation: Paebbels
79+
directory: tests/Invalid
80+
dry-run: true
81+
fail-on-error: false
82+
83+
- name: 📋 Verify output parameters
84+
uses: ./.github/actions/check-outputs
85+
with:
86+
synchronized: ${{ steps.synchronize.outputs.synchronized }}
87+
created: ${{ steps.synchronize.outputs.created }}
88+
created-tags: ${{ steps.synchronize.outputs.created-tags }}
89+
skipped: ${{ steps.synchronize.outputs.skipped }}
90+
errors: ${{ steps.synchronize.outputs.errors }}
91+
expected-synchronized: 1
92+
expected-created: 0
93+
expected-created-tags: 0
94+
expected-skipped: 0
95+
# 1 missing 'Missing.repos' + 4 malformed lines in 'ghdl.repos'
96+
expected-errors: 5
97+
98+
FailOnError:
99+
name: 🐧 Counted errors let the action fail
100+
runs-on: ubuntu-26.04
101+
102+
steps:
103+
- name: ⏬ Checkout repository to use the local action
104+
uses: actions/checkout@v7
105+
106+
- name: 🔄 Synchronize forked repositories
107+
id: synchronize
108+
continue-on-error: true
109+
uses: ./
110+
with:
111+
github-token: ${{ github.token }}
112+
target-organisation: Paebbels
113+
directory: tests/Invalid
114+
dry-run: true
115+
116+
- name: 📋 Verify the action failed
117+
shell: bash
118+
env:
119+
OUTCOME: ${{ steps.synchronize.outcome }}
120+
run: |
121+
# 📋 Verify the action failed
122+
set +e
123+
124+
ANSI_LIGHT_RED=$'\x1b[91m'
125+
ANSI_LIGHT_GREEN=$'\x1b[92m'
126+
ANSI_NOCOLOR=$'\x1b[0m'
127+
128+
printf "%s" "Checking the action's outcome ... "
129+
if [[ "${OUTCOME}" == "failure" ]]; then
130+
printf "%s\n" "${ANSI_LIGHT_GREEN}[PASSED]${ANSI_NOCOLOR} (failure)"
131+
else
132+
printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR} (expected 'failure', got '${OUTCOME}')"
133+
printf "::error title=%s::%s\n" "FailOnError" "The action's outcome is '${OUTCOME}', but 'failure' was expected."
134+
exit 1
135+
fi
136+
137+
# A merge commit on 'main' is a release: tag it with the release pull-request's title and start this pipeline again
138+
# on that tag.
139+
TriggerTaggedRelease:
140+
uses: pyTooling/Actions/.github/workflows/TagReleaseCommit.yml@r8
141+
needs:
142+
- Prepare
143+
- DryRun
144+
- ErrorHandling
145+
- FailOnError
146+
if: needs.Prepare.outputs.is_release_commit == 'true'
147+
permissions:
148+
contents: write # required to create the tag
149+
actions: write # required to start the tagged pipeline
150+
with:
151+
version: ${{ needs.Prepare.outputs.version }}
152+
auto_tag: ${{ needs.Prepare.outputs.is_release_commit }}
153+
secrets: inherit
154+
155+
# In parallel to the release page: propose the version branch update, so consumers pinning '@v1' can be moved to
156+
# this release by merging one pull-request. The workflow is local for now; once it has proven itself here it can be
157+
# promoted to pyTooling/Actions.
158+
UpdateVersionBranch:
159+
uses: ./.github/workflows/UpdateVersionBranch.yml
160+
needs:
161+
- Prepare
162+
- DryRun
163+
- ErrorHandling
164+
- FailOnError
165+
if: needs.Prepare.outputs.is_release_tag == 'true'
166+
permissions:
167+
contents: write # required to create a version branch
168+
pull-requests: write # required to open the pull-request
169+
with:
170+
version: ${{ needs.Prepare.outputs.version }}
171+
prefix: 'v'
172+
173+
# The tagged run publishes the release page. Its description is the body of the pull-request that produced the
174+
# tagged merge commit, which 'PublishReleaseNotes' looks up itself.
175+
ReleasePage:
176+
uses: pyTooling/Actions/.github/workflows/PublishReleaseNotes.yml@r8
177+
needs:
178+
- Prepare
179+
- DryRun
180+
- ErrorHandling
181+
- FailOnError
182+
if: needs.Prepare.outputs.is_release_tag == 'true'
183+
with:
184+
tag: ${{ needs.Prepare.outputs.version }}
185+
secrets: inherit

0 commit comments

Comments
 (0)