name: Prepare Variables on: workflow_call: inputs: ubuntu_image: description: 'Name of the Ubuntu image.' required: false default: 'ubuntu-24.04' type: string main_branch: description: 'Name of the branch containing releases.' required: false default: 'main' type: string development_branch: description: 'Name of the development branch containing features.' required: false default: 'dev' type: string release_branch: description: 'Name of the branch containing releases and nightly builds.' required: false default: 'main' type: string nightly_tag_pattern: description: 'Pattern for nightly tags on the release branch.' required: false default: 'nightly' type: string release_tag_pattern: description: 'Pattern for release tags on the release branch. Usually: vXX.YY.ZZ' required: false default: '(v|r)?[0-9]+(\.[0-9]+){0,2}(-(dev|alpha|beta|rc)([0-9]*))?' type: string outputs: on_default_branch: description: "" value: ${{ jobs.Prepare.outputs.on_default_branch }} on_main_branch: description: "" value: ${{ jobs.Prepare.outputs.on_main_branch }} on_release_branch: description: "" value: ${{ jobs.Prepare.outputs.on_release_branch }} on_dev_branch: description: "" value: ${{ jobs.Prepare.outputs.on_dev_branch }} is_regular_commit: description: "" value: ${{ jobs.Prepare.outputs.is_regular_commit }} is_merge_commit: description: "" value: ${{ jobs.Prepare.outputs.is_merge_commit }} is_release_commit: description: "" value: ${{ jobs.Prepare.outputs.is_release_commit }} is_nightly_tag: description: "" value: ${{ jobs.Prepare.outputs.is_nightly_tag }} is_release_tag: description: "" value: ${{ jobs.Prepare.outputs.is_release_tag }} has_submodules: description: "" value: ${{ jobs.Prepare.outputs.has_submodules }} ref_kind: description: "" value: ${{ jobs.Prepare.outputs.ref_kind }} default_branch: description: "" value: ${{ jobs.Prepare.outputs.default_branch }} branch: description: "" value: ${{ jobs.Prepare.outputs.branch }} tag: description: "" value: ${{ jobs.Prepare.outputs.tag }} version: description: "" value: ${{ jobs.Prepare.outputs.version }} pr_title: description: "" value: ${{ jobs.Prepare.outputs.pr_title }} pr_number: description: "" value: ${{ jobs.Prepare.outputs.pr_number }} # pr_mergedby: # description: "" # value: ${{ jobs.Prepare.outputs.pr_mergedby }} # pr_mergedat: # description: "" # value: ${{ jobs.Prepare.outputs.pr_mergedat }} git_submodule_count: description: "" value: ${{ jobs.Prepare.outputs.git_submodule_count }} git_submodule_names: description: "" value: ${{ jobs.Prepare.outputs.git_submodule_names }} git_submodule_paths: description: "" value: ${{ jobs.Prepare.outputs.git_submodule_paths }} jobs: Prepare: name: Extract Information runs-on: ubuntu-24.04 outputs: on_default_branch: ${{ steps.Classify.outputs.on_default_branch }} on_main_branch: ${{ steps.Classify.outputs.on_main_branch }} on_release_branch: ${{ steps.Classify.outputs.on_release_branch }} on_dev_branch: ${{ steps.Classify.outputs.on_dev_branch }} is_regular_commit: ${{ steps.Classify.outputs.is_regular_commit }} is_merge_commit: ${{ steps.Classify.outputs.is_merge_commit }} is_release_commit: ${{ steps.Classify.outputs.is_release_commit }} is_nightly_tag: ${{ steps.Classify.outputs.is_nightly_tag }} is_release_tag: ${{ steps.Classify.outputs.is_release_tag }} has_submodules: ${{ steps.Classify.outputs.has_submodules }} ref_kind: ${{ steps.Classify.outputs.ref_kind }} default_branch: ${{ steps.Classify.outputs.default_branch }} branch: ${{ steps.Classify.outputs.branch }} tag: ${{ steps.Classify.outputs.tag }} version: ${{ steps.Classify.outputs.version || steps.FindPullRequest.outputs.pr_version }} # release_version: ${{ steps.FindPullRequest.outputs.release_version }} pr_title: ${{ steps.FindPullRequest.outputs.pr_title }} pr_number: ${{ steps.Classify.outputs.pr_number || steps.FindPullRequest.outputs.pr_number }} git_submodule_count: ${{ steps.Classify.outputs.git_submodule_count }} git_submodule_names: ${{ steps.Classify.outputs.git_submodule_names }} git_submodule_paths: ${{ steps.Classify.outputs.git_submodule_paths }} steps: - name: ⏬ Checkout repository uses: actions/checkout@v6 with: # The command 'git describe' (used for version) needs the history. fetch-depth: 0 - name: 🖉 GitHub context information run: | printf "%s\n" "github.event_name: ${{ github.event_name }}" printf "%s\n" "github.actor: ${{ github.actor }}" printf "%s\n" "github.ref: ${{ github.ref }}" printf "%s\n" "github.base_ref: ${{ github.base_ref }}" printf "%s\n" "github.head_ref: ${{ github.head_ref }}" printf "%s\n" "github.sha: ${{ github.sha }}" - name: 🖉 Classify commit id: Classify run: | set +e ANSI_LIGHT_RED=$'\x1b[91m' ANSI_LIGHT_GREEN=$'\x1b[92m' ANSI_LIGHT_YELLOW=$'\x1b[93m' ANSI_LIGHT_BLUE=$'\x1b[94m' ANSI_NOCOLOR=$'\x1b[0m' export GH_TOKEN=${{ github.token }} ref="${{ github.ref }}" on_default_branch="false" on_main_branch="false" on_release_branch="false" on_dev_branch="false" is_regular_commit="false" is_merge_commit="false" is_release_commit="false" is_nightly_tag="false" is_release_tag="false" has_submodules="false" ref_kind="unknown" default_branch="" branch="" tag="" pr_number="" version="" git_submodule_count="0" git_submodule_names="" git_submodule_paths="" printf "Classify Git reference '%s' " "${ref}" if [[ "${ref:0:11}" == "refs/heads/" ]]; then printf "${ANSI_LIGHT_GREEN}[BRANCH]\n" ref_kind="branch" branch="${ref:11}" printf "Get default branch name ... " defaultBranch=$(gh repo view "${{ github.repository }}" --json defaultBranchRef --jq '.defaultBranchRef.name' 2>&1) if [[ $? -eq 0 ]]; then printf "${ANSI_LIGHT_GREEN} [OK]\n" default_branch="${defaultBranch}" printf " Default branch ${ANSI_LIGHT_BLUE}'%s'${ANSI_NOCOLOR}\n" "${default_branch}" else printf "${ANSI_LIGHT_RED} [FAILED]\n" printf " ${ANSI_LIGHT_RED}%s${ANSI_NOCOLOR}\n" "${default_branch}" fi printf "Commit checks:\n" printf " Commit: %s\n" "${{ github.sha }}" printf " Commit kind " if [[ -z "$(git rev-list -1 --merges ${{ github.sha }}~1..${{ github.sha }})" ]]; then is_regular_commit="true" printf "${ANSI_LIGHT_YELLOW}[REGULAR]${ANSI_NOCOLOR}\n" else is_merge_commit="true" printf "${ANSI_LIGHT_GREEN}[MERGE]${ANSI_NOCOLOR}\n" fi printf "Branch checks:\n" printf " Branch: %s\n" "${branch}" printf " Commit on default branch ${ANSI_LIGHT_BLUE}'%s'${ANSI_NOCOLOR} " "${defaultBranch}" if [[ "${branch}" == "${defaultBranch}" ]]; then on_default_branch="true" printf "${ANSI_LIGHT_GREEN}[YES]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[NO]${ANSI_NOCOLOR}\n" fi printf " Commit on main branch ${ANSI_LIGHT_BLUE}'%s'${ANSI_NOCOLOR} " "${{ inputs.main_branch }}" if [[ "${branch}" == "${{ inputs.main_branch }}" ]]; then on_main_branch="true" printf "${ANSI_LIGHT_GREEN}[YES]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[NO]${ANSI_NOCOLOR}\n" fi printf " Commit on release branch ${ANSI_LIGHT_BLUE}'%s'${ANSI_NOCOLOR} " "${{ inputs.release_branch }}" if [[ "${branch}" == "${{ inputs.release_branch }}" ]]; then on_release_branch="true" printf "${ANSI_LIGHT_GREEN}[YES]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[NO]${ANSI_NOCOLOR}\n" fi printf " Commit on development branch ${ANSI_LIGHT_BLUE}'%s'${ANSI_NOCOLOR} " "${{ inputs.development_branch }}" if [[ "${branch}" == "${{ inputs.development_branch }}" ]]; then on_dev_branch="true" printf "${ANSI_LIGHT_GREEN}[YES]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[NO]${ANSI_NOCOLOR}\n" fi if [[ "${is_merge_commit}" == "true" ]]; then printf "Release checks:\n" printf " Release kind " if [[ "${on_main_branch}" == "true" ]]; then is_release_commit="true" printf "${ANSI_LIGHT_GREEN}[RELEASE]${ANSI_NOCOLOR}\n" elif [[ "${on_version_branch}" == "true" ]]; then is_release_commit="true" printf "${ANSI_LIGHT_GREEN}[RELEASE]${ANSI_NOCOLOR}\n" elif [[ "${on_release_branch}" == "true" ]]; then is_prerelease_commit="true" printf "${ANSI_LIGHT_YELLOW}[PRERELEASE]${ANSI_NOCOLOR}\n" fi fi elif [[ "${ref:0:10}" == "refs/tags/" ]]; then printf "${ANSI_LIGHT_GREEN}[TAG]\n" ref_kind="tag" tag="${ref:10}" printf "Tag checks:\n" printf " Check if tag is on main branch '%s' ... " "${{ inputs.main_branch }}" git branch --remotes --contains $(git rev-parse --verify "tags/${tag}~0") | grep "origin/${{ inputs.main_branch }}" > /dev/null if [[ $? -eq 0 ]]; then printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n" printf "${ANSI_LIGHT_RED}Tag '%s' isn't on branch '%s'.${ANSI_NOCOLOR}\n" "${tag}" "${{ inputs.main_branch }}" printf "::error title=TagCheck::Tag '%s' isn't on branch '%s'.\n" "${tag}" "${{ inputs.main_branch }}" exit 1 fi NIGHTLY_TAG_PATTERN='^${{ inputs.nightly_tag_pattern }}$' RELEASE_TAG_PATTERN='^${{ inputs.release_tag_pattern }}$' printf "Tag checks:\n" printf " Tag: %s\n" "${tag}" printf " Check tag '%s' against regexp ... " "${tag}" if [[ "${tag}" =~ ${NIGHTLY_TAG_PATTERN} ]]; then printf "${ANSI_LIGHT_GREEN}[NIGHTLY]${ANSI_NOCOLOR}\n" is_nightly_tag="true" elif [[ "${tag}" =~ ${RELEASE_TAG_PATTERN} ]]; then printf "${ANSI_LIGHT_GREEN}[RELEASE]${ANSI_NOCOLOR}\n" version="${tag}" is_release_tag="true" else printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n" printf "${ANSI_LIGHT_RED}Tag name '%s' doesn't conform to regexp${ANSI_NOCOLOR}\n" "${tag}" printf " ${ANSI_LIGHT_RED}nightly tag: %s${ANSI_NOCOLOR}\n" "${NIGHTLY_TAG_PATTERN}" printf " ${ANSI_LIGHT_RED}release tag: %s${ANSI_NOCOLOR}\n" "${RELEASE_TAG_PATTERN}" printf "::error title=RexExpCheck::Tag name '%s' doesn't conform to regexp '%s' nor '%s'.\n" "${tag}" "${NIGHTLY_TAG_PATTERN}" "${RELEASE_TAG_PATTERN}" exit 1 fi if [[ "${is_nightly_tag}" == "true" ]]; then printf " Check if nightly tag is on main branch '%s' ... " "${{ inputs.main_branch }}" git branch --remotes --contains $(git rev-parse --verify "tags/${tag}~0") | grep "origin/${{ inputs.main_branch }}" > /dev/null if [[ $? -eq 0 ]]; then printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n" printf " ${ANSI_LIGHT_RED}Tag '%s' isn't on branch '%s'.${ANSI_NOCOLOR}\n" "${tag}" "${{ inputs.main_branch }}" printf "::error title=TagCheck::Tag '%s' isn't on branch '%s'.\n" "${tag}" "${{ inputs.main_branch }}" exit 1 fi elif [[ "${is_release_tag}" == "true" ]]; then printf " Check if release tag is on main branch '%s' ... " "${{ inputs.main_branch }}" git branch --remotes --contains $(git rev-parse --verify "tags/${tag}~0") | grep "origin/${{ inputs.main_branch }}" > /dev/null if [[ $? -eq 0 ]]; then printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n" else printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n" printf " ${ANSI_LIGHT_RED}Tag '%s' isn't on branch '%s'.${ANSI_NOCOLOR}\n" "${tag}" "${{ inputs.main_branch }}" printf "::error title=TagCheck::Tag '%s' isn't on branch '%s'.\n" "${tag}" "${{ inputs.main_branch }}" exit 1 fi fi elif [[ "${ref:0:10}" == "refs/pull/" ]]; then printf "${ANSI_LIGHT_YELLOW}[PULL REQUEST]\n" ref_kind="pullrequest" pr_number=${ref:11} pr_number=${pr_number%%/*} printf "Pull Request checks:\n" printf " Number: %s\n" "${pr_number}" else printf "${ANSI_LIGHT_RED}[UNKNOWN]\n" printf "${ANSI_LIGHT_RED}Unknown Git reference '%s'.${ANSI_NOCOLOR}\n" "${{ github.ref }}" printf "::error title=Classify Commit::Unknown Git reference '%s'.\n" "${{ github.ref }}" exit 1 fi # Submodules if [[ -f .gitsubmodules ]]; then has_submodules="true" git_modules_file=.gitmodules # $(git rev-parse --show-toplevel)/.gitmodules git_submodule_count="$(grep -Po '(?<=\[submodule \")(.*)(?=\"\])' "${git_modules_file}" | wc -l)" git_submodule_names="$(grep -Po '(?<=\[submodule \")(.*)(?=\"\])' "${git_modules_file}" | paste -sd ':' -)" git_submodule_paths="$(git config --file "${git_modules_file}" --null --name-only --get-regexp '\.path$' | xargs -0 -n1 git config --file "${git_modules_file}" --get | paste -sd ':' -)" fi printf "\nWriting output variables ...\n" tee --append "${GITHUB_OUTPUT}" < %s\n" "${{ github.ref }}^2" "${FATHER_SHA}" exit 1 else printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n" fi printf "Search Pull Request to '%s' and branch containing SHA %s ... " "${{ inputs.release_branch }}" "${FATHER_SHA}" PULL_REQUESTS=$(gh pr list --base "${{ inputs.release_branch }}" --search "${FATHER_SHA}" --state "merged" --json "title,number,mergedBy,mergedAt") if [[ $? -ne 0 || "${PULL_REQUESTS}" == "" ]]; then printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n" printf "${ANSI_LIGHT_RED}Couldn't find a merged Pull Request to '%s'. -> %s${ANSI_NOCOLOR}\n" "${{ inputs.release_branch }}" "${PULL_REQUESTS}" printf "::error title=PullRequest::Couldn't find a merged Pull Request to '%s'. -> %s\n" "${{ inputs.release_branch }}" "${PULL_REQUESTS}" exit 1 else printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n" PR_TITLE="$( printf "%s\n" "${PULL_REQUESTS}" | jq --raw-output ".[0].title")" PR_NUMBER="$( printf "%s\n" "${PULL_REQUESTS}" | jq --raw-output ".[0].number")" PR_MERGED_BY="$(printf "%s\n" "${PULL_REQUESTS}" | jq --raw-output ".[0].mergedBy.login")" PR_MERGED_AT="$(printf "%s\n" "${PULL_REQUESTS}" | jq --raw-output ".[0].mergedAt")" printf "${ANSI_LIGHT_BLUE}Found Pull Request:${ANSI_NOCOLOR}\n" printf " %s\n" "Title: ${PR_TITLE}" printf " %s\n" "Number: ${PR_NUMBER}" printf " %s\n" "MergedBy: ${PR_MERGED_BY}" printf " %s\n" "MergedAt: ${PR_MERGED_AT} ($(date -d"${PR_MERGED_AT}" '+%d.%m.%Y - %H:%M:%S'))" fi RELEASE_TAG_PATTERN='^${{ inputs.release_tag_pattern }}$' printf "Check Pull Request title against regexp '%s' ... " "${RELEASE_TAG_PATTERN}" if [[ "${PR_TITLE}" =~ $RELEASE_TAG_PATTERN ]]; then printf "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}\n" RELEASE_VERSION="${PR_TITLE}" else printf "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}\n" printf "${ANSI_LIGHT_RED}Pull Request title '%s' doesn't conform to regexp '%s'.${ANSI_NOCOLOR}\n" "${PR_TITLE}" "${RELEASE_TAG_PATTERN}" printf "::error title=RexExpCheck::Pull Request title '%s' doesn't conform to regexp '%s'.\n" "${PR_TITLE}" "${RELEASE_TAG_PATTERN}" exit 1 fi printf "Release tag: ${ANSI_LIGHT_GREEN}%s${ANSI_NOCOLOR}\n" "${RELEASE_VERSION}" tee --append "${GITHUB_OUTPUT}" <