├── .editorconfig ├── .github ├── CODEOWNERS ├── actions │ ├── automate-dependabot │ │ └── action.yml │ ├── automate-propagation │ │ └── action.yml │ ├── calculate-next-internal-version │ │ ├── action.yml │ │ └── next-prerelease.sh │ ├── configure-git-author │ │ └── action.yml │ ├── dbp-charts │ │ ├── kubernetes-valid-ns │ │ │ └── action.yml │ │ ├── publish-chart │ │ │ ├── action.yml │ │ │ └── publish_chart.sh │ │ ├── verify-compose │ │ │ ├── action.yml │ │ │ └── docker_compose.sh │ │ └── verify-helm │ │ │ ├── action.yml │ │ │ ├── helm_delete.sh │ │ │ └── helm_install.sh │ ├── dispatch-resume-workflow │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── .nvmrc │ │ ├── LICENSE │ │ ├── README.md │ │ ├── action.yml │ │ ├── dist │ │ │ └── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── debug.ts │ │ │ ├── main.ts │ │ │ ├── utils.ts │ │ │ ├── workflow-handler.ts │ │ │ └── workflow-logs-handler.ts │ │ └── tsconfig.json │ ├── docker-build-image │ │ └── action.yml │ ├── docker-dump-containers-logs │ │ └── action.yml │ ├── docker-scan-image-dirs │ │ └── action.yml │ ├── enforce-pr-conventions │ │ └── action.yml │ ├── env-load-from-yaml │ │ └── action.yml │ ├── free-hosted-runner-disk-space │ │ └── action.yml │ ├── get-branch-name │ │ ├── action.yml │ │ ├── get-branch-name.sh │ │ └── tests │ │ │ └── get-branch-name.bats │ ├── get-build-info │ │ └── action.yml │ ├── get-commit-message │ │ └── action.yml │ ├── gh-cache-cleanup-on-merge │ │ └── action.yml │ ├── git-check-existing-tag │ │ └── action.yml │ ├── git-commit-changes │ │ └── action.yml │ ├── git-latest-tag │ │ ├── action.yml │ │ ├── git-latest-tag.sh │ │ └── tests │ │ │ └── git-latest-tag.bats │ ├── github-check-upcoming-runs │ │ └── action.yml │ ├── github-deployment-create │ │ └── action.yml │ ├── github-deployment-status-update │ │ └── action.yml │ ├── github-deployments-delete │ │ ├── action.yml │ │ └── deleteDeploymentScript.js │ ├── github-download-file │ │ └── action.yml │ ├── github-https-auth │ │ └── action.yml │ ├── github-list-changes │ │ ├── action.yml │ │ └── github-list-changes.sh │ ├── github-pr-check-metadata │ │ └── action.yml │ ├── helm-build-chart │ │ └── action.yml │ ├── helm-integration-tests │ │ └── action.yml │ ├── helm-package-chart │ │ └── action.yml │ ├── helm-parse-next-release │ │ └── action.yml │ ├── helm-plugin │ │ └── action.yml │ ├── helm-publish-chart │ │ └── action.yml │ ├── helm-release-and-publish │ │ └── action.yml │ ├── helm-template-yamllint │ │ ├── .yamllint.yml │ │ └── action.yml │ ├── helm-update-chart-version │ │ └── action.yml │ ├── install-galaxy-deps │ │ └── action.yml │ ├── install-ubuntu-default-tools │ │ └── action.yml │ ├── jx-updatebot-pr │ │ └── action.yml │ ├── kubectl-keep-nslogs │ │ └── action.yml │ ├── kubectl-wait │ │ └── action.yml │ ├── load-release-descriptor │ │ └── action.yml │ ├── maven-build-and-tag │ │ └── action.yml │ ├── maven-build │ │ └── action.yml │ ├── maven-configure │ │ └── action.yml │ ├── maven-dependency-scan │ │ └── action.yml │ ├── maven-deploy-file │ │ ├── action.yml │ │ └── settings.xml │ ├── maven-release │ │ ├── action.yml │ │ └── update-pom-version.sh │ ├── maven-tag │ │ └── action.yml │ ├── maven-update-pom-version │ │ └── action.yml │ ├── md-toc │ │ └── action.yml │ ├── nexus-move-artifacts │ │ └── action.yml │ ├── pipenv │ │ ├── action.yml │ │ └── requirements.txt │ ├── pre-commit │ │ └── action.yml │ ├── process-coverage-report │ │ └── action.yml │ ├── rancher │ │ ├── action.yml │ │ ├── rancher_api.py │ │ └── requirements.txt │ ├── release-notes-aggregator │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── .nvmrc │ │ ├── README.md │ │ ├── action.yml │ │ ├── dist │ │ │ └── index.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ │ ├── debug.ts │ │ │ ├── main.ts │ │ │ ├── utils.ts │ │ │ └── workflow-handler.ts │ │ └── tsconfig.json │ ├── reportportal-prepare │ │ ├── action.yml │ │ ├── get-rp-input.sh │ │ └── tests │ │ │ └── reportportal-prepare.bats │ ├── reportportal-summarize │ │ ├── action.yml │ │ ├── get-rp-output.sh │ │ ├── get-slack-message.sh │ │ ├── get-teams-message.sh │ │ ├── tests │ │ │ ├── empty-launch.json │ │ │ ├── get-rp-output.bats │ │ │ ├── get-slack-message.bats │ │ │ ├── get-teams-message.bats │ │ │ ├── sample-launch.json │ │ │ ├── sample-launches.json │ │ │ └── write-step-summary.bats │ │ └── write-step-summary.sh │ ├── resolve-preview-name │ │ ├── action.yml │ │ └── resolve-preview-name.sh │ ├── send-slack-notification-slow-job │ │ └── action.yml │ ├── send-slack-notification │ │ ├── action.yml │ │ ├── compute-message.sh │ │ └── tests │ │ │ ├── sample-commit-message.txt │ │ │ ├── sample-long-message-cut.txt │ │ │ ├── sample-long-message.txt │ │ │ └── send-slack-notification.bats │ ├── send-teams-notification │ │ ├── action.yml │ │ ├── compute-message.sh │ │ ├── tests │ │ │ ├── sample-commit-message.txt │ │ │ ├── sample-long-message-cut.txt │ │ │ ├── sample-long-message.txt │ │ │ ├── sample-needs.json │ │ │ └── send-teams-notification.bats │ │ └── transform-mentions.sh │ ├── setup-docker │ │ └── action.yml │ ├── setup-github-release-binary │ │ └── action.yml │ ├── setup-helm-docs │ │ └── action.yml │ ├── setup-java-build │ │ ├── action.yml │ │ └── settings.xml │ ├── setup-jx-release-version │ │ └── action.yml │ ├── setup-kcadm │ │ └── action.yml │ ├── setup-kind │ │ ├── action.yml │ │ └── kind.yml │ ├── setup-kubepug │ │ ├── action.yml │ │ └── setup-kubepug.sh │ ├── setup-pysemver │ │ └── action.yml │ ├── setup-rancher-cli │ │ └── action.yml │ ├── setup-terraform-docs │ │ └── action.yml │ ├── setup-updatebot │ │ └── action.yml │ ├── setup-updatecli │ │ └── action.yml │ ├── slack-file-upload │ │ ├── action.yml │ │ ├── requirements.txt │ │ └── slack_file_upload.py │ ├── sonar-scan-on-built-project │ │ └── action.yml │ ├── sonar-scanner │ │ └── action.yml │ ├── update-deployment-runtime-versions │ │ └── action.yml │ ├── update-pom-to-next-pre-release │ │ └── action.yml │ ├── update-project-base-tag │ │ └── action.yml │ ├── validate-maven-versions │ │ └── action.yml │ └── veracode │ │ ├── action.yml │ │ └── source_clear.sh ├── dependabot.template.yml ├── dependabot.yml ├── pull_request_template.md ├── tests │ ├── actions │ │ └── test-setup-helm-docs │ │ │ └── action.yml │ └── env-load-from-yaml │ │ └── env.yml └── workflows │ ├── build-and-release-maven.yml │ ├── helm-publish-new-package-version.yml │ ├── publish-artifacts-for-veracode.yml │ ├── release.yml │ ├── terraform.yml │ ├── test-with-bats.yml │ ├── test.yml │ └── updatecli.yml ├── .gitignore ├── .markdownlint.yml ├── .pre-commit-config.yaml ├── .pre-commit-hooks.yaml ├── .updatecli ├── templates │ └── github_releases.yaml └── values │ └── github_releases │ ├── helm_docs.yaml │ ├── kcadm.yaml │ ├── rancher_cli.yaml │ ├── terraform_docs.yaml │ └── updatecli.yaml ├── LICENSE ├── check_readme.sh ├── docs ├── README.md ├── images │ ├── rp-gh-summary.png │ ├── rp-sample.png │ ├── send-slack-custom-message.png │ ├── send-slack-pr.png │ ├── send-slack-push.png │ ├── send-teams-get-tag-id.png │ ├── send-teams-pr-success.png │ ├── send-teams-push-failure.png │ └── send-teams-push-success.png ├── pre-commit-hooks.md └── security.md ├── release.sh ├── update-dependabot.sh └── version.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.java] 13 | indent_size = 4 14 | 15 | [*.md] 16 | max_line_length = off 17 | trim_trailing_whitespace = false 18 | 19 | [Makefile] 20 | indent_style = tab 21 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See https://github.com/orgs/Alfresco/teams/alfresco-build-tools-maintainers 2 | * @Alfresco/alfresco-build-tools-maintainers 3 | -------------------------------------------------------------------------------- /.github/actions/automate-dependabot/action.yml: -------------------------------------------------------------------------------- 1 | name: Automate dependabot pulls requests management 2 | description: 'Auto-approve dependabot PRs minor and patch versions, and auto-merge patch versions' 3 | inputs: 4 | token: 5 | description: > 6 | Token used to enable auto-merge and auto-approve. 7 | This token CANNOT be the default `GITHUB_TOKEN` on auto-merge action, 8 | otherwise the merge of the PR will not trigger a build. 9 | required: true 10 | merge-option: 11 | description: 'Merge option' 12 | required: false 13 | default: '--squash' 14 | 15 | runs: 16 | using: composite 17 | steps: 18 | - name: Check is dependabot 19 | id: check 20 | env: 21 | EVENT_NAME: ${{ github.event_name }} 22 | PR_LOGIN: ${{ github.event.pull_request.user.login }} 23 | shell: bash 24 | run: | 25 | if [[ $EVENT_NAME == 'pull_request' && $PR_LOGIN == 'dependabot[bot]' ]] 26 | then 27 | echo "continue=true" >> $GITHUB_OUTPUT 28 | else 29 | echo "continue=false" >> $GITHUB_OUTPUT 30 | fi 31 | 32 | - name: Dependabot metadata 33 | if: steps.check.outputs.continue == 'true' 34 | id: metadata 35 | uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b # v2.4.0 36 | with: 37 | github-token: "${{ inputs.token }}" 38 | 39 | - name: Enable auto-merge for minor and patch Dependabot PRs 40 | if: steps.check.outputs.continue == 'true' && (steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch') 41 | env: 42 | PR_URL: ${{ github.event.pull_request.html_url }} 43 | GITHUB_TOKEN: ${{ inputs.token }} 44 | shell: bash 45 | run: gh pr merge --auto ${{ inputs.merge-option }} "$PR_URL" 46 | 47 | - name: Auto-approve patch Dependabot PRs 48 | if: steps.check.outputs.continue == 'true' && steps.metadata.outputs.update-type == 'version-update:semver-patch' 49 | env: 50 | PR_URL: ${{ github.event.pull_request.html_url }} 51 | GITHUB_TOKEN: ${{ inputs.token }} 52 | shell: bash 53 | run: gh pr review --approve "$PR_URL" 54 | -------------------------------------------------------------------------------- /.github/actions/automate-propagation/action.yml: -------------------------------------------------------------------------------- 1 | name: Automate version propagation pulls requests management 2 | description: 'Auto-approve and auto-merge version propagation PRs.' 3 | inputs: 4 | auto-merge-token: 5 | description: > 6 | Token used to enable auto-merge. 7 | This token CANNOT be the default `GITHUB_TOKEN`, otherwise the merge of the PR will not trigger a build. 8 | required: true 9 | approval-token: 10 | description: > 11 | Token used to approve. 12 | This token CANNOT be the `BOT_GITHUB_TOKEN` secret, because it's linked to alfresco-build user (who created the PR). 13 | The default `GITHUB_TOKEN` can be used in this case. 14 | required: true 15 | merge-option: 16 | description: 'Merge option' 17 | required: false 18 | default: '--squash' 19 | 20 | runs: 21 | using: composite 22 | steps: 23 | - name: Check is propagation PR 24 | id: check 25 | env: 26 | LABEL: ${{ github.event.label.name }} 27 | PR_LOGIN: ${{ github.event.pull_request.user.login }} 28 | shell: bash 29 | run: | 30 | if [[ $LABEL == 'updatebot' && $PR_LOGIN == 'alfresco-build' ]] 31 | then 32 | echo "continue=true" >> $GITHUB_OUTPUT 33 | else 34 | echo "continue=false" >> $GITHUB_OUTPUT 35 | fi 36 | 37 | - name: Enable auto-merge for propagation Pull Request 38 | if: steps.check.outputs.continue == 'true' 39 | env: 40 | PR_URL: ${{ github.event.pull_request.html_url }} 41 | GITHUB_TOKEN: ${{ inputs.auto-merge-token }} 42 | shell: bash 43 | run: gh pr merge --auto ${{ inputs.merge-option }} "$PR_URL" 44 | 45 | - name: Auto-approve propagation Pull Request 46 | if: steps.check.outputs.continue == 'true' 47 | env: 48 | PR_URL: ${{ github.event.pull_request.html_url }} 49 | GITHUB_TOKEN: ${{ inputs.approval-token }} 50 | shell: bash 51 | run: gh pr review --approve "$PR_URL" 52 | -------------------------------------------------------------------------------- /.github/actions/calculate-next-internal-version/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Calculate next internal version' 2 | description: 'Calculate next internal version based on existing tags' 3 | inputs: 4 | next-version: 5 | description: 'Next version following the pattern MAJOR.MINOR.PATCH' 6 | required: true 7 | prerelease-type: 8 | description: The type of the prerelease, i.e. `alpha`, `beta`, `rc` 9 | required: false 10 | default: alpha 11 | repository-directory: 12 | description: "Path to the directory holding the git repository" 13 | required: false 14 | 15 | outputs: 16 | next-prerelease: 17 | description: "Next prerelease" 18 | value: ${{ steps.next-prerelease-resolver.outputs.next-prerelease }} 19 | runs: 20 | using: "composite" 21 | steps: 22 | - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 23 | - uses: Alfresco/alfresco-build-tools/.github/actions/setup-pysemver@v8.23.2 24 | - id: next-prerelease-resolver 25 | run: ${{ github.action_path }}/next-prerelease.sh 26 | shell: bash 27 | env: 28 | NEXT_VERSION: ${{ inputs.next-version }} 29 | PRERELEASE_TYPE: ${{ inputs.prerelease-type }} 30 | REPO_DIR: ${{inputs.repository-directory}} 31 | -------------------------------------------------------------------------------- /.github/actions/calculate-next-internal-version/next-prerelease.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | if [ -n "$REPO_DIR" ] 5 | then 6 | cd "$REPO_DIR" 7 | fi 8 | 9 | echo "Fetching tags ... " 10 | git fetch --tags 11 | 12 | FIRST_PRERELEASE_SUFFIX="-${PRERELEASE_TYPE}.1" 13 | 14 | echo "Next version: $NEXT_VERSION" 15 | LATEST_PRERELEASE="$(git tag --sort=-creatordate | grep -m 1 "^$NEXT_VERSION\-$PRERELEASE_TYPE\.[[:digit:]]\{1,4\}$" | cat)" 16 | if [ -n "$LATEST_PRERELEASE" ]; then 17 | echo "Latest prerelease version found: $LATEST_PRERELEASE" 18 | NEXT_PRERELEASE="$(pysemver bump prerelease "$LATEST_PRERELEASE")" 19 | else 20 | echo "No prerelease found for version $NEXT_VERSION yet" 21 | NEXT_PRERELEASE="$NEXT_VERSION$FIRST_PRERELEASE_SUFFIX" 22 | fi 23 | echo "Next prerelease: $NEXT_PRERELEASE" 24 | echo "next-prerelease=$NEXT_PRERELEASE" >> $GITHUB_OUTPUT 25 | -------------------------------------------------------------------------------- /.github/actions/configure-git-author/action.yml: -------------------------------------------------------------------------------- 1 | name: "configure-git-author" 2 | description: "Configure the git identity" 3 | inputs: 4 | username: 5 | description: "Git username" 6 | required: true 7 | email: 8 | description: "Email" 9 | required: true 10 | global: 11 | description: "Global scope" 12 | required: false 13 | default: 'false' 14 | runs: 15 | using: "composite" 16 | steps: 17 | - shell: bash 18 | run: | 19 | GIT_GLOBAL_OPTION='' 20 | if [ ${{ inputs.global }} = true ] ; then 21 | GIT_GLOBAL_OPTION='--global' 22 | fi 23 | git config $GIT_GLOBAL_OPTION user.name ${{ inputs.username }} 24 | git config $GIT_GLOBAL_OPTION user.email ${{ inputs.email }} 25 | -------------------------------------------------------------------------------- /.github/actions/dbp-charts/kubernetes-valid-ns/action.yml: -------------------------------------------------------------------------------- 1 | name: kubernetes valid namespace 2 | description: | 3 | Generate a sanitized namespace name for kubernetes to use based on the release 4 | name, ap version and some other parameters 5 | inputs: 6 | branch_name: 7 | description: name of the git branch we're executing from 8 | required: true 9 | release_prefix: 10 | description: a release prefix to differentiate from other releases 11 | required: true 12 | outputs: 13 | namespace: 14 | description: generated namespace 15 | value: ${{ steps.genns.outputs.namespace }} 16 | runs: 17 | using: composite 18 | steps: 19 | - name: generate namespace 20 | id: genns 21 | shell: bash 22 | env: 23 | BRANCH_NAME: ${{ inputs.branch_name }} 24 | RELEASE_PREFIX: ${{ inputs.release_prefix }} 25 | run: | 26 | BRANCH_PREFIX="${BRANCH_NAME:0:28}" 27 | BRANCH_NS="${BRANCH_PREFIX//[^[:alnum:]]/-}" 28 | RELEASE_NS=$"${RELEASE_PREFIX//[^[:alnum:]]/-}" 29 | NS_SUFFIX=${GITHUB_RUN_NUMBER:-0} 30 | echo namespace="${BRANCH_NS,,}"-"${RELEASE_NS,,}"-"${NS_SUFFIX}" >> $GITHUB_OUTPUT 31 | -------------------------------------------------------------------------------- /.github/actions/dbp-charts/publish-chart/action.yml: -------------------------------------------------------------------------------- 1 | name: "Publish helm chart on GitHub " 2 | description: "Publish new version of an helm chart to the Alfresco repo" 3 | inputs: 4 | github_token: 5 | description: "GitHub token" 6 | required: true 7 | github_username: 8 | description: "git config username" 9 | required: true 10 | github_email: 11 | description: "git config email" 12 | required: true 13 | chart_name: 14 | description: "full name of helm chart directory" 15 | required: true 16 | alpha_suffix: 17 | description: "suffix that if found in the version would publish it on incubator repo" 18 | required: false 19 | default: "SNAPSHOT" 20 | 21 | runs: 22 | using: composite 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 26 | with: 27 | fetch-depth: 0 28 | - name: Get branch name 29 | uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@v8.23.2 30 | - name: Publish 31 | run: ${{ github.action_path }}/publish_chart.sh 32 | shell: bash 33 | env: 34 | GH_TOKEN: ${{ inputs.github_token }} 35 | GH_USERNAME: ${{ inputs.github_username }} 36 | GH_EMAIL: ${{ inputs.github_email }} 37 | PROJECT_NAME: ${{ inputs.chart_name }} 38 | ALPHA_SUFFIX: ${{ inputs.alpha_suffix }} 39 | -------------------------------------------------------------------------------- /.github/actions/dbp-charts/publish-chart/publish_chart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | HELM_REPO_BASE_URL="https://kubernetes-charts.alfresco.com" 3 | CHART_VERSION=$(yq eval .version helm/"${PROJECT_NAME}"/Chart.yaml) 4 | 5 | if [[ "$CHART_VERSION" == *"$ALPHA_SUFFIX"* ]]; then 6 | export HELM_REPO=incubator 7 | else 8 | export HELM_REPO=stable 9 | fi 10 | 11 | COMMIT_MESSAGE="Publishing ${PROJECT_NAME} v${CHART_VERSION} on ${HELM_REPO} repo" 12 | echo "$COMMIT_MESSAGE" 13 | echo '---' 14 | 15 | git config --global user.name "${GH_USERNAME}" 16 | git config --global user.email "${GH_EMAIL}" 17 | git clone https://"${GH_TOKEN}"@github.com/Alfresco/charts.git 18 | echo using PROJECT_NAME="${PROJECT_NAME}",HELM_REPO="${HELM_REPO}" 19 | mkdir repo 20 | helm package --dependency-update --destination repo helm/"${PROJECT_NAME}" 21 | helm repo index repo --url "${HELM_REPO_BASE_URL}"/"${HELM_REPO}" --merge charts/"${HELM_REPO}"/index.yaml 22 | mv repo/* charts/"${HELM_REPO}" 23 | cd charts 24 | git add "${HELM_REPO}" 25 | git commit -m "$COMMIT_MESSAGE" 26 | git push --quiet origin master 27 | -------------------------------------------------------------------------------- /.github/actions/dbp-charts/verify-compose/action.yml: -------------------------------------------------------------------------------- 1 | name: "Verify and test docker compose" 2 | description: "Setup environment and run docker compose tests" 3 | inputs: 4 | compose_file_path: 5 | description: "full path to docker compose file to test" 6 | required: false 7 | default: "./docker-compose.yml" 8 | compose_pull: 9 | description: "run docker-compose pull before tests" 10 | required: false 11 | default: "true" 12 | postman_path: 13 | description: "path to postman collection" 14 | required: false 15 | default: "test/postman/docker-compose" 16 | postman_json: 17 | description: "postman collection json file" 18 | required: false 19 | default: "acs-test-docker-compose-collection.json" 20 | docker_username: 21 | description: "username for Docker Hub" 22 | required: false 23 | docker_password: 24 | description: "password for Docker Hub" 25 | required: false 26 | quay_username: 27 | description: "username for Quay.io" 28 | required: false 29 | quay_password: 30 | description: "password for Quay.io" 31 | required: false 32 | 33 | runs: 34 | using: composite 35 | steps: 36 | - if: ${{ inputs.quay_username != '' && inputs.quay_password != '' }} 37 | name: Login to Quay.io 38 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 39 | with: 40 | registry: quay.io 41 | username: ${{ inputs.quay_username }} 42 | password: ${{ inputs.quay_password }} 43 | - if: ${{ inputs.docker_username != '' && inputs.docker_password != '' }} 44 | name: Login to Docker Hub 45 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 46 | with: 47 | username: ${{ inputs.docker_username }} 48 | password: ${{ inputs.docker_password }} 49 | - name: Run Docker Compose tests 50 | run: ${{ github.action_path }}/docker_compose.sh 51 | shell: bash 52 | env: 53 | COMPOSE_FILE_PATH: ${{ inputs.compose_file_path }} 54 | COMPOSE_PULL: ${{ inputs.compose_pull }} 55 | POSTMAN_PATH: ${{ inputs.postman_path }} 56 | POSTMAN_JSON: ${{ inputs.postman_json }} 57 | -------------------------------------------------------------------------------- /.github/actions/dbp-charts/verify-compose/docker_compose.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | COMPOSE_BIN="docker compose" 4 | 5 | echo "Starting Alfresco in docker compose" 6 | $COMPOSE_BIN -f "${COMPOSE_FILE_PATH}" ps 7 | if [ "$COMPOSE_PULL" = "true" ]; then 8 | $COMPOSE_BIN -f "${COMPOSE_FILE_PATH}" pull --quiet 9 | fi 10 | export COMPOSE_HTTP_TIMEOUT=120 11 | $COMPOSE_BIN -f "${COMPOSE_FILE_PATH}" up -d --quiet-pull --wait 12 | 13 | echo "All services are up and running... starting postman tests" 14 | 15 | docker run -a STDOUT --volume "$(realpath "${POSTMAN_PATH}"):/etc/newman" --network host postman/newman:5.3 run "${POSTMAN_JSON}" --global-var "protocol=http" --global-var "url=localhost:8080" 16 | -------------------------------------------------------------------------------- /.github/actions/dbp-charts/verify-helm/helm_delete.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash +e 2 | 3 | out_of_ns_ingress_cleanup() { 4 | echo "Something went wrong uninstalling ingress release... Need to do some cleanup" 5 | for i in clusterrole clusterrolebindings; do kubectl delete "$i" "ing-${RELEASE_PREFIX}-${GITHUB_RUN_NUMBER}-ingress-nginx" 6 | done 7 | } 8 | 9 | echo "cleaning up releases" 10 | helm delete "ing-${RELEASE_PREFIX}-${GITHUB_RUN_NUMBER}" -n "${K8SNS}" || out_of_ns_ingress_cleanup 11 | helm delete "${RELEASE_PREFIX}-${GITHUB_RUN_NUMBER}" -n "${K8SNS}" 12 | kubectl delete secret quay-registry-secret -n "${K8SNS}" 13 | kubectl delete namespace "${K8SNS}" --grace-period=1 14 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true 4 | }, 5 | extends: [ 6 | 'eslint:recommended', 7 | 'plugin:@typescript-eslint/eslint-recommended', 8 | 'plugin:@typescript-eslint/recommended' 9 | ], 10 | parser: '@typescript-eslint/parser', 11 | parserOptions: { 12 | 'project': 'tsconfig.json', 13 | 'sourceType': 'module' 14 | }, 15 | plugins: [ 16 | '@typescript-eslint' 17 | ], 18 | rules: { 19 | 'no-trailing-spaces': 'error', 20 | 'no-console': 'off', 21 | 22 | '@typescript-eslint/semi': ['error', 'never'], 23 | '@typescript-eslint/indent': ['error', 2], 24 | '@typescript-eslint/member-delimiter-style': 'off', 25 | '@typescript-eslint/no-explicit-any': 'warn', 26 | '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': 'next|res|req' }], 27 | 28 | 'func-call-spacing': 'off', 29 | '@typescript-eslint/func-call-spacing': 'error', 30 | 31 | 'quotes': 'off', 32 | '@typescript-eslint/quotes': ['error', 'single'], 33 | 34 | 'comma-spacing': 'off', 35 | '@typescript-eslint/comma-spacing': ['error'] 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | .idea 4 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Ben Coleman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Workflow Dispatch and wait' 2 | description: 'Trigger and chain GitHub Actions workflows with workflow_dispatch events and wait for result' 3 | 4 | inputs: 5 | workflow: 6 | description: 'Name or ID of workflow to run' 7 | required: true 8 | token: 9 | description: 'GitHub token with repo write access, can NOT use secrets.GITHUB_TOKEN, see readme' 10 | required: true 11 | inputs: 12 | description: 'Inputs to pass to the workflow, must be a JSON string. All values must be strings (even if used as boolean or number)' 13 | required: false 14 | ref: 15 | description: 'The reference of the workflow run. The reference can be a branch, tag, or a commit SHA' 16 | required: false 17 | repo: 18 | description: 'Repo owner & name, slash separated, only set if invoking a workflow in a different repo' 19 | required: false 20 | run-name: 21 | description: 'If specified will select the run ID based on the run name' 22 | required: false 23 | run-id: 24 | description: 'If specified will select the run ID on existing workflow' 25 | required: false 26 | display-workflow-run-url: 27 | description: 'Get the URL of the triggered workflow and display it in logs (useful to follow the progress of the triggered workflow)' 28 | required: false 29 | default: 'true' 30 | display-workflow-run-url-interval: 31 | description: 'The time to wait (+unit) between two polls to get the URL of the workflow run' 32 | required: false 33 | default: 1m 34 | display-workflow-run-url-timeout: 35 | description: 'Maximum amount of time (+unit) to wait for the URL of the workflow run. If the timeout is reached, it is just ignored' 36 | required: false 37 | default: 10m 38 | wait-for-completion: 39 | description: 'Block until the triggered workflow has finished' 40 | required: false 41 | default: 'true' 42 | wait-for-completion-timeout: 43 | description: 'Maximum amount of time (+unit) to wait to mark workflow as timed out' 44 | required: false 45 | default: 1h 46 | wait-for-completion-interval: 47 | description: 'Time to wait (+unit) between two polls to get run status' 48 | required: false 49 | default: 1m 50 | workflow-logs: 51 | description: >- 52 | Indicate what to do with logs of the triggered workflow. 53 | `ignore` do not retrieve logs from tiggered workflow. 54 | `print` retrieves logs from triggered workflow and print in the workflow that triggered the other workflow. 55 | `output` retrieves logs from triggered workflow and set them as `workflow-logs` output. 56 | `json-output` retrieves logs from triggered workflow and return a json array groupped by job name. 57 | required: false 58 | default: ignore 59 | 60 | outputs: 61 | workflow-conclusion: 62 | description: 'Conclusion of the triggered workflow' 63 | workflow-id: 64 | description: 'ID of the triggered workflow' 65 | workflow-url: 66 | description: 'URL of the triggered workflow' 67 | workflow-logs: 68 | description: | 69 | Logs of the triggered workflow. Based on `inputs.workflow-logs`, format is set to: 70 | - `output`: Multiline logs formatted as: ' | ' 71 | - `json-output`: JSON logs formatted as: '{"": [{"": ""}]' 72 | 73 | runs: 74 | using: 'node20' 75 | main: 'dist/index.js' 76 | 77 | branding: 78 | color: purple 79 | icon: send 80 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workflow-dispatch-and-wait", 3 | "version": "4.0.0", 4 | "description": "Trigger running GitHub Actions workflows and wait for result", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "ncc build src/main.ts -o dist", 8 | "lint": "eslint src/", 9 | "lint-fix": "eslint src/ --fix" 10 | }, 11 | "keywords": [ 12 | "github", 13 | "actions", 14 | "worflow", 15 | "trigger" 16 | ], 17 | "author": "Aurélien Baudet", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@actions/core": "1.10.1", 21 | "@actions/github": "6.0.0", 22 | "@typescript-eslint/eslint-plugin": "7.7.0", 23 | "@typescript-eslint/parser": "7.7.0", 24 | "@vercel/ncc": "0.38.1", 25 | "eslint": "8.57.0", 26 | "typescript": "5.4.5" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/src/debug.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | 3 | export function debug(title: string, content: any) { 4 | if (core.isDebug()) { 5 | core.info(`::group::${title}`) 6 | try { 7 | core.debug(JSON.stringify(content, null, 3)) 8 | } catch(e) { 9 | core.debug(`Failed to serialize object, trying toString. Cause: ${e}`) 10 | core.debug(content?.toString()) 11 | } 12 | core.info('::endgroup::') 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import * as github from '@actions/github' 3 | 4 | enum TimeUnit { 5 | S = 1000, 6 | M = 60 * 1000, 7 | H = 60 * 60 * 1000 8 | } 9 | 10 | function toMilliseconds(timeWithUnit: string): number { 11 | const unitStr = timeWithUnit.substring(timeWithUnit.length-1) 12 | const unit = TimeUnit[unitStr.toUpperCase() as keyof typeof TimeUnit] 13 | if (!unit) { 14 | throw new Error('Unknown time unit '+unitStr) 15 | } 16 | const time = parseFloat(timeWithUnit) 17 | return time * unit 18 | } 19 | 20 | function parse(inputsJson: string) { 21 | if(inputsJson) { 22 | try { 23 | return JSON.parse(inputsJson) 24 | } catch(e) { 25 | throw new Error(`Failed to parse 'inputs' parameter. Must be a valid JSON.\nCause: ${e}`) 26 | } 27 | } 28 | return {} 29 | } 30 | export function getArgs() { 31 | // Required inputs 32 | const token = core.getInput('token') 33 | const workflowRef = core.getInput('workflow') 34 | // Optional inputs, with defaults 35 | const ref = core.getInput('ref') || github.context.ref 36 | const [owner, repo] = core.getInput('repo') 37 | ? core.getInput('repo').split('/') 38 | : [github.context.repo.owner, github.context.repo.repo] 39 | 40 | // Decode inputs, this MUST be a valid JSON string 41 | const inputs = parse(core.getInput('inputs')) 42 | 43 | const displayWorkflowUrlStr = core.getInput('display-workflow-run-url') 44 | const displayWorkflowUrl = displayWorkflowUrlStr && displayWorkflowUrlStr === 'true' 45 | const displayWorkflowUrlTimeout = toMilliseconds(core.getInput('display-workflow-run-url-timeout')) 46 | const displayWorkflowUrlInterval = toMilliseconds(core.getInput('display-workflow-run-url-interval')) 47 | 48 | const waitForCompletionStr = core.getInput('wait-for-completion') 49 | const waitForCompletion = waitForCompletionStr && waitForCompletionStr === 'true' 50 | const waitForCompletionTimeout = toMilliseconds(core.getInput('wait-for-completion-timeout')) 51 | const checkStatusInterval = toMilliseconds(core.getInput('wait-for-completion-interval')) 52 | const runName = core.getInput('run-name') 53 | const runId = core.getInput('run-id') 54 | const workflowLogMode = core.getInput('workflow-logs') 55 | 56 | return { 57 | token, 58 | workflowRef, 59 | ref, 60 | owner, 61 | repo, 62 | inputs, 63 | displayWorkflowUrl, 64 | displayWorkflowUrlTimeout, 65 | displayWorkflowUrlInterval, 66 | checkStatusInterval, 67 | waitForCompletion, 68 | waitForCompletionTimeout, 69 | runName, 70 | runId, 71 | workflowLogMode 72 | } 73 | } 74 | 75 | export function sleep(ms: number) { 76 | return new Promise(resolve => setTimeout(resolve, ms)) 77 | } 78 | 79 | export function isTimedOut(start: number, waitForCompletionTimeout: number) { 80 | return Date.now() > start + waitForCompletionTimeout 81 | } 82 | 83 | export function formatDuration(duration: number) { 84 | const durationSeconds = duration / 1000 85 | const hours = Math.floor(durationSeconds / 3600) 86 | const minutes = Math.floor((durationSeconds - (hours * 3600)) / 60) 87 | const seconds = durationSeconds - (hours * 3600) - (minutes * 60) 88 | 89 | let hoursStr = hours + '' 90 | let minutesStr = minutes + '' 91 | let secondsStr = seconds + '' 92 | 93 | if (hours < 10) {hoursStr = '0'+hoursStr} 94 | if (minutes < 10) {minutesStr = '0'+minutesStr} 95 | if (seconds < 10) {secondsStr = '0'+secondsStr} 96 | return hoursStr+'h '+minutesStr+'m '+secondsStr+'s' 97 | } 98 | -------------------------------------------------------------------------------- /.github/actions/dispatch-resume-workflow/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "rootDir": "./src", 6 | "strict": true, 7 | "noImplicitAny": true, 8 | "esModuleInterop": true 9 | }, 10 | "exclude": ["node_modules", "**/*.test.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /.github/actions/docker-dump-containers-logs/action.yml: -------------------------------------------------------------------------------- 1 | name: "Docker dump containers logs" 2 | description: "Persists Docker containers logs" 3 | inputs: 4 | output-archive-name: 5 | description: the desired output archive name 6 | default: "containers-logs.tar.gz" 7 | required: false 8 | runs: 9 | using: composite 10 | steps: 11 | - name: "Dump containers logs and archive them" 12 | shell: bash 13 | run: | 14 | # Get containers state 15 | docker ps -a 16 | # Dump all containers logs to files 17 | docker ps -a --format '{{.ID}} {{.Names}}' | while read -r id name ; do 18 | docker logs "${id}" --tail 5000 > "${name}.log" 19 | done 20 | # Create archive with log files 21 | tar -zcf logs.tar.gz *.log 22 | # Specify output artefact name 23 | if [ "${{ inputs.output-archive-name }}" = "containers-logs.tar.gz" ]; then 24 | echo "artefactName=containers-logs-${{ github.job }}-${{ github.run_attempt }}-$(date +%Y%m%d%H%M%S).tar.gz" >> $GITHUB_ENV 25 | else 26 | echo "artefactName=${{ inputs.output-archive-name }}" >> $GITHUB_ENV 27 | fi 28 | - name: "Upload archive containing all *.log files" 29 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 30 | with: 31 | path: logs.tar.gz 32 | name: ${{ env.artefactName }} 33 | -------------------------------------------------------------------------------- /.github/actions/docker-scan-image-dirs/action.yml: -------------------------------------------------------------------------------- 1 | name: Scan docker image directories 2 | description: Scan the directories Dockerfile 3 | inputs: 4 | base-directory: 5 | description: base directory to be scanned 6 | required: false 7 | default: . 8 | name-shortener-pattern: 9 | description: >- 10 | Pattern to be removed from the directory name while generating the the field `short-name`. This is useful to remove a common prefix from the name. 11 | For instance, if the directory path is `./some/path/to/my/docker-image/images-my-service` and the pattern is `images-`, the resulting 12 | `short-name` will be `my-service`. In the case where no pattern is provided, the short name will be the same as the directory name, i.e. `images-my-service`. 13 | required: false 14 | default: "" 15 | outputs: 16 | image-dirs-as-json: 17 | description: list of directories containing Dockerfile formatted as JSON 18 | value: ${{ steps.scan-image-dirs.outputs.image-dirs-as-json }} 19 | image-dirs-with-metadata: 20 | description: >- 21 | JSON containing the list of all directories containing Dockerfile including metadata. i.e. path to the directory, 22 | whether the docker docker image should be skipped or not and shortened name of the directly (useful for display 23 | names in the CI for instance). 24 | This includes directories with `docker.skip=true` 25 | value: ${{ steps.scan-image-dirs.outputs.image-dirs-with-metadata }} 26 | runs: 27 | using: composite 28 | steps: 29 | - id: scan-image-dirs 30 | name: Scan Image Dirs 31 | shell: bash 32 | working-directory: ${{ inputs.base-directory }} 33 | env: 34 | NAME_SHORTENER_PATTERN: ${{ inputs.name-shortener-pattern }} 35 | run: | 36 | IMAGE_DIRS=$(find . -type f -mindepth 2 -name Dockerfile | grep -v target | xargs -I% dirname % | xargs || echo "") 37 | echo "image dirs IMAGE_DIRS=$IMAGE_DIRS" 38 | 39 | FILTERED_IMAGE_DIRS=() 40 | IMAGE_DIRS_WITH_METADATA="[]" 41 | for IMAGE_DIR in $IMAGE_DIRS; do 42 | export IMAGE_DIR 43 | echo checking $IMAGE_DIR 44 | 45 | SKIP_DOCKER=$(yq '.project.properties.["docker.skip"] // "false"' "$IMAGE_DIR/pom.xml") 46 | export SKIP_DOCKER 47 | 48 | if [ "$SKIP_DOCKER" = "false" ]; then 49 | echo add $IMAGE_DIR 50 | FILTERED_IMAGE_DIRS+=($IMAGE_DIR) 51 | fi 52 | 53 | IMAGE_DIRS_WITH_METADATA=$(echo $IMAGE_DIRS_WITH_METADATA | yq -o json -I=0 \ 54 | '. + {"path" : env(IMAGE_DIR), "skip-docker" : env(SKIP_DOCKER), "short-name" : env(IMAGE_DIR) | sub(".*\/", "")}' ) 55 | 56 | done 57 | 58 | if [ "$NAME_SHORTENER_PATTERN" != "" ]; then 59 | IMAGE_DIRS_WITH_METADATA=$(echo $IMAGE_DIRS_WITH_METADATA | yq -o json -I=0 \ 60 | '. | map(.["short-name"] |= sub(env(NAME_SHORTENER_PATTERN), ""))') 61 | fi 62 | 63 | echo "filtered image dirs FILTERED_IMAGE_DIRS=${FILTERED_IMAGE_DIRS[@]}" 64 | IMAGE_DIRS_AS_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${FILTERED_IMAGE_DIRS[@]}") 65 | echo "generated image dirs matrix IMAGE_DIRS_AS_JSON=$IMAGE_DIRS_AS_JSON" 66 | echo "image-dirs-as-json=$IMAGE_DIRS_AS_JSON" >> $GITHUB_OUTPUT 67 | 68 | echo "Generated dirs matrix with metadata:" 69 | echo "$IMAGE_DIRS_WITH_METADATA" | yq -o=json 70 | echo "image-dirs-with-metadata=$IMAGE_DIRS_WITH_METADATA" >> $GITHUB_OUTPUT 71 | -------------------------------------------------------------------------------- /.github/actions/env-load-from-yaml/action.yml: -------------------------------------------------------------------------------- 1 | name: "env-load-from-yaml" 2 | description: "Load environment variables from a yaml file" 3 | inputs: 4 | ignore_regex: 5 | description: "Bash regex to ignore certain lines" 6 | required: false 7 | default: ^$ 8 | yml_path: 9 | description: "Path to the yaml file to parse" 10 | required: true 11 | runs: 12 | using: "composite" 13 | steps: 14 | - name: Parse env global 15 | run: | 16 | while read ENVVAR; do 17 | if [[ "$ENVVAR" =~ ${{ inputs.ignore_regex }} ]]; then 18 | echo "Skipping unwanted $ENVVAR" 19 | continue 20 | fi 21 | eval $ENVVAR 22 | echo "$(eval echo $ENVVAR)" >> $GITHUB_ENV 23 | done < <(yq '.env.global[]' ${{ inputs.yml_path }}) 24 | shell: bash 25 | -------------------------------------------------------------------------------- /.github/actions/get-branch-name/action.yml: -------------------------------------------------------------------------------- 1 | name: "Get branch name" 2 | description: "Get branch name from GitHub and load it as a variable to the runner env" 3 | inputs: 4 | sanitize: 5 | description: sanitize branch name and avoid anything that isn't letters, numbers, dash 6 | default: "false" 7 | required: false 8 | max-length: 9 | description: ensure that the final branch name is no longer than specified characters 10 | default: "0" 11 | required: false 12 | runs: 13 | using: composite 14 | steps: 15 | - name: Get branch name 16 | run: ${{ github.action_path }}/get-branch-name.sh 17 | env: 18 | SANITIZE: ${{ inputs.sanitize }} 19 | MAX_LENGTH: ${{ inputs.max-length }} 20 | shell: bash 21 | -------------------------------------------------------------------------------- /.github/actions/get-branch-name/get-branch-name.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | BRANCH_NAME=${GITHUB_HEAD_REF:-$GITHUB_REF_NAME} 3 | if [ "$SANITIZE" = "true" ]; then 4 | BRANCH_NAME=$(echo "$BRANCH_NAME" | tr -d "." | tr "/" "-" | tr "[:upper:]" "[:lower:]") 5 | fi 6 | if [ "$MAX_LENGTH" -gt "0" ]; then 7 | BRANCH_NAME="${BRANCH_NAME:0:$MAX_LENGTH}" 8 | # shellcheck disable=SC2001 9 | BRANCH_NAME=$(echo "$BRANCH_NAME" | sed 's/-$//') 10 | fi 11 | 12 | echo "Branch name is '$BRANCH_NAME'" 13 | echo "BRANCH_NAME=$BRANCH_NAME" >> "$GITHUB_ENV" 14 | -------------------------------------------------------------------------------- /.github/actions/get-branch-name/tests/get-branch-name.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | # Runs everywhere 3 | DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 4 | PATH="$DIR/..:$PATH" 5 | 6 | # Mock GitHub Actions default variables 7 | export GITHUB_ENV=/dev/null 8 | export GITHUB_HEAD_REF="OPSEXP-1234" 9 | 10 | # Mock get-branch-name defaults 11 | export MAX_LENGTH="0" 12 | export SANITIZE="false" 13 | } 14 | 15 | @test "basic" { 16 | run get-branch-name.sh 17 | 18 | [ "$status" -eq 0 ] 19 | [ "$output" = "Branch name is 'OPSEXP-1234'" ] 20 | } 21 | 22 | @test "sanitize" { 23 | export SANITIZE="true" 24 | 25 | run get-branch-name.sh 26 | 27 | [ "$status" -eq 0 ] 28 | [ "$output" = "Branch name is 'opsexp-1234'" ] 29 | } 30 | 31 | @test "max-length" { 32 | export MAX_LENGTH="6" 33 | 34 | run get-branch-name.sh 35 | 36 | [ "$status" -eq 0 ] 37 | [ "$output" = "Branch name is 'OPSEXP'" ] 38 | } 39 | 40 | @test "max-length and trailing dash" { 41 | export MAX_LENGTH="7" 42 | 43 | run get-branch-name.sh 44 | 45 | [ "$status" -eq 0 ] 46 | [ "$output" = "Branch name is 'OPSEXP'" ] 47 | } 48 | 49 | @test "max-length and not trailing dash" { 50 | export MAX_LENGTH="9" 51 | 52 | run get-branch-name.sh 53 | 54 | [ "$status" -eq 0 ] 55 | [ "$output" = "Branch name is 'OPSEXP-12'" ] 56 | } 57 | -------------------------------------------------------------------------------- /.github/actions/get-build-info/action.yml: -------------------------------------------------------------------------------- 1 | name: "Get build info" 2 | description: "Get build-related info from GitHub and load it as generically named variables into the runner env" 3 | runs: 4 | using: composite 5 | steps: 6 | - uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@v8.23.2 7 | - name: "Get build info" 8 | run: | 9 | [[ $GITHUB_EVENT_NAME == "pull_request" ]] && IS_PULL_REQUEST="true" || IS_PULL_REQUEST="false" 10 | echo "PULL_REQUEST=$IS_PULL_REQUEST" >> "$GITHUB_ENV" 11 | echo "BUILD_NUMBER=$GITHUB_RUN_NUMBER" >> "$GITHUB_ENV" 12 | echo "ATTEMPT_NUMBER=$GITHUB_RUN_ATTEMPT" >> "$GITHUB_ENV" 13 | echo "JOB_NAME=$GITHUB_JOB" >> "$GITHUB_ENV" 14 | 15 | echo "Pull Request: '$IS_PULL_REQUEST'" 16 | echo "Build Number: '$GITHUB_RUN_NUMBER'" 17 | echo "Attempt Number: '$GITHUB_RUN_ATTEMPT'" 18 | echo "Job Name: '$GITHUB_JOB'" 19 | shell: bash 20 | -------------------------------------------------------------------------------- /.github/actions/get-commit-message/action.yml: -------------------------------------------------------------------------------- 1 | name: "Get commit message" 2 | description: "Get commit message from GitHub and load it as a variable to the runner env" 3 | runs: 4 | using: composite 5 | steps: 6 | - name: Get commit msg 7 | run: | 8 | MSG=$(git log --format=%B -n 1 ${{github.event.after}}) 9 | echo COMMIT_MESSAGE=\"$MSG\" >> $GITHUB_ENV 10 | shell: bash 11 | -------------------------------------------------------------------------------- /.github/actions/gh-cache-cleanup-on-merge/action.yml: -------------------------------------------------------------------------------- 1 | name: "GH cache cleanup" 2 | description: "Performs the cleanup of cache entries related with already closed PR" 3 | inputs: 4 | token: 5 | description: The GH token 6 | required: true 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Cache cleanup 11 | shell: bash 12 | run: | 13 | gh extension install actions/gh-actions-cache 14 | echo "Fetching and deleting all cache keys..." 15 | 16 | while : 17 | do 18 | cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1) 19 | if [ -z "$cacheKeysForPR" ]; then 20 | echo "No more caches to delete." 21 | break 22 | fi 23 | 24 | ## Setting this to not fail the workflow while deleting cache keys. 25 | set +e 26 | echo "Deleting caches..." 27 | for cacheKey in $cacheKeysForPR 28 | do 29 | gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm 30 | done 31 | done 32 | echo "Done" 33 | env: 34 | GH_TOKEN: ${{ inputs.token }} 35 | REPO: ${{ github.repository }} 36 | BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge 37 | -------------------------------------------------------------------------------- /.github/actions/git-check-existing-tag/action.yml: -------------------------------------------------------------------------------- 1 | name: Check existing tag 2 | description: Check if a tag with the given name already exists for this remote repository 3 | inputs: 4 | tag: 5 | description: The name of the tag to be checked 6 | required: true 7 | repository-directory: 8 | description: Optional path to the the directory holding the git repository (defaults to current directory) 9 | required: false 10 | 11 | outputs: 12 | exists: 13 | description: Flag containing the result of the check ("true" if exists; "false" otherwise) 14 | value: ${{ steps.check-tag.outputs.tag-exists }} 15 | 16 | runs: 17 | using: composite 18 | steps: 19 | - name: Check existing tag 20 | id: check-tag 21 | shell: bash 22 | env: 23 | TAG: ${{ inputs.tag }} 24 | REPO_DIR: ${{inputs.repository-directory}} 25 | run: | 26 | if [ -n "$REPO_DIR" ] 27 | then 28 | cd $REPO_DIR 29 | fi 30 | if git ls-remote --exit-code --tags origin "$TAG" 31 | then 32 | echo "Tag $TAG exists already" 33 | echo "tag-exists=true" >> $GITHUB_OUTPUT 34 | else 35 | echo "Tag $TAG does not exist" 36 | echo "tag-exists=false" >> $GITHUB_OUTPUT 37 | fi 38 | -------------------------------------------------------------------------------- /.github/actions/git-commit-changes/action.yml: -------------------------------------------------------------------------------- 1 | name: "Commit changes" 2 | description: "Commit current changes" 3 | inputs: 4 | username: 5 | description: "The username to be set as global user" 6 | required: true 7 | add-options: 8 | description: "Options to be added to `git add`" 9 | required: true 10 | commit-message: 11 | description: "The commit message to be used while committing" 12 | required: true 13 | repository-directory: 14 | description: "Path to the the directory holding the git repository" 15 | required: false 16 | commit-options: 17 | description: "Additional Git commit command options" 18 | required: false 19 | default: '' 20 | skip-if-no-changes: 21 | description: "Skips the actual commit when no changes are staged" 22 | required: false 23 | default: 'false' 24 | runs: 25 | using: composite 26 | steps: 27 | - name: Commit stagged changes 28 | shell: bash 29 | run: | 30 | REPO_DIR="${{inputs.repository-directory}}" 31 | if [ -n "$REPO_DIR" ] 32 | then 33 | cd $REPO_DIR 34 | fi 35 | git config --global user.name ${{ inputs.username }} 36 | git config --global user.email ${{ inputs.username }}@users.noreply.github.com 37 | git add ${{ inputs.add-options }} 38 | git status 39 | git --no-pager diff --cached 40 | if ${{ inputs.skip-if-no-changes == 'true' }} ; 41 | then 42 | git diff-index --quiet HEAD || git commit -m "${{ inputs.commit-message }}" ${{ inputs.commit-options }} 43 | else 44 | git commit -m "${{ inputs.commit-message }}" ${{ inputs.commit-options }} 45 | fi 46 | -------------------------------------------------------------------------------- /.github/actions/git-latest-tag/action.yml: -------------------------------------------------------------------------------- 1 | name: Get latest tag for pattern 2 | description: Get the latest tag for the given pattern 3 | inputs: 4 | pattern: 5 | description: > 6 | The pattern used to filter the tags: any expression supported by `git tag --list "expression"` 7 | required: false 8 | default: '*' 9 | repository-directory: 10 | description: Optional path to the the directory holding the git repository (defaults to current directory) 11 | required: false 12 | outputs: 13 | tag: 14 | description: the latest tag found for the pattern provided as input 15 | value: ${{steps.latest-tag.outputs.tag}} 16 | tag_long_sha: 17 | description: the latest tag long sha found for the pattern provided as input 18 | value: ${{steps.latest-tag.outputs.tag_long_sha}} 19 | runs: 20 | using: composite 21 | steps: 22 | - name: get latest tag 23 | id: latest-tag 24 | shell: bash 25 | env: 26 | PATTERN: ${{ inputs.pattern }} 27 | REPO_DIR: ${{ inputs.repository-directory }} 28 | run: ${{ github.action_path }}/git-latest-tag.sh 29 | -------------------------------------------------------------------------------- /.github/actions/git-latest-tag/git-latest-tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$REPO_DIR" ]; then 4 | cd "$REPO_DIR" 5 | fi 6 | git fetch --tags 7 | TAG=$(git tag --list "$PATTERN" --sort=-creatordate | head -n 1) 8 | TAG_LONG_SHA=$(git rev-list -n 1 $TAG) 9 | echo "Tag for the pattern $PATTERN is $TAG ($TAG_LONG_SHA)" 10 | echo "tag=$TAG" >> "$GITHUB_OUTPUT" 11 | echo "tag_long_sha=$TAG_LONG_SHA" >> "$GITHUB_OUTPUT" 12 | -------------------------------------------------------------------------------- /.github/actions/git-latest-tag/tests/git-latest-tag.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | git fetch --tags 3 | 4 | # Runs everywhere 5 | DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 6 | PATH="$DIR/..:$PATH" 7 | 8 | # Mock GitHub Actions default variables 9 | export GITHUB_ENV=/dev/null 10 | export GITHUB_HEAD_REF="AAE-11760-get-latest-tag-sha" 11 | 12 | # Mock git-latest-tag defaults 13 | export PATTERN="*" 14 | export REPO_DIR="$PWD" 15 | } 16 | 17 | @test "latest_tag" { 18 | regex="v[0-9]+\.[0-9]+\.[0-9]+" 19 | run git-latest-tag.sh 20 | [ "$status" -eq 0 ] 21 | if [[ ! $output =~ $regex ]]; then 22 | echo "Output does not match regex: $regex" 23 | exit 1 24 | fi 25 | } 26 | 27 | @test "tag_v1.0.0" { 28 | export PATTERN="v1.0.0" 29 | tag="v1.0.0" 30 | tag_sha="93891a5cfd55868bdfbd145ed8016ea8c63e37be" 31 | run git-latest-tag.sh 32 | 33 | [ "$status" -eq 0 ] 34 | [ "$output" = "Tag for the pattern $PATTERN is $tag ($tag_sha)" ] 35 | } 36 | -------------------------------------------------------------------------------- /.github/actions/github-check-upcoming-runs/action.yml: -------------------------------------------------------------------------------- 1 | name: Fail if an upcoming run is detected 2 | description: Exits on error when an upcoming run is detected on the same branch, and rerun it if cancelled 3 | inputs: 4 | github-token: 5 | description: GitHub Token 6 | required: true 7 | workflow: 8 | description: The workflow file name eg workflow.yml 9 | required: true 10 | event: 11 | description: The event to filter runs on 12 | default: pull_request 13 | 14 | outputs: 15 | exit: 16 | description: True if this check produced an exit 17 | value: ${{ steps.check.outputs.exit }} 18 | 19 | runs: 20 | using: "composite" 21 | steps: 22 | - name: Get branch name 23 | uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@v8.23.2 24 | 25 | - name: Check upcoming runs 26 | id: check 27 | env: 28 | GH_TOKEN: ${{ inputs.github-token }} 29 | WORKFLOW: ${{ inputs.workflow }} 30 | EVENT: ${{ inputs.event }} 31 | shell: bash 32 | run: | 33 | URL="/repos/$GITHUB_REPOSITORY/actions/workflows/$WORKFLOW/runs" 34 | echo "Checking runs at $URL for $BRANCH_NAME" 35 | RUNS=$(gh api -X GET $URL -F branch=$BRANCH_NAME -F event=$EVENT) 36 | 37 | RUN=$(echo $RUNS | jq --argjson id $GITHUB_RUN_ID 'first(.workflow_runs[] | select(.id > $id) | {"id":.id, "status":.status, "conclusion":.conclusion})') 38 | if [ ! -z "$RUN" ]; then 39 | 40 | echo "Current run id: $GITHUB_RUN_ID" 41 | echo "Upcoming runs:" 42 | echo $RUNS | jq --argjson id $GITHUB_RUN_ID '.workflow_runs[] | select(.id > $id) | {"id":.id, "status":.status, "conclusion":.conclusion}' 43 | 44 | ID=$(echo $RUN | jq -r ".id") 45 | STATUS=$(echo $RUN | jq -r ".status") 46 | CONCLUSION=$(echo $RUN | jq -r ".conclusion") 47 | RERUN_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$ID" 48 | 49 | if [[ "$STATUS" == "completed" && "$CONCLUSION" == "cancelled" ]]; then 50 | echo "::notice::Re-running $ID: $RERUN_URL" 51 | gh run rerun -R $GITHUB_REPOSITORY $ID --failed 52 | fi 53 | 54 | echo "exit=true" >> $GITHUB_OUTPUT 55 | echo "::error::Exiting as newest run $ID is waiting: $RERUN_URL" && exit 1 56 | else 57 | echo "exit=false" >> $GITHUB_OUTPUT 58 | fi 59 | -------------------------------------------------------------------------------- /.github/actions/github-deployment-create/action.yml: -------------------------------------------------------------------------------- 1 | name: Create GitHub Deployment 2 | description: Create GitHub Deployment 3 | inputs: 4 | github-token: 5 | description: GitHub Token 6 | required: true 7 | environment: 8 | description: The Environment for this Deployment 9 | required: true 10 | state: 11 | description: The Initial State to set right after creation 12 | default: "" 13 | 14 | outputs: 15 | id: 16 | description: The created deployment id 17 | value: ${{ steps.create.outputs.id }} 18 | 19 | runs: 20 | using: "composite" 21 | steps: 22 | - name: Create Deployment 23 | id: create 24 | env: 25 | GH_TOKEN: ${{ inputs.github-token }} 26 | TARGET_ENV: ${{ inputs.environment }} 27 | shell: bash 28 | run: | 29 | URL="/repos/$GITHUB_REPOSITORY/deployments" 30 | 31 | echo "Creating deployment at $URL for sha $GITHUB_SHA and env $TARGET_ENV" 32 | # use a json object to be able to empty the required_contexts array 33 | CREATED="$(jq -n --arg ref "$GITHUB_SHA" --arg environment "$TARGET_ENV" '{ref: $ref, environment: $environment, "auto_merge": false, "required_contexts": []}' | gh api -X POST $URL --input -)" 34 | echo $CREATED 35 | 36 | DEPLOYMENT_ID="$(echo $CREATED | jq -r ".id")" 37 | echo "Created deployment $DEPLOYMENT_ID" 38 | 39 | echo "id=$DEPLOYMENT_ID" >> $GITHUB_OUTPUT 40 | 41 | - name: Update Deployment State 42 | if: ${{ inputs.state != '' }} 43 | uses: Alfresco/alfresco-build-tools/.github/actions/github-deployment-status-update@v8.23.2 44 | with: 45 | github-token: ${{ inputs.github-token }} 46 | deployment-id: ${{ steps.create.outputs.id }} 47 | state: ${{ inputs.state }} 48 | -------------------------------------------------------------------------------- /.github/actions/github-deployment-status-update/action.yml: -------------------------------------------------------------------------------- 1 | name: Update Deployment Status 2 | description: Update Deployment Status 3 | inputs: 4 | github-token: 5 | description: GitHub Token 6 | required: true 7 | deployment-id: 8 | description: The Deployment Id 9 | required: true 10 | state: 11 | description: The Deployment State to be set (error, failure, inactive, in_progress, queued, pending, success) 12 | required: true 13 | 14 | runs: 15 | using: "composite" 16 | steps: 17 | - name: Update deployment status 18 | id: update 19 | env: 20 | GH_TOKEN: ${{ inputs.github-token }} 21 | DEPLOYMENT_ID: ${{ inputs.deployment-id }} 22 | STATE: ${{ inputs.state }} 23 | REPO_URL: ${{ github.server_url }}/${{ github.repository }} 24 | shell: bash 25 | run: | 26 | URL="/repos/$GITHUB_REPOSITORY/deployments/$DEPLOYMENT_ID/statuses" 27 | LOG_URL="$REPO_URL/actions/runs/$GITHUB_RUN_ID/attempts/$GITHUB_RUN_ATTEMPT" 28 | 29 | echo "Updating deployment $DEPLOYMENT_ID with state $STATE" 30 | UPDATED="$(gh api -X POST $URL -F state=$STATE -F log_url=$LOG_URL)" 31 | echo $UPDATED 32 | 33 | DEPLOYMENT_URL="$(echo $UPDATED | jq -r ".url")" 34 | ENVIRONMENT="$(echo $UPDATED | jq -r ".environment")" 35 | 36 | echo "Updated deployment status for [$ENVIRONMENT]($REPO_URL/deployments/$ENVIRONMENT) to: $STATE" >> $GITHUB_STEP_SUMMARY 37 | -------------------------------------------------------------------------------- /.github/actions/github-deployments-delete/action.yml: -------------------------------------------------------------------------------- 1 | name: Delete Github Deployments 2 | 3 | description: 4 | Deletes all GitHub deployments on a given branch. 5 | Used as workaround to delete the flood of messages visible on some PRs where environments are leveraged but deployments are not. 6 | 7 | inputs: 8 | branch-name: 9 | description: The name of the branch for the deployments 10 | required: true 11 | environment: 12 | description: The optional environment for the deployments 13 | required: false 14 | 15 | runs: 16 | using: composite 17 | steps: 18 | - name: delete-deployments 19 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 20 | env: 21 | GITHUB_ACTION_PATH: ${{ github.action_path }} 22 | with: 23 | script: | 24 | const options={ 25 | ref:'${{ inputs.branch-name }}', 26 | environment:'${{ inputs.environment }}' 27 | }; 28 | const githubActionPath = process.env.GITHUB_ACTION_PATH; 29 | const script = require(`${githubActionPath}/deleteDeploymentScript.js`); 30 | await script({github, context, options}); 31 | -------------------------------------------------------------------------------- /.github/actions/github-deployments-delete/deleteDeploymentScript.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({github, context, options}) => { 2 | const perPage = 100; 3 | let page = 1; 4 | let allDeployments = []; 5 | const {ref,environment} = options; 6 | 7 | while(true) { 8 | const deployments = await github.rest.repos.listDeployments({ 9 | owner: context.repo.owner, 10 | repo: context.repo.repo, 11 | ref: ref, 12 | per_page: perPage, 13 | page: page, 14 | environment: environment 15 | }); 16 | 17 | allDeployments = [...allDeployments, ...deployments.data]; 18 | if (!deployments.data.length) { 19 | break; 20 | } 21 | page++; 22 | } 23 | 24 | await Promise.all( 25 | allDeployments.map(async (deployment) => { 26 | await github.rest.repos.createDeploymentStatus({ 27 | owner: context.repo.owner, 28 | repo: context.repo.repo, 29 | deployment_id: deployment.id, 30 | state: 'inactive' 31 | }); 32 | return github.rest.repos.deleteDeployment({ 33 | owner: context.repo.owner, 34 | repo: context.repo.repo, 35 | deployment_id: deployment.id 36 | }); 37 | }) 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /.github/actions/github-download-file/action.yml: -------------------------------------------------------------------------------- 1 | name: "Github Download File" 2 | description: "Download a file from another repository" 3 | inputs: 4 | token: 5 | description: "GitHub Access Token" 6 | required: true 7 | repository: 8 | description: "The owner and repository name from which the file should be downloaded. For example, octocat/Hello-World." 9 | required: true 10 | file-path: 11 | description: "Path to the file you want to download" 12 | required: true 13 | target: 14 | description: "Where and with what name to save the file" 15 | required: true 16 | runs: 17 | using: "composite" 18 | steps: 19 | - name: "Download file" 20 | shell: bash 21 | env: 22 | GITHUB_TOKEN: ${{ inputs.token }} 23 | run: | 24 | export API_URL=https://api.github.com/repos/${{ inputs.repository }}/contents/${{ inputs.file-path }} 25 | gh api $API_URL -H "Accept: application/vnd.github.raw" >> ${{ inputs.target }} 26 | -------------------------------------------------------------------------------- /.github/actions/github-https-auth/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Github https authentication' 2 | description: 'Configure git to use http credentials for accessing private repositories' 3 | inputs: 4 | username: 5 | description: 'The username of the account' 6 | required: true 7 | pat: 8 | description: 'The token of the account' 9 | required: true 10 | runs: 11 | using: "composite" 12 | steps: 13 | - name: Configure git to use bot credentials 14 | run: git config --global url."https://${{ inputs.username }}:${{ inputs.pat }}@github.com".insteadOf "https://github.com" 15 | shell: bash 16 | -------------------------------------------------------------------------------- /.github/actions/github-list-changes/action.yml: -------------------------------------------------------------------------------- 1 | name: "Github List Changes" 2 | description: "List all changed files in a pushed set of commits or a pull request" 3 | inputs: 4 | write-list-to-env: 5 | description: "If set to true then write the list of changed files to the environment variable GITHUB_MODIFIED_FILES" 6 | default: "false" 7 | outputs: 8 | all_changed_files: 9 | description: The list of changed files (one per line) 10 | value: ${{ steps.list-changes.outputs.all-changed-files }} 11 | runs: 12 | using: "composite" 13 | steps: 14 | - name: "List changed files" 15 | id: list-changes 16 | shell: bash 17 | env: 18 | BEFORE_COMMIT: ${{ github.event.before }} 19 | AFTER_COMMIT: ${{ github.event.after }} 20 | PULL_REQUEST_NUMBER: ${{ github.event.number }} 21 | WRITE_LIST_TO_ENV: ${{ inputs.write-list-to-env }} 22 | run: ${{ github.action_path }}/github-list-changes.sh 23 | -------------------------------------------------------------------------------- /.github/actions/github-list-changes/github-list-changes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [[ $GITHUB_EVENT_NAME == "pull_request" ]]; then 4 | # Get the list of changed files from the pull request. 5 | git diff --name-only origin/$GITHUB_BASE_REF refs/remotes/pull/$PULL_REQUEST_NUMBER/merge > all-changed-files.txt 6 | elif [[ $GITHUB_EVENT_NAME == "push" ]]; then 7 | # Check if the old commit exists (it might not for force pushes). 8 | old_commit=$BEFORE_COMMIT 9 | # If it doesn't exist, then run against the (single) latest commit. 10 | git log -1 $old_commit > /dev/null 2>&1 || old_commit="$AFTER_COMMIT~" 11 | # Get the list of changed files from the pushed commits. 12 | git diff --name-only $old_commit $AFTER_COMMIT > all-changed-files.txt 13 | else 14 | echo "Unsupported event type: $GITHUB_EVENT_NAME" 15 | exit 1 16 | fi 17 | 18 | echo "List of changed files:" 19 | cat all-changed-files.txt 20 | 21 | # Multiline output requires a unique delimiter. 22 | EOF="EOF_9f507bc5-395d-47a6-83c7-ef23e9f5d313" 23 | 24 | # Write the list to the GitHub step output. 25 | echo "all-changed-files<<$EOF" >> $GITHUB_OUTPUT 26 | echo "$( cat all-changed-files.txt )" >> $GITHUB_OUTPUT 27 | echo "$EOF" >> $GITHUB_OUTPUT 28 | 29 | # Write the list to the environment variable if requested. 30 | if [[ "$WRITE_LIST_TO_ENV" == "true" ]]; then 31 | echo "GITHUB_MODIFIED_FILES<<$EOF" >> $GITHUB_ENV 32 | echo "$( cat all-changed-files.txt )" >> $GITHUB_ENV 33 | echo "$EOF" >> $GITHUB_ENV 34 | fi 35 | -------------------------------------------------------------------------------- /.github/actions/github-pr-check-metadata/action.yml: -------------------------------------------------------------------------------- 1 | name: PR author and label check 2 | description: Checks PR author and label, using PR that led to merge on push 3 | 4 | inputs: 5 | gh-token: 6 | description: 'GitHub token with content read permission' 7 | required: true 8 | actor: 9 | description: 'Check if the pull request was created by this actor' 10 | required: false 11 | label: 12 | description: 'Check if the pull request contains this label' 13 | required: true 14 | 15 | outputs: 16 | result: 17 | description: "Result of the check" 18 | value: ${{ steps.check.outputs.result }} 19 | 20 | runs: 21 | using: composite 22 | steps: 23 | - name: Check 24 | id: check 25 | env: 26 | GH_TOKEN: ${{ inputs.gh-token }} 27 | SHA: ${{ github.event.pull_request.head.sha || github.sha }} 28 | INPUT_LABEL: ${{ inputs.label }} 29 | INPUT_ACTOR: ${{ inputs.actor }} 30 | shell: bash 31 | run: | 32 | echo "Event name: $GITHUB_EVENT_NAME" 33 | PR_INFO=$(gh api /repos/$GITHUB_REPOSITORY/commits/$SHA/pulls | jq -r '.[0] | {user_login: .user.login, labels: [.labels[].name]}' ) 34 | LABELS=$(echo $PR_INFO | jq -r '.labels') 35 | echo "Labels found: $LABELS" 36 | 37 | if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then 38 | GITHUB_ACTOR=$(echo $PR_INFO | jq -r '.user_login') 39 | fi 40 | echo "Creator: $GITHUB_ACTOR" 41 | 42 | if [ -n "$INPUT_ACTOR" ] 43 | then 44 | [[ "$GITHUB_ACTOR" == "$INPUT_ACTOR" && "$LABELS" == *"$INPUT_LABEL"* ]] && RESULT=true || RESULT=false 45 | else 46 | [[ "$LABELS" == *"$INPUT_LABEL"* ]] && RESULT=true || RESULT=false 47 | fi 48 | 49 | echo "result=$RESULT" 50 | echo "result=$RESULT" >> $GITHUB_OUTPUT 51 | -------------------------------------------------------------------------------- /.github/actions/helm-build-chart/action.yml: -------------------------------------------------------------------------------- 1 | name: "Build helm chart" 2 | description: "Build helm chart by running `helm up` and `helm lint`" 3 | inputs: 4 | chart-dir: 5 | description: "Path to the folder holding Chart.yaml" 6 | required: true 7 | 8 | runs: 9 | using: composite 10 | steps: 11 | - name: Build and lint 12 | shell: bash 13 | run: | 14 | helm dep up ${{ inputs.chart-dir }} 15 | helm lint ${{ inputs.chart-dir }} 16 | -------------------------------------------------------------------------------- /.github/actions/helm-integration-tests/action.yml: -------------------------------------------------------------------------------- 1 | name: Helm Integration Tests 2 | description: > 3 | Execute helm upgrade with dry run on given chart 4 | 5 | inputs: 6 | chart-dir: 7 | description: 'Path to the folder holding Chart.yaml' 8 | required: true 9 | test-rancher-url: 10 | description: 'Rancher URL for tests, tests are skipped if not filled' 11 | required: true 12 | test-rancher-access-key: 13 | description: 'Rancher access key for tests, tests are skipped if not filled' 14 | required: true 15 | test-rancher-secret-key: 16 | description: 'Rancher secret key for tests, tests are skipped if not filled' 17 | required: true 18 | test-cluster-name: 19 | description: 'Name of the Rancher cluster name for tests' 20 | required: true 21 | test-namespace: 22 | description: > 23 | Name of the namespace in rancher for tests (should be unique in PRs), 24 | tests are skipped if not filled. 25 | required: false 26 | test-gateway-domain: 27 | description: > 28 | Value of the `global.gateway.domain` property used for the `helm upgrade` command. 29 | required: false 30 | default: 'example' 31 | test-keycloak-client-secret: 32 | description: > 33 | Value of the `global.keycloak.clientSecret` property used for the `helm upgrade` command. 34 | required: false 35 | 36 | runs: 37 | using: composite 38 | steps: 39 | - name: Setup rancher 40 | uses: Alfresco/alfresco-build-tools/.github/actions/setup-rancher-cli@v8.23.2 41 | with: 42 | url: ${{ inputs.test-rancher-url }} 43 | access-key: ${{ inputs.test-rancher-access-key }} 44 | secret-key: ${{ inputs.test-rancher-secret-key }} 45 | context: ${{ inputs.test-cluster-name }} 46 | - name: Compute Keycloak Client Secret 47 | id: compute-keycloak-secret 48 | shell: bash 49 | env: 50 | KEYCLOAK_SECRET: ${{ inputs.test-keycloak-client-secret }} 51 | run: | 52 | if [ -n "$KEYCLOAK_SECRET" ] 53 | then 54 | echo "result=$KEYCLOAK_SECRET" >> $GITHUB_OUTPUT 55 | else 56 | echo "result=$(uuidgen)" >> $GITHUB_OUTPUT 57 | fi 58 | - name: Execute helm upgrade dry-run 59 | env: 60 | CHART_DIR: ${{ inputs.chart-dir }} 61 | NAMESPACE: ${{ inputs.test-namespace }} 62 | DOMAIN: ${{ inputs.test-gateway-domain }} 63 | KEYCLOAK_SECRET: ${{ steps.compute-keycloak-secret.outputs.result }} 64 | shell: bash 65 | run: | 66 | NAMESPACE_LOWERCASE=$(echo ${NAMESPACE} | tr "[:upper:]" "[:lower:]") 67 | helm upgrade $NAMESPACE_LOWERCASE $CHART_DIR \ 68 | --install \ 69 | --set global.gateway.domain=$DOMAIN \ 70 | --set global.keycloak.clientSecret=$KEYCLOAK_SECRET \ 71 | --namespace $NAMESPACE_LOWERCASE \ 72 | --wait \ 73 | --dry-run 74 | -------------------------------------------------------------------------------- /.github/actions/helm-package-chart/action.yml: -------------------------------------------------------------------------------- 1 | name: "Package helm chart" 2 | description: "Package helm chart by running `helm dep up` and ` helm package`" 3 | inputs: 4 | chart-dir: 5 | description: Relative path to the folder holding Chart.yaml 6 | required: true 7 | chart-repository-dir: 8 | description: Optional path to the git repository holding the chart project (defaults to current directory) 9 | required: false 10 | outputs: 11 | package-file: 12 | description: The name of the generated package file. It's uploaded as an artifact and can be downloaded using actions/download-artifact 13 | value: ${{ steps.package.outputs.package-file }} 14 | package-file-path: 15 | description: The path of the generated package file. 16 | value: ${{ steps.package.outputs.package-file-path }} 17 | 18 | runs: 19 | using: composite 20 | steps: 21 | 22 | - name: Generate random path for helm package 23 | shell: bash 24 | run: echo "RANDOM_PATH=$(uuidgen)" >> $GITHUB_ENV 25 | 26 | - name: Package chart 27 | id: package 28 | shell: bash 29 | env: 30 | CHART_REPO_DIR: ${{inputs.chart-repository-dir }} 31 | run: | 32 | if [ -n "$CHART_REPO_DIR" ] 33 | then 34 | cd $CHART_REPO_DIR 35 | fi 36 | 37 | helm package --dependency-update --destination $RANDOM_PATH ${{ inputs.chart-dir }} 38 | 39 | PACKAGE_FILE=$(ls $RANDOM_PATH | grep "**/*\.tgz") 40 | PACKAGE_FILE_PATH="$(pwd)/$RANDOM_PATH/$PACKAGE_FILE" 41 | echo "package-file=$PACKAGE_FILE" >> $GITHUB_OUTPUT 42 | echo "package-file-path=$PACKAGE_FILE_PATH" >> $GITHUB_OUTPUT 43 | 44 | - name: Upload Artifact 45 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 46 | with: 47 | name: ${{steps.package.outputs.package-file}} 48 | path: ${{steps.package.outputs.package-file-path}} 49 | if-no-files-found: error 50 | -------------------------------------------------------------------------------- /.github/actions/helm-parse-next-release/action.yml: -------------------------------------------------------------------------------- 1 | name: Parse next release from chart 2 | description: > 3 | Parses the next main release version based on the content of Chart.yaml. 4 | The suffix `-SNAPSHOT` is removed. 5 | inputs: 6 | chart-dir: 7 | description: "The relative path to the directory holding Chart.yaml" 8 | required: true 9 | chart-repository-dir: 10 | description: "The path the git repository holding the chart project" 11 | required: false 12 | outputs: 13 | next-release: 14 | description: Next released parsed from the Chart.yaml file 15 | value: ${{ steps.parse-next-release.outputs.next-release }} 16 | runs: 17 | using: composite 18 | steps: 19 | - name: Parse next release 20 | id: parse-next-release 21 | shell: bash 22 | env: 23 | CHART_REPO_DIR: ${{ inputs.chart-repository-dir }} 24 | run: | 25 | if [ -n "$CHART_REPO_DIR" ] 26 | then 27 | cd $CHART_REPO_DIR 28 | fi 29 | 30 | NEXT_VERSION=$(yq e '.version' ${{ inputs.chart-dir }}/Chart.yaml | grep -o "[0-9]*\.[0-9]*.[0-9]*") 31 | echo "Next final version: $NEXT_VERSION" 32 | echo "next-release=$NEXT_VERSION" >> $GITHUB_OUTPUT 33 | -------------------------------------------------------------------------------- /.github/actions/helm-plugin/action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Helm Plugin install 3 | description: > 4 | Install an helm plugin from provided url 5 | inputs: 6 | plugin_url: 7 | description: URL where to get the plugin from 8 | required: true 9 | plugin_version: 10 | description: version of the helm-unittest plugin to install 11 | required: false 12 | default: latest 13 | runs: 14 | using: composite 15 | steps: 16 | - name: Install Helm plugin ${{ inputs.plugin_url }} 17 | shell: bash 18 | run: | 19 | set -e 20 | [ ${{ inputs.plugin_version }} != 'latest' ] && \ 21 | VER="--version ${{ inputs.plugin_version }}" 22 | helm plugin install ${{ inputs.plugin_url }} $VER 23 | -------------------------------------------------------------------------------- /.github/actions/helm-template-yamllint/.yamllint.yml: -------------------------------------------------------------------------------- 1 | extends: default 2 | 3 | rules: 4 | line-length: disable 5 | indentation: disable 6 | trailing-spaces: disable 7 | -------------------------------------------------------------------------------- /.github/actions/helm-template-yamllint/action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Helm templates yaml linter 3 | description: > 4 | Render helm chart templates and pipe into yamllint (check for duplicated keys and other inconsistencies that helm itself doesn't care of) 5 | inputs: 6 | chart-dir: 7 | description: Root folder of the chart where to launch helm commands 8 | required: false 9 | default: . 10 | output-dir: 11 | description: Output folder where the yaml files will be persisted 12 | required: false 13 | default: /tmp/helm-template 14 | helm-options: 15 | description: Pass arbitrary values to helm command 16 | required: false 17 | default: "" 18 | yamllint-config-path: 19 | description: Path to a custom yamllint config 20 | required: false 21 | default: "" 22 | runs: 23 | using: composite 24 | steps: 25 | - name: Cleanup output dir 26 | shell: bash 27 | run: rm -fr ${{ inputs.output-dir }} 28 | - name: Render templates 29 | shell: bash 30 | working-directory: ${{ inputs.chart-dir }} 31 | run: helm template . --output-dir ${{ inputs.output-dir }} ${{ inputs.helm-options }} 32 | - name: Lint 33 | env: 34 | YAMLLINT_CONFIG_FILE: ${{ inputs.yamllint-config-path }} 35 | shell: bash 36 | run: | 37 | YAMLLINT_CONFIG_FILE="${YAMLLINT_CONFIG_FILE:=${{ github.action_path }}/.yamllint.yml}" 38 | yamllint ${{ inputs.output-dir }} 39 | -------------------------------------------------------------------------------- /.github/actions/helm-update-chart-version/action.yml: -------------------------------------------------------------------------------- 1 | name: "Update chart version" 2 | description: "Update the version field in the Chart.yaml file" 3 | inputs: 4 | new-version: 5 | description: "The new version of the chart" 6 | required: true 7 | chart-dir: 8 | description: "The relative path to the directory holding Chart.yaml" 9 | required: true 10 | chart-repository-dir: 11 | description: "The path the git repository holding the chart project" 12 | required: false 13 | helm-docs-version: 14 | description: 'Version of helm-docs' 15 | required: false 16 | runs: 17 | using: composite 18 | steps: 19 | - uses: Alfresco/alfresco-build-tools/.github/actions/setup-helm-docs@v8.23.2 20 | with: 21 | version: ${{ inputs.helm-docs-version }} 22 | - name: Update version 23 | shell: bash 24 | env: 25 | CHART_REPO_DIR: ${{ inputs.chart-repository-dir }} 26 | run: | 27 | if [ -n "$CHART_REPO_DIR" ] 28 | then 29 | cd $CHART_REPO_DIR 30 | fi 31 | yq -i e '.version = "${{ inputs.new-version }}"' ${{ inputs.chart-dir }}/Chart.yaml 32 | helm-docs 33 | -------------------------------------------------------------------------------- /.github/actions/install-galaxy-deps/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Galaxy dependencies' 2 | description: 'Install and cache ansible galaxy dependencies' 3 | inputs: 4 | cache-name: 5 | description: 'A keyword to compose the cache final name' 6 | required: true 7 | default: 'default' 8 | cache-version: 9 | description: 'Increase to force recreating the cache' 10 | required: true 11 | default: "1" 12 | runs: 13 | using: "composite" 14 | steps: 15 | - name: Cache Ansible collections and roles 16 | id: collections-cache 17 | uses: actions/cache@v4 18 | with: 19 | path: | 20 | ~/.ansible/collections 21 | ~/.ansible/roles 22 | key: ansible-galaxy-v${{ inputs.cache-version }}-${{ inputs.cache-name }}-${{ hashFiles('requirements.yml') }} 23 | 24 | - name: Fetch dependencies from Ansible Galaxy 25 | run: | 26 | CMD_PREFIX="" 27 | if command -v pipenv >/dev/null 2>&1; then 28 | CMD_PREFIX="pipenv run" 29 | fi 30 | $CMD_PREFIX ansible-galaxy install -r requirements.yml --force 31 | if: steps.collections-cache.outputs.cache-hit != 'true' 32 | shell: bash 33 | -------------------------------------------------------------------------------- /.github/actions/install-ubuntu-default-tools/action.yml: -------------------------------------------------------------------------------- 1 | name: "Install Ubuntu default tools" 2 | description: "Install common Ubuntu tools (e.g.: docker, git, zip, unzip)" 3 | inputs: 4 | packages: 5 | description: "The list of package names to be installed separated by a whitespace" 6 | required: false 7 | sudo: 8 | description: "Whether to use sudo or not" 9 | required: false 10 | default: "true" 11 | runs: 12 | using: composite 13 | steps: 14 | - name: "Install common tools" 15 | shell: bash 16 | run: | 17 | if [ "${{ inputs.sudo }}" = "true" ]; then 18 | SUDO="sudo" 19 | else 20 | SUDO="" 21 | fi 22 | 23 | $SUDO apt-get update 24 | $SUDO apt-get install -y ca-certificates curl gnupg git zip unzip ${{ inputs.packages }} 25 | 26 | # Install Docker as per https://docs.docker.com/engine/install/ubuntu/ 27 | $SUDO install -m 0755 -d /etc/apt/keyrings 28 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | $SUDO gpg --dearmor -o /etc/apt/keyrings/docker.gpg 29 | $SUDO chmod a+r /etc/apt/keyrings/docker.gpg 30 | echo \ 31 | "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ 32 | "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ 33 | $SUDO tee /etc/apt/sources.list.d/docker.list > /dev/null 34 | $SUDO apt-get update 35 | $SUDO apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 36 | -------------------------------------------------------------------------------- /.github/actions/kubectl-keep-nslogs/action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: upload k8s logs as artifacts 3 | description: > 4 | Upload Kubernetes logs (jobs and pods) as a github artifact. 5 | Special attention must be payed to repo's storage limits. 6 | inputs: 7 | namespace: 8 | description: The kubernetes namespace to get logs from 9 | required: false 10 | default: default 11 | log_retention: 12 | description: Number of days to keep the logs for 13 | required: false 14 | default: "10" 15 | runs: 16 | using: composite 17 | steps: 18 | - id: artifactdir 19 | name: Create artifact directory 20 | shell: bash 21 | run: | 22 | ARTIFACTS_DIR=$(mktemp -d) 23 | echo "ARTIFACTS_DIR=${ARTIFACTS_DIR}" >> $GITHUB_OUTPUT 24 | - name: Fetch logs 25 | shell: bash 26 | working-directory: ${{ steps.artifactdir.outputs.ARTIFACTS_DIR }} 27 | run: | 28 | kubectl config set-context --current --namespace=${{ inputs.namespace }} 29 | for type in deployment.apps statefulset.apps jobs; do 30 | [ -d "${type}" ] || mkdir "${type}" 31 | for i in $(kubectl get "$type" -o name); do \ 32 | kubectl logs "$i" --all-containers=true | \ 33 | gzip > "${i}.log.gz" 34 | done 35 | done 36 | - name: upload kubernetes logs as artifact 37 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 38 | with: 39 | name: >- 40 | ${{ inputs.namespace }}_logs.${{ github.run_number }}.${{ github.run_attempt }} 41 | retention-days: ${{ inputs.log_retention }} 42 | path: ${{ steps.artifactdir.outputs.ARTIFACTS_DIR }} 43 | -------------------------------------------------------------------------------- /.github/actions/kubectl-wait/action.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Kubectl wait 3 | description: > 4 | Wait for all resources inside a namespace to be ready 5 | inputs: 6 | namespace: 7 | description: Namespace to wait for 8 | required: false 9 | wait-timeout: 10 | description: Timeout for the wait command 11 | required: false 12 | default: 10m 13 | wait-condition: 14 | description: Condition to wait for 15 | required: false 16 | default: Ready 17 | wait-resource: 18 | description: Resource to wait for 19 | required: false 20 | default: pods 21 | runs: 22 | using: composite 23 | steps: 24 | - name: Set vars 25 | shell: bash 26 | run: | 27 | NAMESPACE_PARAM="${{ inputs.namespace != '' && format('-n {0}', inputs.namespace) || '' }}" >> $GITHUB_ENV 28 | 29 | - name: Watch resources 30 | shell: bash 31 | run: | 32 | kubectl get ${{ inputs.wait-resource }} --watch $NAMESPACE_PARAM & 33 | kubectl wait --timeout=${{ inputs.wait-timeout }} --all=true --for=condition=${{ inputs.wait-condition }} ${{ inputs.wait-resource }} $NAMESPACE_PARAM 34 | 35 | - name: Spit resources status after wait 36 | shell: bash 37 | if: always() 38 | run: | 39 | kubectl get ${{ inputs.wait-resource }} $NAMESPACE_PARAM 40 | kubectl describe ${{ inputs.wait-resource }} $NAMESPACE_PARAM 41 | -------------------------------------------------------------------------------- /.github/actions/maven-dependency-scan/action.yml: -------------------------------------------------------------------------------- 1 | name: Create Dependency Graph 2 | description: Create dependency graph for the project 3 | 4 | inputs: 5 | restore-artifact-pattern: 6 | description: Pattern to match artifacts. 7 | required: false 8 | restore-artifact-path: 9 | description: Path to the artifact directory. 10 | required: false 11 | java-version: 12 | description: Java version to use. 13 | required: true 14 | maven-version: 15 | description: Maven version to use. 16 | required: true 17 | maven-args: 18 | description: Maven arguments for dependency submission. 19 | required: true 20 | maven-username: 21 | description: Maven username for authentication. 22 | required: false 23 | maven-password: 24 | description: Maven password for authentication. 25 | required: false 26 | ghcr-username: 27 | description: ghcr.io user name 28 | required: false 29 | ghcr-password: 30 | description: ghcr.io password 31 | required: false 32 | 33 | runs: 34 | using: composite 35 | steps: 36 | - name: Download M2 build artifacts 37 | if: ${{ inputs.restore-artifact-pattern != '' }} 38 | uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 39 | with: 40 | pattern: ${{ inputs.restore-artifact-pattern }} 41 | merge-multiple: true 42 | path: ${{ inputs.restore-artifact-path }} 43 | 44 | - uses: Alfresco/alfresco-build-tools/.github/actions/maven-configure@v8.23.2 45 | id: maven-configure 46 | with: 47 | java-version: ${{ inputs.java-version }} 48 | maven-version: ${{ inputs.maven-version }} 49 | 50 | - name: Submit Dependency Graph 51 | uses: advanced-security/maven-dependency-submission-action@4f64ddab9d742a4806eeb588d238e4c311a8397d # v4.1.1 52 | with: 53 | maven-args: ${{steps.maven-configure.outputs.maven-options}} ${{ inputs.maven-args }} 54 | env: 55 | MAVEN_USERNAME: ${{ inputs.maven-username }} 56 | MAVEN_PASSWORD: ${{ inputs.maven-password }} 57 | GHCR_USERNAME: ${{ inputs.ghcr-username }} 58 | GHCR_PASSWORD: ${{ inputs.ghcr-password }} 59 | -------------------------------------------------------------------------------- /.github/actions/maven-deploy-file/action.yml: -------------------------------------------------------------------------------- 1 | name: "maven-deploy-file" 2 | description: "Deploy one or more binaries to a maven repository" 3 | inputs: 4 | group-id: 5 | description: groupId of the artifact(s) to be deployed 6 | required: true 7 | artifact-id: 8 | description: artifactId of the artifact(s) to be deployed 9 | required: true 10 | repository-url: 11 | description: Maven repository URL where artifact(s) will be deployed 12 | required: true 13 | version: 14 | description: version of the artifact(s) to be deployed 15 | required: true 16 | file: 17 | description: Path to the main file that needs to be deployed 18 | required: true 19 | maven-username: 20 | description: Username to authenticate to the maven repository (when not using a custom settings.xml) 21 | required: false 22 | maven-password: 23 | description: Password to authenticate to the maven repository (when not using a custom settings.xml) 24 | required: false 25 | repository-id: 26 | description: Credentials to use as defined in settings.xml 27 | required: false 28 | default: authenticated-maven-repository 29 | generate-pom: 30 | description: Upload an autogenerated POM for artifact(s) 31 | required: false 32 | default: 'true' 33 | classifier: 34 | description: Classifier of the main file that needs to be deployed 35 | required: false 36 | files: 37 | description: Comma separated paths to additional files that needs to be deployed 38 | required: false 39 | classifiers: 40 | description: Comma separated classifiers for additional files that needs to be deployed 41 | required: false 42 | types: 43 | description: Comma separated types for additional files that needs to be deployed 44 | required: false 45 | runs: 46 | using: "composite" 47 | steps: 48 | - name: Copy embedded settings.xml if not already existing 49 | shell: bash 50 | env: 51 | MAVEN_USERNAME: ${{ inputs.maven-username }} 52 | MAVEN_PASSWORD: ${{ inputs.maven-password }} 53 | run: | 54 | if [ ! -f ~/.m2/settings.xml ]; then 55 | echo "Using embedded settings.xml" 56 | if [ -z "$MAVEN_USERNAME" ] || [ -z "$MAVEN_PASSWORD" ]; then 57 | echo "::error ::You need to provide credentials as maven-username and maven-password inputs when not providing a custom settings.xml" 58 | exit 1 59 | fi 60 | mkdir -p ~/.m2/ 61 | cp ${{ github.action_path }}/settings.xml ~/.m2/ 62 | else 63 | echo "Existing settings.xml found" 64 | echo "Make sure to provide repository-id as input for choosing the right authentication credentials" 65 | fi 66 | - name: mvn deploy:deploy-file 67 | shell: bash 68 | env: 69 | MAVEN_USERNAME: ${{ inputs.maven-username }} 70 | MAVEN_PASSWORD: ${{ inputs.maven-password }} 71 | run: | 72 | OPTIONAL_ARGS="" 73 | if [[ -n "${{ inputs.files }}" && -n "${{ inputs.classifiers }}" && -n "${{ inputs.types }}" ]]; then 74 | OPTIONAL_ARGS='-Dfiles=${{ inputs.files }} -Dclassifiers=${{ inputs.classifiers }} -Dtypes=${{ inputs.types }}' 75 | fi 76 | mvn deploy:deploy-file -B \ 77 | -DgroupId=${{ inputs.group-id }} \ 78 | -DartifactId=${{ inputs.artifact-id }} \ 79 | -Durl=${{ inputs.repository-url }} \ 80 | -DrepositoryId=${{ inputs.repository-id }} \ 81 | -Dversion=${{ inputs.version }} \ 82 | -Dfile=${{ inputs.file }} \ 83 | -Dclassifier=${{ inputs.classifier }} \ 84 | -DgeneratePom=${{ inputs.generate-pom }} \ 85 | $OPTIONAL_ARGS \ 86 | -DretryFailedDeploymentCount=5 87 | -------------------------------------------------------------------------------- /.github/actions/maven-deploy-file/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | authenticated-maven-repository 5 | ${env.MAVEN_USERNAME} 6 | ${env.MAVEN_PASSWORD} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.github/actions/maven-release/update-pom-version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RELEASE_VERSION=${1:-$RELEASE_VERSION} 4 | EXTRA_REPLACEMENTS=${2:-EXTRA_REPLACEMENTS} 5 | 6 | POM_VERSION=$(yq -p=xml e '.project.version' pom.xml) 7 | echo "Updating versions in pom.xml files: ${POM_VERSION} --> ${RELEASE_VERSION}" 8 | 9 | SED_REPLACEMENTS="${SED_REPLACEMENTS} -e 's|${POM_VERSION}|${RELEASE_VERSION}|g'" 10 | for PROPERTY in ${EXTRA_REPLACEMENTS//,/ } 11 | do 12 | PROPERTY_NAME=${PROPERTY%=*} 13 | PROPERTY_VALUE=${PROPERTY#*=} 14 | echo "Property to be updated $PROPERTY_NAME: $PROPERTY_VALUE --> $RELEASE_VERSION" 15 | SED_REPLACEMENTS="${SED_REPLACEMENTS} -e 's|<$PROPERTY_NAME>${PROPERTY_VALUE}|<$PROPERTY_NAME>${RELEASE_VERSION}|g'" 16 | done 17 | 18 | if [[ "$OSTYPE" == "darwin"* ]]; then 19 | eval "find . -name pom.xml -exec sed -i.bak ${SED_REPLACEMENTS} {} \;" 20 | find . -name pom.xml.bak -delete 21 | else 22 | eval "find . -name pom.xml -exec sed -i ${SED_REPLACEMENTS} {} \;" 23 | fi 24 | 25 | echo "Checking for occurrences of non final versions..." 26 | grep -r '[0-9]*\.[0-9]*\.[0-9]*\-SNAPSHOT\|[0-9]*\.[0-9]*\.[0-9]*\-alpha\.[0-9]*' --include=pom.xml . \ 27 | && echo "At least one occurrence of a non final version was found. Stopping the release..." && exit 1 \ 28 | || echo "No occurrences of non final versions was found. Proceeding with the release..." 29 | -------------------------------------------------------------------------------- /.github/actions/maven-update-pom-version/action.yml: -------------------------------------------------------------------------------- 1 | description: Update pom files to the provided version 2 | name: Update pom version 3 | inputs: 4 | version: 5 | description: the new version to be set in the pom files 6 | required: true 7 | maven-cli-opts: 8 | description: extra maven properties 9 | required: false 10 | property-to-update: 11 | description: property to update in addition to the version of the pom file 12 | required: false 13 | repository-directory: 14 | description: git repository holding the code 15 | required: false 16 | runs: 17 | using: composite 18 | steps: 19 | - name: Update pom files to the new version 20 | shell: bash 21 | env: 22 | MAVEN_CLI_OPTS: ${{ inputs.maven-cli-opts }} 23 | VERSION: ${{ inputs.version }} 24 | PROPERTY_NAME: ${{ inputs.property-to-update }} 25 | REPO_DIR: ${{ inputs.repository-directory }} 26 | run: | 27 | if [ -n "$REPO_DIR" ] 28 | then 29 | cd $REPO_DIR 30 | fi 31 | [[ -n "$PROPERTY_NAME" ]] && SET_PROPERTY="versions:set-property -Dproperty=$PROPERTY_NAME" || SET_PROPERTY="" 32 | mvn -B versions:set $SET_PROPERTY -DnewVersion=$VERSION -DprocessAllModules=true -DgenerateBackupPoms=false $MAVEN_CLI_OPTS 33 | -------------------------------------------------------------------------------- /.github/actions/md-toc/action.yml: -------------------------------------------------------------------------------- 1 | name: Markdown ToC Generator 2 | description: Generate a Table of Contents from a Markdown file 3 | inputs: 4 | md_toc_version: 5 | description: Markdown Table of Contents Package version 6 | required: false 7 | default: 1.2.0 8 | md_src: 9 | description: | 10 | Markdown file(s) to generate Table of Contents for. It can be a list of 11 | space separated files or a glob pattern relative to the repository root. 12 | required: true 13 | depth: 14 | description: Depth of Table of Contents 15 | required: false 16 | default: '2' 17 | dry_run: 18 | description: Skip destructive actions 19 | required: false 20 | default: 'false' 21 | append: 22 | description: >- 23 | A string to append to Table of Contents (e.g. you may want to append the 24 | sha of the commit toc was added on top of?) 25 | required: false 26 | default: '' 27 | bullets: 28 | description: Bullets to use for Table of Contents ("*", "-" or "+") 29 | required: false 30 | default: '' 31 | node_version: 32 | description: Node.js version to install (false means do not install) 33 | required: false 34 | default: '20' 35 | runs: 36 | using: 'composite' 37 | steps: 38 | - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 39 | if: ${{ inputs.node_install }} 40 | with: 41 | node-version: ${{ inputs.node_version }} 42 | - name: Install Markdown ToC node package 43 | run: npm install -g markdown-toc@${{ inputs.md_toc_version }} 44 | shell: bash 45 | - name: Generate Table of Contents 46 | env: 47 | MDTOC_IARG: ${{ inputs.dry_run == 'false' && '-i' || '' }} 48 | MDTOC_BARG: ${{ inputs.bullets != '' && format('--bullets {0}', inputs.bullets) || '' }} 49 | run: | 50 | export MDTOC_ARGS="${{ env.MDTOC_IARG }} ${{ env.MDTOC_BARG }}" 51 | for f in ${{ inputs.md_src }}; do 52 | if [ -f $f ]; then 53 | markdown-toc $MDTOC_ARGS \ 54 | --maxdepth ${{ inputs.depth }} \ 55 | --append "${{ inputs.append }}" $f && \ 56 | echo "Table of Contents successfully generated in ${{ inputs.md_src }}" 57 | else 58 | echo "File $f not found.. Skipping!" 59 | fi 60 | done 61 | shell: bash 62 | - name: Autocommit changes 63 | if: inputs.dry_run == 'false' 64 | uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0 65 | with: 66 | commit_message: Auto update TOC in ${{ inputs.md_src }} 67 | disable_globbing: true 68 | file_pattern: ${{ inputs.md_src }} 69 | -------------------------------------------------------------------------------- /.github/actions/nexus-move-artifacts/action.yml: -------------------------------------------------------------------------------- 1 | name: Move artifacts to destination repository 2 | description: Move artifacts to destination repository in Nexus 3 3 | inputs: 4 | nexus-username: 5 | description: Nexus username 6 | required: true 7 | nexus-password: 8 | description: Nexus password 9 | required: true 10 | nexus-url: 11 | description: Base URL to the Nexus server 12 | required: true 13 | destination-repository: 14 | description: The destination repository 15 | required: true 16 | source-repository: 17 | description: The source repository 18 | required: true 19 | group: 20 | description: The maven group-id of the components to be moved 21 | required: true 22 | version: 23 | description: The version of the components to be moved 24 | required: true 25 | 26 | runs: 27 | using: composite 28 | steps: 29 | - name: count-artifacts 30 | id: count-artifacts 31 | shell: bash 32 | env: 33 | NEXUS_USERNAME: ${{ inputs.nexus-username }} 34 | NEXUS_PASSWORD: ${{ inputs.nexus-password }} 35 | NEXUS_URL: ${{ inputs.nexus-url }} 36 | SOURCE_REPOSITORY: ${{ inputs.source-repository }} 37 | GROUP: ${{ inputs.group }} 38 | VERSION: ${{ inputs.version }} 39 | run: | 40 | echo "Counting artifacts in repository ${SOURCE_REPOSITORY} in Nexus" 41 | search_response=$(curl -sSf -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" \ 42 | -X GET "${NEXUS_URL}/service/rest/v1/search?repository=${SOURCE_REPOSITORY}&group=${GROUP}&version=${VERSION}" \ 43 | -H 'Content-Type: application/json' \ 44 | -H 'accept: application/json' \ 45 | -d '{}') 46 | count=$(echo "$search_response" | yq '.items | length') 47 | echo "count=$count" >> $GITHUB_OUTPUT 48 | 49 | - name: move-artifacts 50 | id: move-artifacts 51 | shell: bash 52 | env: 53 | NEXUS_USERNAME: ${{ inputs.nexus-username }} 54 | NEXUS_PASSWORD: ${{ inputs.nexus-password }} 55 | NEXUS_URL: ${{ inputs.nexus-url }} 56 | DESTINATION_REPOSITORY: ${{ inputs.destination-repository }} 57 | SOURCE_REPOSITORY: ${{ inputs.source-repository }} 58 | GROUP: ${{ inputs.group }} 59 | VERSION: ${{ inputs.version }} 60 | run: | 61 | count="${{ steps.count-artifacts.outputs.count }}" 62 | if [ $count -eq 0 ]; then 63 | echo "No artifacts found in repository ${SOURCE_REPOSITORY} for group ${GROUP} and version ${VERSION}" 64 | else 65 | echo "Moving artifacts to destination repository ${DESTINATION_REPOSITORY} from source repository ${SOURCE_REPOSITORY} in Nexus" 66 | curl -sSf -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" \ 67 | -X POST "${NEXUS_URL}/service/rest/v1/staging/move/${DESTINATION_REPOSITORY}?repository=${SOURCE_REPOSITORY}&group=${GROUP}&version=${VERSION}" \ 68 | -H 'Content-Type: application/json' \ 69 | -H 'accept: application/json' \ 70 | -d '{}' 71 | fi 72 | -------------------------------------------------------------------------------- /.github/actions/pipenv/action.yml: -------------------------------------------------------------------------------- 1 | name: pipenv 2 | description: 'Install python packages with pipenv' 3 | inputs: 4 | python-version: 5 | description: The python version 6 | required: false 7 | default: "3.9" 8 | outputs: 9 | pipenv-root: 10 | description: >- 11 | Root directory where the virtual environment has been created (where the 12 | Pipfile sits) 13 | value: ${{ steps.pipenv.outputs.pipenv-root }} 14 | 15 | runs: 16 | using: "composite" 17 | steps: 18 | - name: Install pipenv dependency 19 | shell: bash 20 | run: pip install -r ${{ github.action_path }}/requirements.txt 21 | - name: Prepare pipenv virtualenv 22 | id: pipenv 23 | shell: bash 24 | run: | 25 | pipenv install --deploy --dev --python ${{ inputs.python-version }} 26 | echo "pipenv-root=$(pwd)" >> $GITHUB_OUTPUT 27 | -------------------------------------------------------------------------------- /.github/actions/pipenv/requirements.txt: -------------------------------------------------------------------------------- 1 | pipenv==2025.0.3 2 | -------------------------------------------------------------------------------- /.github/actions/pre-commit/action.yml: -------------------------------------------------------------------------------- 1 | name: "Pre-commit run" 2 | description: "Install and run pre-commit" 3 | inputs: 4 | pre-commit-args: 5 | description: Additional parameters to pass to pre-commit 6 | required: false 7 | pre-commit-all-files: 8 | description: >- 9 | Whether to run pre-commit checks on all files (defaults to "true") 10 | required: false 11 | default: "true" 12 | auto-commit: 13 | description: >- 14 | Enables auto-commit of eventual fixups 15 | (requires `permissions.contents: write` on the calling job) 16 | required: false 17 | default: "false" 18 | python-version: 19 | description: The python version of the local runner 20 | required: false 21 | default: "3.9" 22 | skip_checkout: 23 | description: If the internal checkout action should be skipped or not 24 | required: false 25 | default: "false" 26 | runs: 27 | using: "composite" 28 | steps: 29 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 30 | if: inputs.skip_checkout == 'false' 31 | env: 32 | REF_TO_CHECKOUT: ${{ inputs.auto-commit == 'true' && github.head_ref || '' }} 33 | with: 34 | ref: ${{ env.REF_TO_CHECKOUT }} 35 | 36 | - name: Set up Python ${{ inputs.python-version }} 37 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 38 | with: 39 | python-version: ${{ inputs.python-version }} 40 | 41 | - name: build extra_args 42 | shell: bash 43 | env: 44 | EXTRA_ARGS: '' 45 | run: | 46 | ${{ inputs.pre-commit-all-files }} && EXTRA_ARGS='--all-files' 47 | EXTRA_ARGS="${EXTRA_ARGS} ${{ inputs.pre-commit-args }}" 48 | echo EXTRA_ARGS="${EXTRA_ARGS}" >> $GITHUB_ENV 49 | 50 | - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 51 | id: pre-commit 52 | env: 53 | CONTINUE_ON_ERROR: ${{ inputs.auto-commit == 'true' }} 54 | continue-on-error: ${{ fromJSON(env.CONTINUE_ON_ERROR) }} 55 | with: 56 | extra_args: ${{ env.EXTRA_ARGS }} 57 | 58 | - uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0 59 | id: auto-commit-action 60 | if: inputs.auto-commit == 'true' 61 | 62 | - name: Re-throw potential pre-commit failure when no changes detected for auto-commit 63 | if: inputs.auto-commit == 'true' && steps.pre-commit.outcome == 'failure' && steps.auto-commit-action.outputs.changes_detected == 'false' 64 | run: echo "pre-commit failed and no changes detected to auto-commit" && exit 1 65 | shell: bash 66 | -------------------------------------------------------------------------------- /.github/actions/process-coverage-report/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Process Coverage Report' 2 | description: 'Process the generated coverage for further reporting, uses JaCoCo-report plugin' 3 | inputs: 4 | paths: 5 | description: 'Comma separated paths of the generated JaCoCo xml files (supports wildcard glob pattern)' 6 | required: true 7 | token: 8 | description: 'Github personal token to add commits to Pull Request' 9 | required: true 10 | min-coverage-overall: 11 | description: 'The minimum code coverage that is required to pass for overall project' 12 | required: false 13 | default: '80' 14 | min-coverage-changed-files: 15 | description: 'The minimum code coverage that is required to pass for changed files' 16 | required: false 17 | default: '80' 18 | title: 19 | description: 'Optional title for the Pull Request comment' 20 | required: false 21 | update-comment: 22 | description: 'Update the coverage report comment instead of creating new ones. Requires title to works properly.' 23 | required: false 24 | default: 'false' 25 | skip-if-no-changes: 26 | description: "Comment won't be added if there is no coverage information present for the files changed" 27 | required: false 28 | default: 'false' 29 | pass-emoji: 30 | description: 'Github emoji to use for pass status shown when coverage greater than min coverage (should be a Github supported emoji)' 31 | required: false 32 | default: ':green_apple:' 33 | fail-emoji: 34 | description: 'Github emoji to use for fail status shown when coverage lesser than min coverage (should be a Github supported emoji)' 35 | required: false 36 | default: ':x:' 37 | continue-on-error: 38 | description: 'When there is an error do not fail the action, but log a warning' 39 | required: false 40 | default: 'true' 41 | debug-mode: 42 | description: 'Run the action in debug mode and get debug logs printed in console' 43 | required: false 44 | default: 'false' 45 | 46 | outputs: 47 | coverage-overall: 48 | description: 'The overall coverage of the project' 49 | value: ${{ steps.jacoco-aggregate.outputs.coverage-overall }} 50 | coverage-changed-files: 51 | description: 'The total coverage of all changed files' 52 | value: ${{ steps.jacoco-aggregate.outputs.coverage-changed-files }} 53 | 54 | runs: 55 | using: composite 56 | steps: 57 | - uses: madrapps/jacoco-report@50d3aff4548aa991e6753342d9ba291084e63848 # v1.7.2 58 | id: jacoco-aggregate 59 | with: 60 | paths: ${{ inputs.paths }} 61 | token: ${{ inputs.token }} 62 | min-coverage-overall: ${{ inputs.min-coverage-overall }} 63 | min-coverage-changed-files: ${{ inputs.min-coverage-changed-files }} 64 | title: ${{ inputs.title }} 65 | update-comment: ${{ inputs.update-comment }} 66 | skip-if-no-changes: ${{ inputs.skip-if-no-changes }} 67 | pass-emoji: ${{ inputs.pass-emoji }} 68 | fail-emoji: ${{ inputs.fail-emoji }} 69 | continue-on-error: ${{ inputs.continue-on-error }} 70 | debug-mode: ${{ inputs.debug-mode }} 71 | coverage-overall: ${{ inputs.coverage-overall }} 72 | coverage-changed-files: ${{ inputs.coverage-changed-files }} 73 | -------------------------------------------------------------------------------- /.github/actions/rancher/action.yml: -------------------------------------------------------------------------------- 1 | name: "rancher" 2 | description: "Action to register cluster to rancher or detach cluster from rancher" 3 | inputs: 4 | rancher-access-key: 5 | description: 'Rancher API access key' 6 | required: true 7 | rancher-secret-key: 8 | description: 'Rancher API secret key' 9 | required: true 10 | rancher-url: 11 | description: 'Rancher URL' 12 | required: true 13 | action: 14 | description: register or detach 15 | required: true 16 | cluster-name: 17 | description: Name of cluster 18 | required: true 19 | aws-access-key: 20 | description: aws access key, not needed if detach 21 | required: false 22 | aws-secret-key: 23 | description: aws secret key, not needed if detach 24 | required: false 25 | aws-region: 26 | description: aws region, not needed if detach 27 | required: false 28 | runs: 29 | using: "composite" 30 | steps: 31 | - uses: azure/setup-kubectl@3e0aec4d80787158d308d7b364cb1b702e7feb7f # v4.0.0 32 | - name: setup-python 33 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 34 | with: 35 | python-version: "3.9" 36 | cache: pip 37 | - name: install library 38 | shell: bash 39 | run: pip install -r ${{ github.action_path }}/requirements.txt 40 | - name: ${{ inputs.action }} cluster 41 | shell: bash 42 | run: | 43 | if [ "${{ inputs.action }}" = "register" ]; then 44 | export AWS_ACCESS_KEY_ID=${{ inputs.aws-access-key }} 45 | export AWS_SECRET_ACCESS_KEY=${{ inputs.aws-secret-key }} 46 | aws eks --region ${{ inputs.aws-region }} update-kubeconfig --name ${{ inputs.cluster-name }} 47 | fi 48 | export RANCHER2_URL=${{ inputs.rancher-url }} 49 | export RANCHER2_ACCESS_KEY=${{ inputs.rancher-access-key }} 50 | export RANCHER2_SECRET_KEY=${{ inputs.rancher-secret-key }} 51 | export CLUSTER_NAME=${{ inputs.cluster-name }} 52 | python3 ${{ github.action_path }}/rancher_api.py ${{ inputs.action }} 53 | -------------------------------------------------------------------------------- /.github/actions/rancher/rancher_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import subprocess 6 | import rancher 7 | 8 | RANCHER2_ACCESS_KEY = os.getenv('RANCHER2_ACCESS_KEY') 9 | RANCHER2_SECRET_KEY = os.getenv('RANCHER2_SECRET_KEY') 10 | CLUSTER_NAME = os.getenv('CLUSTER_NAME') 11 | RANCHER2_URL = os.getenv('RANCHER2_URL') + '/v3' 12 | 13 | # The first time the API was called, it doesn't work. 14 | _client = rancher.Client(url=RANCHER2_URL, 15 | access_key=RANCHER2_ACCESS_KEY, 16 | secret_key=RANCHER2_SECRET_KEY) 17 | 18 | client = rancher.Client(url=RANCHER2_URL, 19 | access_key=RANCHER2_ACCESS_KEY, 20 | secret_key=RANCHER2_SECRET_KEY) 21 | 22 | 23 | def register_cluster(): 24 | """Register cluster to rancher""" 25 | for cluster in client.list_cluster(): 26 | if cluster['name'] == CLUSTER_NAME: 27 | if cluster['state'] == 'active': 28 | print(f"Cluster {CLUSTER_NAME} already registered, skip register") 29 | return 30 | print(f"Trying to register {CLUSTER_NAME} cluster...") 31 | registation_token = client.list_cluster_registration_token( 32 | clusterId=cluster['id']) 33 | cmd = registation_token['data'][0]['command'] 34 | subprocess.run(cmd, shell=True) 35 | return 36 | print(f"Cluster {CLUSTER_NAME} not found, doing nothing") 37 | 38 | 39 | def get_cluster_id(): 40 | """Get cluster id based on cluster name""" 41 | for cluster in client.list_cluster(): 42 | if cluster['name'] == CLUSTER_NAME: 43 | return cluster['id'] 44 | return False 45 | 46 | 47 | def detach_cluster(): 48 | """Detach cluster from rancher""" 49 | cluster_id = get_cluster_id() 50 | if cluster_id: 51 | cluster = client.by_id_cluster(cluster_id) 52 | client.delete(cluster) 53 | print(f"Cluster {CLUSTER_NAME} detach sent") 54 | else: 55 | print(f"Cluster {CLUSTER_NAME} not found, nothing to detach") 56 | 57 | 58 | if __name__ == "__main__": 59 | option = sys.argv[1] 60 | 61 | # register require kubeconfig setup 62 | if option == "register": 63 | register_cluster() 64 | elif option == "detach": 65 | detach_cluster() 66 | -------------------------------------------------------------------------------- /.github/actions/rancher/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/rancher/client-python.git@f617457722f95eded2a74b301ab08d79502a5c3f 2 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true 4 | }, 5 | extends: [ 6 | 'eslint:recommended', 7 | 'plugin:@typescript-eslint/eslint-recommended', 8 | 'plugin:@typescript-eslint/recommended' 9 | ], 10 | parser: '@typescript-eslint/parser', 11 | parserOptions: { 12 | 'project': 'tsconfig.json', 13 | 'sourceType': 'module' 14 | }, 15 | plugins: [ 16 | '@typescript-eslint' 17 | ], 18 | rules: { 19 | 'no-trailing-spaces': 'error', 20 | 'no-console': 'off', 21 | 22 | '@typescript-eslint/semi': ['error', 'never'], 23 | '@typescript-eslint/indent': ['error', 2], 24 | '@typescript-eslint/member-delimiter-style': 'off', 25 | '@typescript-eslint/no-explicit-any': 'warn', 26 | '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': 'next|res|req' }], 27 | 28 | 'func-call-spacing': 'off', 29 | '@typescript-eslint/func-call-spacing': 'error', 30 | 31 | 'quotes': 'off', 32 | '@typescript-eslint/quotes': ['error', 'single'], 33 | 34 | 'comma-spacing': 'off', 35 | '@typescript-eslint/comma-spacing': ['error'] 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | .idea 4 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action for aggregate a release notes 2 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/action.yml: -------------------------------------------------------------------------------- 1 | name: Release Notes Aggregator 2 | description: 'Creates a release notes by aggregating external repositories release notes.' 3 | inputs: 4 | external-repo: 5 | description: 'The name of the external repositories to aggregate release notes from' 6 | required: true 7 | from-external-version: 8 | description: 'The version to generate external release notes from' 9 | required: false 10 | to-external-version: 11 | description: 'The version to generate external release notes to' 12 | required: false 13 | release-id: 14 | description: 'The release ID of the origin repository' 15 | required: true 16 | token: 17 | description: 'GitHub Token for accessing GHCR.' 18 | required: true 19 | 20 | runs: 21 | using: 'node20' 22 | main: 'dist/index.js' 23 | 24 | branding: 25 | color: purple 26 | icon: send 27 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "release-notes-aggregator", 3 | "version": "0.0.1", 4 | "description": "GitHub Action to aggregate release notes from multiple repositories", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "ncc build src/main.ts -o dist", 8 | "lint": "eslint src/", 9 | "lint-fix": "eslint src/ --fix" 10 | }, 11 | "keywords": [ 12 | "github", 13 | "actions" 14 | ], 15 | "author": "Maurizio Vitale", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "@actions/core": "1.10.1", 19 | "@actions/github": "6.0.0", 20 | "@typescript-eslint/eslint-plugin": "7.7.0", 21 | "@typescript-eslint/parser": "7.7.0", 22 | "@vercel/ncc": "0.38.1", 23 | "eslint": "8.57.0", 24 | "typescript": "5.4.5" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/src/debug.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * @license 3 | * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import * as core from '@actions/core' 19 | 20 | export function debug(title: string, content: any) { 21 | if (core.isDebug()) { 22 | core.info(`::group::${title}`) 23 | try { 24 | core.debug(JSON.stringify(content, null, 3)) 25 | } catch(e) { 26 | core.debug(`Failed to serialize object, trying toString. Cause: ${e}`) 27 | core.debug(content?.toString()) 28 | } 29 | core.info('::endgroup::') 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/src/main.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * @license 3 | * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import * as core from '@actions/core' 19 | import { getArgs } from './utils' 20 | import { WorkflowHandler } from './workflow-handler' 21 | 22 | async function run(): Promise { 23 | try { 24 | const args = getArgs() 25 | const workflowHandler = new WorkflowHandler(args.token, args.owner, args.repo, args.externalRepo, args.generateRNfromVersion, args.generateRNtoVersion, args.releaseId) 26 | 27 | try { 28 | await workflowHandler.generateReleaseNotesFromExternalRepo(); 29 | 30 | await workflowHandler.aggregateExternalReleaseToCurrentReleaseNotes(); 31 | 32 | await workflowHandler.updateReleaseNotes(); 33 | } catch(e: any) { 34 | core.warning(`Failed to generate the external release note: ${e.message}`); 35 | } 36 | 37 | } catch (error: any) { 38 | core.setFailed(error.message) 39 | } 40 | } 41 | 42 | run() 43 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/src/utils.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * @license 3 | * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import * as core from '@actions/core' 19 | import * as github from '@actions/github' 20 | 21 | function parse(inputsJson: string) { 22 | if(inputsJson) { 23 | try { 24 | return JSON.parse(inputsJson) 25 | } catch(e) { 26 | throw new Error(`Failed to parse 'inputs' parameter. Must be a valid JSON.\nCause: ${e}`) 27 | } 28 | } 29 | return {} 30 | } 31 | export function getArgs() { 32 | // Required inputs 33 | const token = core.getInput('token') 34 | const workflowRef = core.getInput('workflow') 35 | // Optional inputs, with defaults 36 | const ref = core.getInput('ref') || github.context.ref 37 | const [owner, repo] = [github.context.repo.owner, github.context.repo.repo] 38 | 39 | // Decode inputs, this MUST be a valid JSON string 40 | const inputs = parse(core.getInput('inputs')) 41 | const externalRepo = core.getInput('external-repo') 42 | const generateRNfromVersion = core.getInput('from-external-version') 43 | const generateRNtoVersion = core.getInput('to-external-version') 44 | const releaseId = core.getInput('release-id') 45 | 46 | return { 47 | token, 48 | owner, 49 | repo, 50 | inputs, 51 | externalRepo, 52 | generateRNfromVersion, 53 | generateRNtoVersion, 54 | releaseId, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/src/workflow-handler.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * @license 3 | * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import * as core from '@actions/core' 19 | import * as github from '@actions/github' 20 | import { debug } from './debug' 21 | 22 | export class WorkflowHandler { 23 | private octokit: any 24 | private releaseNotesExternal: string = ''; 25 | private aggregatedReleaseNotes: string = ''; 26 | 27 | constructor(token: string, 28 | private owner: string, 29 | private repo: string, 30 | private externalRepo: string, 31 | private generateRNfromVersion: string, 32 | private generateRNtoVersion: string, 33 | private releaseId: string) { 34 | 35 | // Get octokit client for making API calls 36 | this.octokit = github.getOctokit(token) 37 | } 38 | 39 | async generateReleaseNotesFromExternalRepo(): Promise { 40 | try { 41 | const releaseNotesExternalResponse = await this.octokit.rest.repos.generateReleaseNotes({ 42 | owner: this.owner, 43 | repo: this.externalRepo, 44 | tag_name: this.generateRNtoVersion, 45 | previous_tag_name: this.generateRNfromVersion, 46 | }); 47 | 48 | this.releaseNotesExternal = releaseNotesExternalResponse.data.body; 49 | debug('Release Notes External', this.releaseNotesExternal) 50 | 51 | } catch (error: any) { 52 | debug('External Release Notes in status error', error) 53 | throw error 54 | } 55 | } 56 | 57 | async aggregateExternalReleaseToCurrentReleaseNotes(): Promise { 58 | try { 59 | const currentRelease = await this.octokit.rest.repos.getRelease({ 60 | owner: this.owner, 61 | repo: this.repo, 62 | release_id: this.releaseId, 63 | }); 64 | debug('Current Release Notes:', currentRelease.data.body); 65 | 66 | // concatenate the external release to the current by using the repo name as a header 67 | this.aggregatedReleaseNotes = `${currentRelease.data.body}\n\n---\n\n## ${this.externalRepo}\n\n${this.releaseNotesExternal}`; 68 | } catch (error: any) { 69 | debug('Release Notes aggregation in status error', error) 70 | throw error 71 | } 72 | } 73 | 74 | async updateReleaseNotes(): Promise { 75 | try { 76 | await this.octokit.rest.repos.updateRelease({ 77 | owner: this.owner, 78 | repo: this.repo, 79 | release_id: this.releaseId, 80 | body: this.aggregatedReleaseNotes, 81 | draft: false, 82 | prerelease: false, 83 | }); 84 | } catch (error: any) { 85 | debug('Release Notes update in status error', error) 86 | throw error 87 | } 88 | 89 | debug(`Conclusion`,`Release notes for the external repo ${this.externalRepo} was aggregated successfully`); 90 | 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /.github/actions/release-notes-aggregator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "rootDir": "./src", 6 | "strict": true, 7 | "noImplicitAny": true, 8 | "esModuleInterop": true 9 | }, 10 | "exclude": ["node_modules", "**/*.test.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /.github/actions/reportportal-prepare/action.yml: -------------------------------------------------------------------------------- 1 | name: Prepare Report Portal 2 | description: Prepares Report Portal configuration information 3 | inputs: 4 | rp-launch-prefix: 5 | description: The launch key prefix for Report Portal 6 | required: false 7 | rp-token: 8 | description: The token for Report Portal 9 | required: false 10 | rp-url: 11 | description: The URL for Report Portal (should not be a secret) 12 | required: false 13 | default: "https://reportportal.envalfresco.com" 14 | rp-project: 15 | description: The project used in Report Portal 16 | required: false 17 | rp-extra-attributes: 18 | description: Extra attributes for Report Portal 19 | required: false 20 | rp-use-static-launch-name: 21 | description: If set, the rp-launch-prefix will be used as the full launch name in Report Portal 22 | required: false 23 | default: "false" 24 | auto-configure: 25 | description: >- 26 | Enables automated default configuration (adds default GitHub context 27 | information in launch key and attributes) 28 | required: false 29 | default: "true" 30 | 31 | outputs: 32 | enabled: 33 | description: "'true' if Report Portal is configured" 34 | value: ${{ steps.info.outputs.enabled }} 35 | key: 36 | description: The Report Portal launch key 37 | value: ${{ steps.info.outputs.key }} 38 | url: 39 | description: The Report Portal launch URL 40 | value: ${{ steps.info.outputs.url }} 41 | mvn-opts: 42 | description: The Report Portal maven options 43 | value: ${{ steps.info.outputs.mvn-opts }} 44 | 45 | runs: 46 | using: composite 47 | steps: 48 | - name: Get branch name 49 | uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@v8.23.2 50 | 51 | - name: Compute Report Portal input info 52 | id: info 53 | shell: bash 54 | env: 55 | RP_LAUNCH_PREFIX: ${{ inputs.rp-launch-prefix }} 56 | RP_TOKEN: ${{ inputs.rp-token }} 57 | RP_URL: ${{ inputs.rp-url }} 58 | RP_PROJECT: ${{ inputs.rp-project }} 59 | RP_EXTRA_ATTRIBUTES: ${{ inputs.rp-extra-attributes }} 60 | AUTO: ${{ inputs.auto-configure }} 61 | USE_STATIC_LAUNCH_NAME: ${{ inputs.rp-use-static-launch-name }} 62 | run: ${{ github.action_path }}/get-rp-input.sh 63 | -------------------------------------------------------------------------------- /.github/actions/reportportal-prepare/get-rp-input.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [[ -n "$RP_LAUNCH_PREFIX" && -n "$RP_TOKEN" && -n "$RP_URL" && -n "$RP_PROJECT" ]]; then 4 | echo "enabled=true" >> $GITHUB_OUTPUT 5 | 6 | RP_LAUNCH_KEY="$RP_LAUNCH_PREFIX" 7 | if [[ "$AUTO" == "true" && "$USE_STATIC_LAUNCH_NAME" == "false" ]]; then 8 | RP_LAUNCH_KEY="$RP_LAUNCH_PREFIX-$GITHUB_EVENT_NAME-$GITHUB_RUN_ID" 9 | fi 10 | echo "key=$RP_LAUNCH_KEY" >> $GITHUB_OUTPUT 11 | 12 | URL="$RP_URL/ui/#$RP_PROJECT/launches/all" 13 | echo "url=$URL" >> $GITHUB_OUTPUT 14 | 15 | echo "Report Portal key=$RP_LAUNCH_KEY, url=$URL" 16 | 17 | RUN_TITLE="Run on GitHub Actions $GITHUB_RUN_ID" 18 | if [[ "$GITHUB_RUN_ATTEMPT" != '1' ]]; then 19 | RUN_TITLE+=" (attempt #$GITHUB_RUN_ATTEMPT)" 20 | fi 21 | RUN_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/attempts/$GITHUB_RUN_ATTEMPT" 22 | 23 | OPTS='"'-Drp.launch="$RP_LAUNCH_KEY"'"' 24 | OPTS+=' "'-Drp.uuid="$RP_TOKEN"'"' 25 | OPTS+=' "'-Drp.endpoint="$RP_URL"'"' 26 | OPTS+=' "'-Drp.project="$RP_PROJECT"'"' 27 | if [[ "$AUTO" == "true" ]]; then 28 | OPTS+=' "'-Drp.description=["$RUN_TITLE"]\("$RUN_URL"\)'"' 29 | OPTS+=' "'-Drp.attributes='branch:'"$BRANCH_NAME"';event:'"$GITHUB_EVENT_NAME"';repository:'"$GITHUB_REPOSITORY"';ghrun:'"$GITHUB_RUN_ID"';run:'"$RP_LAUNCH_KEY$RP_EXTRA_ATTRIBUTES"'"' 30 | else 31 | OPTS+=' "'-Drp.attributes='ghrun:'"$GITHUB_RUN_ID$RP_EXTRA_ATTRIBUTES"'"' 32 | fi 33 | 34 | echo "mvn-opts=$OPTS" >> $GITHUB_OUTPUT 35 | else 36 | echo "Report Portal not enabled: configuration not available" 37 | 38 | echo "enabled=false" >> $GITHUB_OUTPUT 39 | echo "key=" >> $GITHUB_OUTPUT 40 | echo "url=" >> $GITHUB_OUTPUT 41 | echo "mvnopts=" >> $GITHUB_OUTPUT 42 | fi 43 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/action.yml: -------------------------------------------------------------------------------- 1 | name: Summarize Report Portal 2 | description: Computes post-tests summary and slack message 3 | inputs: 4 | tests-outcome: 5 | description: Tests outcome ('success', 'failure',...) 6 | required: true 7 | rp-launch-key: 8 | description: The launch key for Report Portal 9 | required: false 10 | rp-token: 11 | description: The token for Report Portal 12 | required: false 13 | rp-url: 14 | description: The URL for Report Portal (should not be a secret) 15 | required: false 16 | default: "https://reportportal.envalfresco.com" 17 | rp-project: 18 | description: The project used in Report Portal 19 | required: false 20 | default: "alfresco-process-acceptance-tests" 21 | 22 | outputs: 23 | slack-message: 24 | description: Outcome message for slack 25 | value: ${{ steps.slack-message.outputs.message }} 26 | teams-message: 27 | description: Outcome message for teams 28 | value: ${{ steps.teams-message.outputs.message }} 29 | 30 | runs: 31 | using: composite 32 | steps: 33 | - name: Get Report Portal output info 34 | id: rp-output 35 | shell: bash 36 | env: 37 | RP_LAUNCH_KEY: ${{ inputs.rp-launch-key }} 38 | RP_TOKEN: ${{ inputs.rp-token }} 39 | RP_URL: ${{ inputs.rp-url }} 40 | RP_PROJECT: ${{ inputs.rp-project }} 41 | run: ${{ github.action_path }}/get-rp-output.sh 42 | 43 | - name: Update step summary 44 | shell: bash 45 | env: 46 | OUTCOME: ${{ inputs.tests-outcome }} 47 | RP_LAUNCH_KEY: ${{ inputs.rp-launch-key }} 48 | RP_CONTENT: ${{ steps.rp-output.outputs.content }} 49 | RP_LAUNCH_URL: ${{ steps.rp-output.outputs.url }} 50 | run: ${{ github.action_path }}/write-step-summary.sh 51 | 52 | - name: Compute Slack message 53 | id: slack-message 54 | shell: bash 55 | env: 56 | RP_LAUNCH_KEY: ${{ inputs.rp-launch-key }} 57 | RP_CONTENT: ${{ steps.rp-output.outputs.content }} 58 | RP_LAUNCH_URL: ${{ steps.rp-output.outputs.url }} 59 | run: ${{ github.action_path }}/get-slack-message.sh 60 | 61 | - name: Compute Teams message 62 | id: teams-message 63 | shell: bash 64 | env: 65 | RP_LAUNCH_KEY: ${{ inputs.rp-launch-key }} 66 | RP_CONTENT: ${{ steps.rp-output.outputs.content }} 67 | RP_LAUNCH_URL: ${{ steps.rp-output.outputs.url }} 68 | run: ${{ github.action_path }}/get-teams-message.sh 69 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/get-rp-output.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | CONTENT='' 4 | URL='' 5 | 6 | # support spaces on launch key 7 | urlEncode() { 8 | echo $1 | python -c "import urllib.parse, sys; print(urllib.parse.quote(sys.stdin.read()))" | sed -E 's/(.*).../\1/' | tr -d '\n' 9 | } 10 | 11 | if [[ -n "$RP_LAUNCH_KEY" && -n "$RP_TOKEN" && -n "$RP_URL" && -n "$RP_PROJECT" ]] 12 | then 13 | echo "enabled=true" >> $GITHUB_OUTPUT 14 | 15 | CONTENT=$(curl -s -G -X GET "$RP_URL/api/v1/$RP_PROJECT/launch" \ 16 | -d "filter.cnt.name=$(urlEncode "$RP_LAUNCH_KEY")" \ 17 | -d "filter.has.compositeAttribute=ghrun:$GITHUB_RUN_ID" \ 18 | -d "page.sort=startTime,number,DESC" \ 19 | -H "Authorization: bearer $RP_TOKEN" \ 20 | ) || CONTENT='' 21 | 22 | URL="$RP_URL/ui/#$RP_PROJECT/launches/all" 23 | else 24 | echo "Report Portal not enabled: configuration not available" 25 | 26 | echo "enabled=false" >> $GITHUB_OUTPUT 27 | fi 28 | 29 | echo "content=$CONTENT" >> $GITHUB_OUTPUT 30 | echo "url=$URL" >> $GITHUB_OUTPUT 31 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/get-slack-message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [[ -n "$RP_LAUNCH_KEY" ]]; then 4 | 5 | NB=$(echo "$RP_CONTENT" | jq -r '.page.totalElements // "0"') 6 | if [[ "$NB" == "0" || -z "$NB" ]]; then 7 | MSG+="No report found for key "'`'"$RP_LAUNCH_KEY"'`'"." 8 | MSG+="\nSee <$RP_LAUNCH_URL|latest reports>." 9 | elif [ "$NB" == "1" ]; then 10 | RP_LAUNCH_ID=$(echo "$RP_CONTENT" | jq -r '.content[0].id // empty') 11 | STATUS=$(echo "$RP_CONTENT" | jq -r '.content[0].status // empty') 12 | [[ "$STATUS" == 'PASSED' ]] && ICON="✅" || ICON="❌" 13 | MSG+="See <$RP_LAUNCH_URL/$RP_LAUNCH_ID|report> $ICON" 14 | else 15 | MSG+="$NB reports found for key "'`'"$RP_LAUNCH_KEY"'`'"." 16 | while read -r id ; do 17 | read -r number 18 | read -r status 19 | case $status in 20 | PASSED) 21 | status_icon="✅" ;; 22 | FAILED) 23 | status_icon="❌" 24 | ;; 25 | *) 26 | status_icon="$status" 27 | ;; 28 | esac 29 | MSG+="\n<$RP_LAUNCH_URL/$id|Report #$number> $status_icon" 30 | done < <(echo "$RP_CONTENT" | jq -r '.content[] | .id, .number, .status') 31 | fi 32 | fi 33 | 34 | echo "message=$MSG" >> $GITHUB_OUTPUT 35 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/get-teams-message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [[ -n "$RP_LAUNCH_KEY" ]]; then 4 | 5 | NB=$(echo "$RP_CONTENT" | jq -r '.page.totalElements // "0"') 6 | if [[ "$NB" == "0" || -z "$NB" ]]; then 7 | MSG+="No report found for key $RP_LAUNCH_KEY." 8 | MSG+="\n\nSee [latest reports]($RP_LAUNCH_URL)." 9 | elif [ "$NB" == "1" ]; then 10 | RP_LAUNCH_ID=$(echo "$RP_CONTENT" | jq -r '.content[0].id // empty') 11 | STATUS=$(echo "$RP_CONTENT" | jq -r '.content[0].status // empty') 12 | [[ "$STATUS" == 'PASSED' ]] && ICON="✅" || ICON="❌" 13 | MSG+="See [report]($RP_LAUNCH_URL/$RP_LAUNCH_ID) $ICON" 14 | else 15 | MSG+="$NB reports found for key $RP_LAUNCH_KEY." 16 | while read -r id ; do 17 | read -r number 18 | read -r status 19 | case $status in 20 | PASSED) 21 | status_icon="✅" ;; 22 | FAILED) 23 | status_icon="❌" 24 | ;; 25 | *) 26 | status_icon="$status" 27 | ;; 28 | esac 29 | MSG+="\n\n[Report #$number]($RP_LAUNCH_URL/$id) $status_icon" 30 | done < <(echo "$RP_CONTENT" | jq -r '.content[] | .id, .number, .status') 31 | fi 32 | fi 33 | 34 | echo "message=$MSG" >> $GITHUB_OUTPUT 35 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/tests/empty-launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": [], 3 | "page": { "number": 1, "size": 20, "totalElements": 0, "totalPages": 0 } 4 | } 5 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/tests/get-rp-output.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | # Runs everywhere 3 | DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 4 | PATH="$DIR/..:$PATH" 5 | 6 | export GITHUB_OUTPUT="$BATS_TMPDIR"/test-get-rp-output_ghoutput_"$RANDOM"'.log' 7 | > $GITHUB_OUTPUT 8 | 9 | export RP_LAUNCH_KEY=my-tests-push-3665876492 10 | export RP_TOKEN=tok 11 | export RP_URL=https://rpserver:8080 12 | 13 | export ECHO_DISABLED="Report Portal not enabled: configuration not available" 14 | export DISABLED=$(cat << BATS 15 | enabled=false 16 | content= 17 | url= 18 | BATS 19 | ) 20 | } 21 | 22 | teardown() { 23 | rm -f $GITHUB_OUTPUT 24 | } 25 | 26 | @test "rp disabled (no key)" { 27 | export RP_LAUNCH_KEY="" 28 | run get-rp-output.sh 29 | [ "$status" -eq 0 ] 30 | [ "$(< $GITHUB_OUTPUT)" = "$DISABLED" ] 31 | [ "$output" = "$ECHO_DISABLED" ] 32 | } 33 | 34 | @test "rp disabled (no token)" { 35 | export RP_TOKEN="" 36 | run get-rp-output.sh 37 | [ "$status" -eq 0 ] 38 | [ "$(< $GITHUB_OUTPUT)" = "$DISABLED" ] 39 | [ "$output" = "$ECHO_DISABLED" ] 40 | } 41 | 42 | @test "rp disabled (no url)" { 43 | export RP_URL="" 44 | run get-rp-output.sh 45 | [ "$status" -eq 0 ] 46 | [ "$(< $GITHUB_OUTPUT)" = "$DISABLED" ] 47 | [ "$output" = "$ECHO_DISABLED" ] 48 | } 49 | 50 | @test "rp disabled (no project)" { 51 | export RP_PROJECT="" 52 | run get-rp-output.sh 53 | [ "$status" -eq 0 ] 54 | [ "$(< $GITHUB_OUTPUT)" = "$DISABLED" ] 55 | [ "$output" = "$ECHO_DISABLED" ] 56 | } 57 | 58 | @test "slack message rp disabled" { 59 | export RP_LAUNCH_KEY="" 60 | run get-slack-message.sh 61 | [ "$status" -eq 0 ] 62 | 63 | expected="message=" 64 | [ "$(< $GITHUB_OUTPUT)" = "$expected" ] 65 | } 66 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/tests/get-slack-message.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | # Runs everywhere 3 | DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 4 | PATH="$DIR/..:$PATH" 5 | 6 | export GITHUB_OUTPUT="$BATS_TMPDIR"/test-get-slack-message_ghoutput_"$RANDOM"'.log' 7 | > $GITHUB_OUTPUT 8 | 9 | export RP_LAUNCH_KEY=my-tests-push-3665876492 10 | export RP_TOKEN=tok 11 | export RP_URL=https://rpserver:8080 12 | 13 | export RP_CONTENT="" 14 | export RP_LAUNCH_URL=https://rpserver:8080/ui/#my-project/launches/all 15 | 16 | export NO_MESSAGE="message=" 17 | export KEY_NO_REPORT="message=No report found for key \`my-tests-push-3665876492\`.\nSee ." 18 | export SINGLE_REPORT="message=See ✅" 19 | export MULTIPLE_REPORTS=$(cat << BATS 20 | message=3 reports found for key \`my-tests-push-3665876492\`.\n ❌\n WHATEVER_STATUS\n ✅ 21 | BATS 22 | ) 23 | } 24 | 25 | teardown() { 26 | rm -f $GITHUB_OUTPUT 27 | } 28 | 29 | @test "slack message rp disabled" { 30 | export RP_LAUNCH_KEY="" 31 | run get-slack-message.sh 32 | [ "$status" -eq 0 ] 33 | echo "$(< $GITHUB_OUTPUT)" 34 | [ "$(< $GITHUB_OUTPUT)" = "$NO_MESSAGE" ] 35 | } 36 | 37 | @test "slack message no launch id" { 38 | run get-slack-message.sh 39 | [ "$status" -eq 0 ] 40 | echo "$(< $GITHUB_OUTPUT)" 41 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 42 | } 43 | 44 | @test "slack message single" { 45 | export RP_CONTENT="$(< $BATS_TEST_DIRNAME/sample-launch.json)" 46 | run get-slack-message.sh 47 | [ "$status" -eq 0 ] 48 | echo "$(< $GITHUB_OUTPUT)" 49 | [ "$(< $GITHUB_OUTPUT)" = "$SINGLE_REPORT" ] 50 | } 51 | 52 | @test "slack message multiple" { 53 | export RP_CONTENT="$(< $BATS_TEST_DIRNAME/sample-launches.json)" 54 | run get-slack-message.sh 55 | [ "$status" -eq 0 ] 56 | echo "$(< $GITHUB_OUTPUT)" 57 | [ "$(< $GITHUB_OUTPUT)" = "$MULTIPLE_REPORTS" ] 58 | } 59 | 60 | @test "slack message rp failure no results" { 61 | run get-slack-message.sh 62 | [ "$status" -eq 0 ] 63 | echo "$(< $GITHUB_OUTPUT)" 64 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 65 | } 66 | 67 | @test "slack message rp failure no results empty json" { 68 | export RP_CONTENT="{}" 69 | run get-slack-message.sh 70 | [ "$status" -eq 0 ] 71 | echo "$(< $GITHUB_OUTPUT)" 72 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 73 | } 74 | 75 | @test "slack message rp success no results" { 76 | export OUTCOME="success" 77 | export RP_CONTENT="$(< $BATS_TEST_DIRNAME/empty-launch.json)" 78 | run get-slack-message.sh 79 | [ "$status" -eq 0 ] 80 | echo "$(< $GITHUB_OUTPUT)" 81 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 82 | } 83 | 84 | @test "slack message rp failure no results empty json no launch key" { 85 | export RP_LAUNCH_KEY="" 86 | export RP_CONTENT="{}" 87 | run get-slack-message.sh 88 | [ "$status" -eq 0 ] 89 | echo "$(< $GITHUB_OUTPUT)" 90 | [ "$(< $GITHUB_OUTPUT)" = "$NO_MESSAGE" ] 91 | 92 | } 93 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/tests/get-teams-message.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | # Runs everywhere 3 | DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 4 | PATH="$DIR/..:$PATH" 5 | 6 | export GITHUB_OUTPUT="$BATS_TMPDIR"/test-get-teams-message_ghoutput_"$RANDOM"'.log' 7 | > $GITHUB_OUTPUT 8 | 9 | export RP_LAUNCH_KEY=my-tests-push-3665876492 10 | export RP_TOKEN=tok 11 | export RP_URL=https://rpserver:8080 12 | 13 | export RP_CONTENT="" 14 | export RP_LAUNCH_URL=https://rpserver:8080/ui/#my-project/launches/all 15 | 16 | export NO_MESSAGE="message=" 17 | export KEY_NO_REPORT="message=No report found for key my-tests-push-3665876492.\n\nSee [latest reports](https://rpserver:8080/ui/#my-project/launches/all)." 18 | export SINGLE_REPORT="message=See [report](https://rpserver:8080/ui/#my-project/launches/all/88) ✅" 19 | export MULTIPLE_REPORTS=$(cat << BATS 20 | message=3 reports found for key my-tests-push-3665876492.\n\n[Report #3](https://rpserver:8080/ui/#my-project/launches/all/91) ❌\n\n[Report #2](https://rpserver:8080/ui/#my-project/launches/all/90) WHATEVER_STATUS\n\n[Report #1](https://rpserver:8080/ui/#my-project/launches/all/89) ✅ 21 | BATS 22 | ) 23 | } 24 | 25 | teardown() { 26 | rm -f $GITHUB_OUTPUT 27 | } 28 | 29 | @test "teams message rp disabled" { 30 | export RP_LAUNCH_KEY="" 31 | run get-teams-message.sh 32 | [ "$status" -eq 0 ] 33 | echo "$(< $GITHUB_OUTPUT)" 34 | [ "$(< $GITHUB_OUTPUT)" = "$NO_MESSAGE" ] 35 | } 36 | 37 | @test "teams message no launch id" { 38 | run get-teams-message.sh 39 | [ "$status" -eq 0 ] 40 | echo "$(< $GITHUB_OUTPUT)" 41 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 42 | } 43 | 44 | @test "teams message single" { 45 | export RP_CONTENT="$(< $BATS_TEST_DIRNAME/sample-launch.json)" 46 | run get-teams-message.sh 47 | [ "$status" -eq 0 ] 48 | echo "$(< $GITHUB_OUTPUT)" 49 | [ "$(< $GITHUB_OUTPUT)" = "$SINGLE_REPORT" ] 50 | } 51 | 52 | @test "teams message multiple" { 53 | export RP_CONTENT="$(< $BATS_TEST_DIRNAME/sample-launches.json)" 54 | run get-teams-message.sh 55 | [ "$status" -eq 0 ] 56 | echo "$(< $GITHUB_OUTPUT)" 57 | [ "$(< $GITHUB_OUTPUT)" = "$MULTIPLE_REPORTS" ] 58 | } 59 | 60 | @test "teams message rp failure no results" { 61 | run get-teams-message.sh 62 | [ "$status" -eq 0 ] 63 | echo "$(< $GITHUB_OUTPUT)" 64 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 65 | } 66 | 67 | @test "teams message rp failure no results empty json" { 68 | export RP_CONTENT="{}" 69 | run get-teams-message.sh 70 | [ "$status" -eq 0 ] 71 | echo "$(< $GITHUB_OUTPUT)" 72 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 73 | } 74 | 75 | @test "teams message rp success no results" { 76 | export OUTCOME="success" 77 | export RP_CONTENT="$(< $BATS_TEST_DIRNAME/empty-launch.json)" 78 | run get-teams-message.sh 79 | [ "$status" -eq 0 ] 80 | echo "$(< $GITHUB_OUTPUT)" 81 | [ "$(< $GITHUB_OUTPUT)" = "$KEY_NO_REPORT" ] 82 | } 83 | 84 | @test "teams message rp failure no results empty json no launch key" { 85 | export RP_LAUNCH_KEY="" 86 | export RP_CONTENT="{}" 87 | run get-teams-message.sh 88 | [ "$status" -eq 0 ] 89 | echo "$(< $GITHUB_OUTPUT)" 90 | [ "$(< $GITHUB_OUTPUT)" = "$NO_MESSAGE" ] 91 | 92 | } 93 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/tests/sample-launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": [ 3 | { 4 | "owner": "superadmin", 5 | "share": false, 6 | "id": 88, 7 | "uuid": "5bc0b4ff-35ce-49c5-a45f-523aab12f909", 8 | "name": "alfresco-process-identity-adapter-push-14720", 9 | "number": 1, 10 | "startTime": 1670786584337, 11 | "endTime": 1670786584753, 12 | "lastModified": 1670786584780, 13 | "status": "PASSED", 14 | "statistics": { 15 | "executions": { "total": 2, "passed": 2 }, 16 | "defects": {} 17 | }, 18 | "attributes": [], 19 | "mode": "DEFAULT", 20 | "analysing": [], 21 | "approximateDuration": 0.0, 22 | "hasRetries": false, 23 | "rerun": false 24 | } 25 | ], 26 | "page": { "number": 1, "size": 20, "totalElements": 1, "totalPages": 1 } 27 | } 28 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/tests/sample-launches.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": [ 3 | { 4 | "owner": "superadmin", 5 | "share": false, 6 | "id": 91, 7 | "uuid": "6027cfb5-af7c-43e0-a0ee-e4c913366a40", 8 | "name": "alfresco-process-identity-adapter-push-15259", 9 | "number": 3, 10 | "startTime": 1670786668191, 11 | "endTime": 1670786726330, 12 | "lastModified": 1670786726346, 13 | "status": "FAILED", 14 | "statistics": { 15 | "executions": { "total": 42, "failed": 1, "passed": 41 }, 16 | "defects": { "to_investigate": { "total": 1, "ti001": 1 } } 17 | }, 18 | "attributes": [], 19 | "mode": "DEFAULT", 20 | "analysing": [], 21 | "approximateDuration": 7.804, 22 | "hasRetries": false, 23 | "rerun": false 24 | }, 25 | { 26 | "owner": "superadmin", 27 | "share": false, 28 | "id": 90, 29 | "uuid": "727fbe2c-78d0-45ac-a960-7ae974e3631d", 30 | "name": "alfresco-process-identity-adapter-push-15259", 31 | "number": 2, 32 | "startTime": 1670786647457, 33 | "endTime": 1670786662721, 34 | "lastModified": 1670786662739, 35 | "status": "WHATEVER_STATUS", 36 | "statistics": { 37 | "executions": { "total": 10, "failed": 1, "passed": 9 }, 38 | "defects": { "to_investigate": { "total": 1, "ti001": 1 } } 39 | }, 40 | "attributes": [], 41 | "mode": "DEFAULT", 42 | "analysing": [], 43 | "approximateDuration": 0.344, 44 | "hasRetries": false, 45 | "rerun": false 46 | }, 47 | { 48 | "owner": "superadmin", 49 | "share": false, 50 | "id": 89, 51 | "uuid": "7c0c2b85-9702-432a-b7a2-862befe9a3b8", 52 | "name": "alfresco-process-identity-adapter-push-15259", 53 | "number": 1, 54 | "startTime": 1670786645268, 55 | "endTime": 1670786645612, 56 | "lastModified": 1670786645646, 57 | "status": "PASSED", 58 | "statistics": { 59 | "executions": { "total": 2, "passed": 2 }, 60 | "defects": {} 61 | }, 62 | "attributes": [], 63 | "mode": "DEFAULT", 64 | "analysing": [], 65 | "approximateDuration": 0.0, 66 | "hasRetries": false, 67 | "rerun": false 68 | } 69 | ], 70 | "page": { "number": 1, "size": 20, "totalElements": 3, "totalPages": 1 } 71 | } 72 | -------------------------------------------------------------------------------- /.github/actions/reportportal-summarize/write-step-summary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | [[ "$OUTCOME" == 'success' ]] && ICON="✅" || ICON="❌" 4 | 5 | echo "#### 📋 Results: $ICON" >> $GITHUB_STEP_SUMMARY 6 | 7 | if [[ -n "$RP_LAUNCH_KEY" ]]; then 8 | NB=$(echo "$RP_CONTENT" | jq -r '.page.totalElements // "0"') 9 | if [[ "$NB" == "0" || -z "$NB" ]]; then 10 | echo "- No report found for key "'`'"$RP_LAUNCH_KEY"'`' >> $GITHUB_STEP_SUMMARY 11 | echo "- See [latest reports]($RP_LAUNCH_URL)" >> $GITHUB_STEP_SUMMARY 12 | elif [ "$NB" == "1" ]; then 13 | RP_LAUNCH_ID=$(echo "$RP_CONTENT" | jq -r '.content[0].id // empty') 14 | echo "See [report]($RP_LAUNCH_URL/$RP_LAUNCH_ID)" >> $GITHUB_STEP_SUMMARY 15 | else 16 | echo "$NB reports found for key "'`'"$RP_LAUNCH_KEY"'`' >> $GITHUB_STEP_SUMMARY 17 | while read -r id ; do 18 | read -r number 19 | read -r status 20 | case $status in 21 | PASSED) 22 | sstatus="✅" ;; 23 | FAILED) 24 | sstatus="❌" 25 | ;; 26 | *) 27 | sstatus="$status" 28 | ;; 29 | esac 30 | echo "- [Report #$number]($RP_LAUNCH_URL/$id) $sstatus" >> $GITHUB_STEP_SUMMARY 31 | done < <(echo "$RP_CONTENT" | jq -r '.content[] | .id, .number, .status') 32 | fi 33 | fi 34 | -------------------------------------------------------------------------------- /.github/actions/resolve-preview-name/action.yml: -------------------------------------------------------------------------------- 1 | name: "Resolve preview name" 2 | description: "Resolve preview name based on the PR number and run number" 3 | outputs: 4 | preview-name: 5 | description: "Preview name resolved for the current context" 6 | value: ${{ steps.resolve-preview-name.outputs.preview-name }} 7 | runs: 8 | using: "composite" 9 | steps: 10 | - name: Resolve preview name 11 | id: resolve-preview-name 12 | shell: bash 13 | run: ${{ github.action_path }}/resolve-preview-name.sh 14 | -------------------------------------------------------------------------------- /.github/actions/resolve-preview-name/resolve-preview-name.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | test "${GITHUB_PR_NUMBER}" && PREVIEW_NAME=pr-${GITHUB_PR_NUMBER} || PREVIEW_NAME=gh-$GITHUB_RUN_NUMBER 5 | echo Preview name: "$PREVIEW_NAME" 6 | echo "preview-name=$PREVIEW_NAME" >> $GITHUB_OUTPUT 7 | -------------------------------------------------------------------------------- /.github/actions/send-slack-notification-slow-job/action.yml: -------------------------------------------------------------------------------- 1 | name: Send a notification for exceeded build time 2 | description: Send a slack notification if build took more than planned 3 | 4 | inputs: 5 | max-build-time-seconds: 6 | description: Maximum acceptable build time in seconds 7 | required: true 8 | slack-token: 9 | description: The slack token 10 | required: true 11 | slack-channel: 12 | description: The slack channel id, channel name, or user id to post to 13 | required: true 14 | 15 | runs: 16 | using: composite 17 | steps: 18 | - name: Fetch billable time from gh API 19 | id: fetch_time 20 | shell: bash 21 | run: | 22 | total_time=$(gh api /repos/${{github.repository}}/actions/runs/${{github.run_id}}/timing | jq ' .billable.UBUNTU.total_ms /1000') 23 | echo "total_time in seconds: ${total_time}" 24 | echo "total_time=${total_time}" >> $GITHUB_OUTPUT 25 | 26 | - name: Slack Notification 27 | if: fromJSON(steps.fetch_time.outputs.total_time) > fromJSON(inputs.max-build-time-seconds) 28 | uses: Alfresco/alfresco-build-tools/.github/actions/send-slack-notification@v8.23.2 29 | with: 30 | channel-id: ${{ inputs.slack-channel }} 31 | message: 'Max build time exceeded: took ${{ steps.fetch_time.outputs.total_time }} seconds (expected max: ${{ inputs.max-build-time-seconds }} seconds)' 32 | token: ${{ inputs.slack-token }} 33 | -------------------------------------------------------------------------------- /.github/actions/send-slack-notification/compute-message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | COMPUTED_MESSAGE="" 4 | 5 | if [[ -n "$BLOCK_MESSAGE" && "$APPEND" == 'true' ]] || [ -z "$BLOCK_MESSAGE" ]; then 6 | case $EVENT_NAME in 7 | pull_request) 8 | COMPUTED_MESSAGE="$PR_TITLE" 9 | ;; 10 | issues) 11 | COMPUTED_MESSAGE="$ISSUE_BODY" 12 | ;; 13 | *) 14 | COMPUTED_MESSAGE="$COMMIT_MESSAGE" 15 | ;; 16 | esac 17 | fi 18 | 19 | if [ -n "$BLOCK_MESSAGE" ]; then 20 | if [[ "$APPEND" == 'true' && -n "$COMPUTED_MESSAGE" ]]; then 21 | COMPUTED_MESSAGE="${COMPUTED_MESSAGE}\n" 22 | fi 23 | COMPUTED_MESSAGE="${COMPUTED_MESSAGE}$BLOCK_MESSAGE" 24 | fi 25 | 26 | if [ -n "$COMPUTED_MESSAGE" ]; then 27 | COMPUTED_MESSAGE="*Message*\n${COMPUTED_MESSAGE}" 28 | COMPUTED_MESSAGE=$(printf "${COMPUTED_MESSAGE}" | sed -z 's/\n/\\n/g' | sed -r 's/"/\\\"/g' | sed -e 's/\r//g') 29 | # avoid error if message is too long (total message must be less than 3001 characters) 30 | COMPUTED_MESSAGE=${COMPUTED_MESSAGE:0:3000} 31 | echo 'result<&2 19 | exit 1 20 | fi 21 | NAME="${ITEM%|*}" 22 | ID="${ITEM#*|}" 23 | 24 | case $TYPE in 25 | user) 26 | ENTITIES+="{\"type\":\"mention\",\"text\":\"${NAME}\",\"mentioned\":{\"id\":\"${ID}\",\"name\":\"${NAME}\"}}" 27 | ;; 28 | tag) 29 | ENTITIES+="{\"type\":\"mention\",\"text\":\"${NAME}\",\"mentioned\":{\"id\":\"${ID}\",\"name\":\"${NAME}\",\"type\":\"tag\"}}" 30 | ;; 31 | esac 32 | done 33 | fi 34 | } 35 | 36 | add_entity "user" "$USERS" 37 | add_entity "tag" "$TAGS" 38 | 39 | ENTITIES+="]" 40 | echo "result=${ENTITIES}" 41 | -------------------------------------------------------------------------------- /.github/actions/setup-docker/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup Docker Engine" 2 | description: "Install latest docker engine and start the service (useful on self-hosted ubuntu runners)" 3 | runs: 4 | using: composite 5 | steps: 6 | - name: Setup Docker 7 | shell: bash 8 | run: | 9 | sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc 10 | echo \ 11 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ 12 | $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ 13 | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 14 | sudo apt-get update 15 | sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y 16 | sudo chmod 666 /var/run/docker.sock 17 | -------------------------------------------------------------------------------- /.github/actions/setup-github-release-binary/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup binary' 2 | description: 'Set up a specific version of a binary from GitHub Releases and add it to the PATH.' 3 | inputs: 4 | repo: 5 | description: 'Repository of binary' 6 | required: true 7 | version: 8 | description: 'Version of binary' 9 | required: true 10 | url_template: 11 | description: 'Template for download url, can use VERSION/NAME/OS/ARCH env vars' 12 | required: false 13 | default: 'v${VERSION}/${NAME}_${VERSION}_${OS}_${ARCH}.tar.gz' 14 | test_args: 15 | description: 'Arguments to test the binary' 16 | required: false 17 | default: '--version' 18 | runs: 19 | using: "composite" 20 | steps: 21 | - shell: bash 22 | env: 23 | REPO: ${{ inputs.repo }} 24 | VERSION: ${{ inputs.version }} 25 | URL_TEMPLATE: ${{ inputs.url_template }} 26 | run: | 27 | NAME=${NAME:-${REPO##*\/}} 28 | OS=${OS:-$(uname | tr '[:upper:]' '[:lower:]')} 29 | ARCH=${ARCH:-$(uname -m)} 30 | URL=https://github.com/$REPO/releases/download/$(eval echo $URL_TEMPLATE) 31 | echo "Downloading $URL ..." 32 | curl -fsSL $URL | tar xz $NAME 33 | sudo mv $NAME /usr/local/bin/$NAME 34 | $NAME ${{ inputs.test_args }} 35 | -------------------------------------------------------------------------------- /.github/actions/setup-helm-docs/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup helm-docs' 2 | description: 'Set up a specific version of helm-docs and add it to the PATH.' 3 | inputs: 4 | version: 5 | description: 'Version of helm-docs' 6 | required: false 7 | outputs: 8 | version: 9 | description: 'Version of helm-docs that was installed' 10 | value: ${{ steps.version-detect.outputs.version }} 11 | runs: 12 | using: "composite" 13 | steps: 14 | - uses: Alfresco/alfresco-build-tools/.github/actions/setup-github-release-binary@v8.23.2 15 | with: 16 | repo: norwoodj/helm-docs 17 | version: ${{ inputs.version != '' && inputs.version || env.DEFAULT_HELM_DOCS_VERSION }} 18 | env: 19 | DEFAULT_HELM_DOCS_VERSION: 1.14.2 20 | - name: Set version as output 21 | shell: bash 22 | id: version-detect 23 | run: echo "version=$(helm-docs -v | awk '{print $NF}')" >> $GITHUB_OUTPUT 24 | -------------------------------------------------------------------------------- /.github/actions/setup-java-build/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup Java build" 2 | description: "Performs the setup of required build tools (eg.: Maven, Java)" 3 | inputs: 4 | java-version: 5 | description: the desired Java version 6 | default: "17" 7 | required: false 8 | java-distribution: 9 | description: the desired Java distribution 10 | default: "temurin" 11 | required: false 12 | maven-settings: 13 | description: the location of the custom Maven settings.xml file to install 14 | default: ".ci.settings.xml" 15 | required: false 16 | cache-key-prefix: 17 | description: the prefix for the maven repository cache key (eg. to handle multiple maven caches within the same repository) 18 | default: "maven" 19 | required: false 20 | runs: 21 | using: composite 22 | steps: 23 | - name: "Cache local Maven repository" 24 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 25 | with: 26 | path: ~/.m2/repository 27 | key: ${{ runner.os }}-${{ inputs.cache-key-prefix }}-${{ hashFiles('**/pom.xml') }} 28 | restore-keys: | 29 | ${{ runner.os }}-${{ inputs.cache-key-prefix }}- 30 | - name: "Install ${{ inputs.maven-settings }}" 31 | shell: bash 32 | run: | 33 | mkdir -p ~/.m2 34 | if [ -f "${{ inputs.maven-settings }}" ]; then 35 | echo "Installing Maven settings file found in the repository: ${{ inputs.maven-settings }}" 36 | cp "${{ inputs.maven-settings }}" ~/.m2/settings.xml 37 | else 38 | echo "Maven settings file: ${{ inputs.maven-settings }} not found in the repository. Installing the default one" 39 | cp ${{ github.action_path }}/settings.xml ~/.m2/settings.xml 40 | fi 41 | - name: "Set up Java" 42 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 43 | with: 44 | java-version: ${{ inputs.java-version }} 45 | distribution: ${{ inputs.java-distribution }} 46 | overwrite-settings: false 47 | -------------------------------------------------------------------------------- /.github/actions/setup-java-build/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | alfresco-internal 5 | 6 | true 7 | 8 | 9 | 10 | alfresco-internal 11 | 12 | true 13 | 14 | 15 | true 16 | 17 | Alfresco Internal Repository 18 | https://artifacts.alfresco.com/nexus/content/groups/internal/ 19 | 20 | 21 | 22 | 23 | alfresco-internal 24 | Alfresco Internal Repository 25 | https://artifacts.alfresco.com/nexus/content/groups/public 26 | 27 | 28 | 29 | 30 | 31 | alfresco-staging 32 | 33 | 34 | alfresco-staging 35 | 36 | true 37 | 38 | 39 | false 40 | 41 | Alfresco Internal Repository 42 | https://artifacts.alfresco.com/nexus/content/groups/staging/ 43 | 44 | 45 | 46 | 47 | alfresco-staging 48 | Alfresco Internal Repository 49 | https://artifacts.alfresco.com/nexus/content/groups/public 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | alfresco-internal 58 | ${env.MAVEN_USERNAME} 59 | ${env.MAVEN_PASSWORD} 60 | 61 | 62 | alfresco-staging 63 | ${env.MAVEN_USERNAME} 64 | ${env.MAVEN_PASSWORD} 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /.github/actions/setup-jx-release-version/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup jx-release-version' 2 | description: 'Set up a specific version of jx-release-version and add it to the PATH.' 3 | inputs: 4 | version: 5 | description: 'Version of jx-release-version' 6 | required: false 7 | default: 2.2.3 8 | runs: 9 | using: "composite" 10 | steps: 11 | - uses: Alfresco/alfresco-build-tools/.github/actions/setup-github-release-binary@v8.23.2 12 | with: 13 | repo: jenkins-x-plugins/jx-release-version 14 | version: ${{ inputs.version }} 15 | url_template: 'v${VERSION}/${NAME}-${OS}-${ARCH}.tar.gz' 16 | env: 17 | ARCH: amd64 18 | -------------------------------------------------------------------------------- /.github/actions/setup-kcadm/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup kcadm' 2 | description: 'Setup Keycloak Admin CLI kcadm and add it to the PATH.' 3 | inputs: 4 | version: 5 | description: 'Version of Keycloak' 6 | required: false 7 | runs: 8 | using: "composite" 9 | steps: 10 | - name: Setup kcadm 11 | shell: bash 12 | run: | 13 | KEYCLOAK_VERSION=${{ inputs.version != '' && inputs.version || env.DEFAULT_KEYCLOAK_VERSION }} 14 | curl -fsSL https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-${KEYCLOAK_VERSION}.tar.gz | tar xz 15 | ln -s keycloak-$KEYCLOAK_VERSION keycloak && ln -s ${PWD}/keycloak/bin/kcadm.sh /usr/local/bin 16 | kcadm.sh help 17 | env: 18 | DEFAULT_KEYCLOAK_VERSION: 26.2.5 19 | -------------------------------------------------------------------------------- /.github/actions/setup-kind/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup a KinD cluster" 2 | description: "Spin a local Kubernetes cluster with ingress-nginx" 3 | inputs: 4 | kind-version: 5 | description: | 6 | The kind version to use. Versions available at: 7 | https://github.com/kubernetes-sigs/kind/releases 8 | default: v0.26.0 9 | kind-node-image: 10 | description: | 11 | The Kind docker node image to use. Should match the same kind version at: 12 | https://github.com/kubernetes-sigs/kind/releases 13 | default: kindest/node:v1.31.4@sha256:2cb39f7295fe7eafee0842b1052a599a4fb0f8bcf3f83d96c7f4864c357c6c30 14 | kind-wait: 15 | description: The duration to wait for the control plane to become ready 16 | default: 60s 17 | ingress-nginx-ref: 18 | description: | 19 | the Nginx ingress ref to get the ingress controller deployment manifest from 20 | (https://github.com/kubernetes/ingress-nginx). Consider main (the default) a floating tag which can result in 21 | deploying any version (including betas) and non repeatable builds. 22 | default: main 23 | metrics: 24 | description: Whether Metrics Server should be installed upon cluster creation 25 | default: "false" 26 | import-docker-credentials-secret-name: 27 | description: | 28 | Whether to create a secret using the given name using file $HOME/.docker/config.json. 29 | You have to login to one or more registries before using this option. 30 | runs: 31 | using: "composite" 32 | steps: 33 | - name: Create cluster 34 | uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 35 | with: 36 | config: ${{ github.action_path }}/kind.yml 37 | version: ${{ inputs.kind-version }} 38 | node_image: ${{ inputs.kind-node-image }} 39 | wait: ${{ inputs.kind-wait }} 40 | 41 | - name: Install Metrics Server 42 | shell: bash 43 | if: inputs.metrics == 'true' 44 | run: >- 45 | helm install --repo https://kubernetes-sigs.github.io/metrics-server/ 46 | --set args={--kubelet-insecure-tls} 47 | metrics-server metrics-server 48 | --namespace kube-system 49 | 50 | - name: Install ingress-nginx 51 | shell: bash 52 | env: 53 | NGINX_MANIFEST_URL: >- 54 | https://raw.githubusercontent.com/kubernetes/ingress-nginx/${{ inputs.ingress-nginx-ref }}/deploy/static/provider/kind/deploy.yaml 55 | run: | 56 | kubectl apply -f "${NGINX_MANIFEST_URL}" 57 | 58 | - name: Wait for ingress ready 59 | shell: bash 60 | run: | 61 | kubectl wait --namespace ingress-nginx \ 62 | --for=condition=ready pod \ 63 | --selector=app.kubernetes.io/component=controller \ 64 | --timeout=90s 65 | 66 | - name: Create registries auth secret 67 | shell: bash 68 | if: inputs.import-docker-credentials-secret-name != '' 69 | run: | 70 | kubectl create secret generic ${{ inputs.import-docker-credentials-secret-name }} \ 71 | --from-file=.dockerconfigjson=$HOME/.docker/config.json \ 72 | --type=kubernetes.io/dockerconfigjson 73 | -------------------------------------------------------------------------------- /.github/actions/setup-kind/kind.yml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Cluster 3 | apiVersion: kind.x-k8s.io/v1alpha4 4 | nodes: 5 | - role: control-plane 6 | kubeadmConfigPatches: 7 | - | 8 | kind: InitConfiguration 9 | nodeRegistration: 10 | kubeletExtraArgs: 11 | node-labels: "ingress-ready=true" 12 | - | 13 | kind: KubeletConfiguration 14 | serializeImagePulls: false 15 | maxParallelImagePulls: 5 16 | extraPortMappings: 17 | - containerPort: 80 18 | hostPort: 80 19 | protocol: TCP 20 | - containerPort: 443 21 | hostPort: 443 22 | protocol: TCP 23 | -------------------------------------------------------------------------------- /.github/actions/setup-kubepug/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup Kubepug" 2 | description: "Install the Kubernetes preupgrade checker" 3 | inputs: 4 | kubepug-version: 5 | description: The kubepug version to install 6 | default: "1.3.2" 7 | required: false 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Install kubepug 12 | shell: bash 13 | run: ${{ github.action_path }}/setup-kubepug.sh ${{ inputs.kubepug-version }} 14 | -------------------------------------------------------------------------------- /.github/actions/setup-kubepug/setup-kubepug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | KUBEPUG_VERSION=$1 3 | if [[ "$RUNNER_OS" == "Windows" ]]; then 4 | curl -fsSLo kubepug.zip https://github.com/rikatz/kubepug/releases/download/v${KUBEPUG_VERSION}/kubepug_windows_amd64.zip 5 | unzip -o kubepug.zip kubepug.exe && rm kubepug.zip && mv kubepug.exe $HOME/bin/ 6 | elif [ "$RUNNER_OS" == "Linux" ]; then 7 | curl -fsSL https://github.com/rikatz/kubepug/releases/download/v${KUBEPUG_VERSION}/kubepug_$(uname | tr '[:upper:]' '[:lower:]')_amd64.tar.gz | tar xz -C /usr/local/bin/ kubepug 8 | else 9 | echo "$RUNNER_OS not supported" 10 | exit 1 11 | fi 12 | 13 | kubepug version 14 | -------------------------------------------------------------------------------- /.github/actions/setup-pysemver/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup pysemver' 2 | description: 'Set up a specific version of pysemver' 3 | inputs: 4 | version: 5 | description: 'Version of pysemver' 6 | required: false 7 | default: 2.13.0 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Install pysemver via pip 12 | env: 13 | TOOL_VERSION: ${{ inputs.version }} 14 | run: | 15 | pip3 install git+https://github.com/python-semver/python-semver.git@$TOOL_VERSION 16 | pysemver --version 17 | shell: bash 18 | -------------------------------------------------------------------------------- /.github/actions/setup-rancher-cli/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Rancher CLI' 2 | description: 'Set up a specific version of Rancher CLI and add it to the PATH.' 3 | inputs: 4 | version: 5 | description: 'Version of Rancher CLI' 6 | required: false 7 | access-key: 8 | description: 'Rancher API access key' 9 | required: false 10 | secret-key: 11 | description: 'Rancher API secret key' 12 | required: false 13 | url: 14 | description: 'Rancher URL' 15 | required: false 16 | context: 17 | description: 'Rancher context for kubectl configuration' 18 | required: false 19 | default: local 20 | runs: 21 | using: "composite" 22 | steps: 23 | - shell: bash 24 | run: | 25 | TOOL_VERSION=${{ inputs.version != '' && inputs.version || env.DEFAULT_RANCHER_CLI_VERSION }} 26 | TOOL_NAME=rancher 27 | TOOL_REPO=rancher/cli 28 | TOOL_OS=$(uname | tr '[:upper:]' '[:lower:]') 29 | TOOL_ARCH=amd64 30 | curl -fsSL https://github.com/$TOOL_REPO/releases/download/v$TOOL_VERSION/$TOOL_NAME-$TOOL_OS-$TOOL_ARCH-v$TOOL_VERSION.tar.gz \ 31 | | tar xz --strip=2 ./$TOOL_NAME-v$TOOL_VERSION/$TOOL_NAME 32 | sudo mv $TOOL_NAME /usr/local/bin/ 33 | echo $($TOOL_NAME --version) 34 | env: 35 | DEFAULT_RANCHER_CLI_VERSION: 2.11.2 36 | - shell: bash 37 | run: | 38 | RANCHER2_BEARER_TOKEN=${{ inputs.access-key }}:${{ inputs.secret-key }} 39 | RANCHER2_URL=${{ inputs.url }} 40 | if [[ -n "$RANCHER2_BEARER_TOKEN" ]] 41 | then 42 | RANCHER_SYSTEM_CONTEXT_INDEX=$(echo 1 | rancher login $RANCHER2_URL -t $RANCHER2_BEARER_TOKEN | grep "$KUBECONTEXT" | grep System | cut -d ' ' -f1) 43 | echo $RANCHER_SYSTEM_CONTEXT_INDEX | rancher login $RANCHER2_URL -t $RANCHER2_BEARER_TOKEN > /dev/null 44 | fi 45 | env: 46 | KUBECONTEXT: ${{ inputs.context }} 47 | - shell: bash 48 | run: | 49 | KUBECONTEXT="${{ inputs.context }}" 50 | if [[ -n "$KUBECONTEXT" ]] 51 | then 52 | mkdir -p $HOME/.kube && rancher cluster kubeconfig ${{ inputs.context }} > $HOME/.kube/config 53 | fi 54 | -------------------------------------------------------------------------------- /.github/actions/setup-terraform-docs/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup terraform-docs' 2 | description: 'Setup terraform-docs and add it to the PATH.' 3 | inputs: 4 | version: 5 | description: 'Version of terraform-docs' 6 | required: false 7 | default: 0.20.0 8 | runs: 9 | using: "composite" 10 | steps: 11 | - uses: Alfresco/alfresco-build-tools/.github/actions/setup-github-release-binary@v8.23.2 12 | with: 13 | repo: terraform-docs/terraform-docs 14 | version: ${{ inputs.version }} 15 | url_template: 'v${VERSION}/${NAME}-v${VERSION}-${OS}-${ARCH}.tar.gz' 16 | env: 17 | ARCH: amd64 18 | -------------------------------------------------------------------------------- /.github/actions/setup-updatebot/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup updatebot' 2 | description: 'Set up a specific version of updatebot and add it to the PATH.' 3 | inputs: 4 | version: 5 | description: 'Version of updatebot' 6 | required: false 7 | default: 1.1.60 8 | runs: 9 | using: "composite" 10 | steps: 11 | - run: | 12 | curl -fsSLo updatebot.jar \ 13 | https://repo1.maven.org/maven2/io/jenkins/updatebot/updatebot/$UPDATEBOT_VERSION/updatebot-$UPDATEBOT_VERSION.jar 14 | echo "java -jar /usr/local/bin/updatebot.jar \$@" > updatebot 15 | chmod +x updatebot 16 | sudo mv updatebot* /usr/local/bin/ 17 | echo updatebot $(updatebot version) 18 | shell: bash 19 | env: 20 | UPDATEBOT_VERSION: ${{ inputs.version }} 21 | -------------------------------------------------------------------------------- /.github/actions/setup-updatecli/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup updatecli' 2 | description: 'Install updatecli binary' 3 | inputs: 4 | version: 5 | description: 'Version of binary' 6 | default: 0.101.0 7 | runs: 8 | using: "composite" 9 | steps: 10 | - uses: Alfresco/alfresco-build-tools/.github/actions/setup-github-release-binary@v8.23.2 11 | with: 12 | repo: updatecli/updatecli 13 | version: ${{ inputs.version }} 14 | url_template: 'v${VERSION}/${NAME}_${OS}_${ARCH}.tar.gz' 15 | test_args: 'version' 16 | -------------------------------------------------------------------------------- /.github/actions/slack-file-upload/action.yml: -------------------------------------------------------------------------------- 1 | name: slack-file-upload 2 | description: Upload file to slack channel 3 | inputs: 4 | slack-token: 5 | description: 'Slack API token' 6 | required: true 7 | slack-channel-id: 8 | description: 'Slack channel ID' 9 | required: true 10 | file-path: 11 | description: 'File to upload' 12 | required: true 13 | file-title: 14 | description: 'Title of file' 15 | python-version: 16 | description: 'Python version' 17 | required: false 18 | default: '3.9' 19 | runs: 20 | using: composite 21 | steps: 22 | - name: Setup Python 23 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 24 | id: setup-python 25 | with: 26 | python-version: ${{ inputs.python-version }} 27 | 28 | - name: Workaround for hashFiles not working outside current workspace 29 | shell: bash 30 | run: cp ${{ github.action_path }}/requirements.txt requirements-slack.txt 31 | 32 | - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 33 | with: 34 | path: ~/.cache/pip 35 | key: ${{ runner.os }}-pip-${{ hashFiles('requirements-slack.txt') }} 36 | 37 | - name: Install requirements via pip 38 | shell: bash 39 | run: ${{ steps.setup-python.outputs.python-path }} -m pip install -r ${{ github.action_path }}/requirements.txt 40 | 41 | - name: Upload ${{ inputs.file-path }} to Slack 42 | shell: bash 43 | env: 44 | SLACK_BOT_TOKEN: ${{ inputs.slack-token }} 45 | SLACK_CHANNEL_ID: ${{ inputs.slack-channel-id }} 46 | run: ${{ steps.setup-python.outputs.python-path }} ${{ github.action_path }}/slack_file_upload.py "${{ inputs.file-path }}" "${{ inputs.file-title }}" 47 | -------------------------------------------------------------------------------- /.github/actions/slack-file-upload/requirements.txt: -------------------------------------------------------------------------------- 1 | slack_sdk==3.33.3 2 | -------------------------------------------------------------------------------- /.github/actions/slack-file-upload/slack_file_upload.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from slack_sdk import WebClient 4 | from slack_sdk.errors import SlackApiError 5 | 6 | def upload_file_to_slack(token, channel_id, file_path, title): 7 | client = WebClient(token=token) 8 | 9 | try: 10 | response = client.files_upload_v2( 11 | channel=channel_id, 12 | file=file_path, 13 | title=title 14 | ) 15 | print(f"File uploaded successfully: {response['file']['id']}") 16 | except SlackApiError as e: 17 | print(f"Error uploading file: {e.response['error']}") 18 | raise e 19 | 20 | if __name__ == "__main__": 21 | if 'SLACK_BOT_TOKEN' not in os.environ: 22 | raise ValueError('SLACK_BOT_TOKEN is not set.') 23 | if 'SLACK_CHANNEL_ID' not in os.environ: 24 | raise ValueError('SLACK_CHANNEL_ID is not set.') 25 | if len(sys.argv) < 2: 26 | raise ValueError('File path must be provided as the first argument.') 27 | 28 | SLACK_BOT_TOKEN = os.environ['SLACK_BOT_TOKEN'] 29 | CHANNEL_ID = os.environ['SLACK_CHANNEL_ID'] 30 | FILE_PATH = sys.argv[1] 31 | TITLE = sys.argv[2] if len(sys.argv) > 2 else None 32 | 33 | upload_file_to_slack(SLACK_BOT_TOKEN, CHANNEL_ID, FILE_PATH, TITLE) 34 | -------------------------------------------------------------------------------- /.github/actions/sonar-scanner/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Sonar Scanner' 2 | description: 'Run Sonar Scanner to load JaCoCo report on SonarCloud' 3 | inputs: 4 | sonar-token: 5 | description: 'SonarCloud token' 6 | required: true 7 | aggregate-report-path: 8 | description: 'Path of the aggregated JaCoCo report' 9 | required: true 10 | project-key: 11 | description: 'SonarCloud project key' 12 | required: true 13 | sonar-host-url: 14 | description: 'SonarCloud host url' 15 | required: false 16 | default: 'https://sonarcloud.io' 17 | sonar-organization: 18 | description: 'SonarCloud organization' 19 | required: false 20 | default: 'alfresco' 21 | 22 | 23 | runs: 24 | using: composite 25 | steps: 26 | - name: Load JaCoCo report on SonarCloud 27 | env: 28 | SONAR_TOKEN: ${{ inputs.sonar-token }} 29 | shell: bash 30 | run: | 31 | mvn sonar:sonar -Dsonar.host.url=${{ inputs.sonar-host-url }} -Dsonar.organization=${{ inputs.sonar-organization }} -Dsonar.projectKey=${{ inputs.project-key }} -Dsonar.coverage.jacoco.xmlReportPaths=${{ inputs.aggregate-report-path }} 32 | -------------------------------------------------------------------------------- /.github/actions/update-deployment-runtime-versions/action.yml: -------------------------------------------------------------------------------- 1 | name: Update runtime versions file 2 | description: Update file runtime-versions-info.json 3 | inputs: 4 | deploymentServiceDir: 5 | description: directory holding the deployment service code 6 | required: true 7 | developmentBranch: 8 | description: name of the development branch 9 | required: true 10 | serviceName: 11 | description: the name of the service to be updated 12 | required: true 13 | dockerImageName: 14 | description: the name of the docker image 15 | required: true 16 | dockerImageTag: 17 | description: the tag of the docker image 18 | required: true 19 | runs: 20 | using: composite 21 | steps: 22 | - shell: bash 23 | env: 24 | RUNTIME_VERSIONS_FILE: alfresco-deployment-service/src/main/resources/runtime-versions-info.json 25 | DEVELOPMENT_BRANCH: ${{ inputs.developmentBranch }} 26 | DOCKER_IMAGE: "quay.io/alfresco/${{ inputs.dockerImageName }}:${{ inputs.dockerImageTag }}" 27 | SERVICE_NAME: ${{ inputs.serviceName }} 28 | working-directory: ${{ inputs.deploymentServiceDir}} 29 | run: 30 | cat <<< $(jq --arg serviceName "$SERVICE_NAME" '(.[]|select(.version? == env.DEVELOPMENT_BRANCH).services[$serviceName].image) |= env.DOCKER_IMAGE' $RUNTIME_VERSIONS_FILE) > $RUNTIME_VERSIONS_FILE 31 | -------------------------------------------------------------------------------- /.github/actions/update-pom-to-next-pre-release/action.yml: -------------------------------------------------------------------------------- 1 | description: Update pom files to the next pre-release 2 | name: Update pom to next pre-release 3 | inputs: 4 | prerelease-type: 5 | description: The type of the prerelease, i.e. `alpha`, `beta`, `rc` 6 | required: false 7 | default: alpha 8 | maven-cli-opts: 9 | description: extra maven properties 10 | required: false 11 | property-to-update: 12 | description: property to update in addition to the version of the pom file 13 | required: false 14 | version: 15 | description: custom version to be set 16 | required: false 17 | outputs: 18 | next-prerelease: 19 | description: "Next prerelease" 20 | value: ${{ steps.resolve-version.outputs.version }} 21 | runs: 22 | using: composite 23 | steps: 24 | - name: Parse next version from POM 25 | id: parse-next-final-version 26 | if: inputs.version == '' 27 | shell: bash 28 | run: | 29 | NEXT_VERSION=$(yq -p=xml e '.project.version' pom.xml | grep -o "[0-9]*\.[0-9]*.[0-9]*") 30 | echo "Next final version: $NEXT_VERSION" 31 | echo "result=$NEXT_VERSION" >> $GITHUB_OUTPUT 32 | 33 | - id: next-prerelease-resolver 34 | name: Calculate next internal release 35 | if: inputs.version == '' 36 | uses: Alfresco/alfresco-build-tools/.github/actions/calculate-next-internal-version@v8.23.2 37 | with: 38 | next-version: ${{ steps.parse-next-final-version.outputs.result }} 39 | prerelease-type: ${{ inputs.prerelease-type }} 40 | 41 | - id: resolve-version 42 | name: Resolve version 43 | shell: bash 44 | run: | 45 | if [ ${{ inputs.version }} != '' ] 46 | then 47 | echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT 48 | else 49 | echo "version=${{ steps.next-prerelease-resolver.outputs.next-prerelease }}" >> $GITHUB_OUTPUT 50 | fi 51 | 52 | - name: Update pom files to the new version 53 | uses: Alfresco/alfresco-build-tools/.github/actions/maven-update-pom-version@v8.23.2 54 | with: 55 | version: ${{ steps.resolve-version.outputs.version }} 56 | maven-cli-opts: ${{ inputs.maven-cli-opts }} 57 | property-to-update: ${{ inputs.property-to-update }} 58 | -------------------------------------------------------------------------------- /.github/actions/update-project-base-tag/action.yml: -------------------------------------------------------------------------------- 1 | name: Update project base tag 2 | description: "Update project base tag in the release descriptor file. The entry `release.baseTag.$project` will be set to `$tag" 3 | inputs: 4 | release-descriptor: 5 | description: Path to the release descriptor 6 | required: true 7 | project: 8 | description: The name of the project to be updated 9 | required: true 10 | tag: 11 | description: the value to be used as base tag for the project 12 | required: true 13 | runs: 14 | using: composite 15 | steps: 16 | - name: Update base tag 17 | shell: bash 18 | env: 19 | RELEASE_DESCRIPTOR: ${{ inputs.release-descriptor }} 20 | PROJECT: ${{ inputs.project }} 21 | TAG: ${{ inputs.tag }} 22 | run: eval "yq -i e '.release.baseTag.$PROJECT = env(TAG)' $RELEASE_DESCRIPTOR" 23 | -------------------------------------------------------------------------------- /.github/actions/validate-maven-versions/action.yml: -------------------------------------------------------------------------------- 1 | name: Validate Maven Versions 2 | description: Validates Maven dependency graph versions to ensure all target includes artifacts versions align 3 | inputs: 4 | target-includes: 5 | required: true 6 | description: list of target includes artifacts separated by comma 7 | default: com.alfresco.process:alfresco-process-version:* 8 | module: 9 | required: false 10 | description: The Maven module name to use for validating dependencies. Defaults to '.' 11 | default: . 12 | maven-username: 13 | required: true 14 | description: Maven username 15 | maven-password: 16 | required: true 17 | description: Maven password 18 | maven-opts: 19 | required: false 20 | description: Maven Java options 21 | default: '-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn' 22 | working-directory: 23 | required: false 24 | description: Maven project working directory 25 | default: . 26 | m2-settings-xml: 27 | required: false 28 | description: relative path to maven settings.xml 29 | default: .m2/settings.xml 30 | runs: 31 | using: composite 32 | steps: 33 | - name: Resolve dependencies 34 | run: | 35 | mvn -B -s $GITHUB_WORKSPACE/${{ inputs.m2-settings-xml }} dependency:resolve 36 | env: 37 | MAVEN_USERNAME: ${{ inputs.maven-username }} 38 | MAVEN_PASSWORD: ${{ inputs.maven-password }} 39 | MAVEN_OPTS: ${{ inputs.maven-opts }} 40 | working-directory: ${{ inputs.working-directory }} 41 | shell: bash 42 | 43 | - name: Generate dependency graph 44 | run: | 45 | mvn -B -s $GITHUB_WORKSPACE/${{ inputs.m2-settings-xml }} --no-transfer-progress \ 46 | com.github.ferstl:depgraph-maven-plugin:4.0.2:graph \ 47 | -pl ${{ inputs.module }} \ 48 | -DgraphFormat=text \ 49 | -DshowVersions \ 50 | -DshowConflicts \ 51 | -DshowDuplicates \ 52 | -DtargetIncludes=${{ inputs.target-includes }} 53 | env: 54 | MAVEN_USERNAME: ${{ inputs.maven-username }} 55 | MAVEN_PASSWORD: ${{ inputs.maven-password }} 56 | MAVEN_OPTS: ${{ inputs.maven-opts }} 57 | working-directory: ${{ inputs.working-directory }} 58 | shell: bash 59 | 60 | - name: Validate dependency conflicts 61 | env: 62 | TERM: xterm-color 63 | run: | 64 | cat ${{ inputs.module }}/target/dependency-graph.txt | grep -z --color "conflict" && echo "Conflicts detected." && exit 1 || echo "Success" 65 | working-directory: ${{ inputs.working-directory }} 66 | shell: bash 67 | -------------------------------------------------------------------------------- /.github/actions/veracode/action.yml: -------------------------------------------------------------------------------- 1 | name: "veracode" 2 | description: "Run Veracode - Source Clear Scan (SCA)" 3 | inputs: 4 | srcclr-api-token: 5 | description: "Agent API Token" 6 | required: true 7 | srcclr-project-ext: 8 | description: "Direct scan results to Veracode project named: /" 9 | required: false 10 | runs: 11 | using: "composite" 12 | steps: 13 | - name: "Install srcclr CLI tool" 14 | shell: bash 15 | run: | 16 | # Install srcclr CLI tool (Veracode) as per https://docs.veracode.com/r/t_sc_cli_agent 17 | curl -sSL 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xdf7dd7a50b746dd4' | sudo gpg --dearmor -o /usr/share/keyrings/veracode-sca-archive.gpg 18 | echo 'deb [signed-by=/usr/share/keyrings/veracode-sca-archive.gpg] https://download.sourceclear.com/ubuntu stable/' | sudo tee /etc/apt/sources.list.d/veracode-sca.list 19 | sudo apt-get update 20 | sudo apt-get install srcclr 21 | - name: "Set target project URI, with extension if provided" 22 | shell: bash 23 | run: | 24 | SRCCLR_SCM_URI="${{ github.server_url }}/${{ github.repository }}" 25 | 26 | if [ -n "${{ inputs.srcclr-project-ext }}" ]; then 27 | SRCCLR_SCM_URI="$SRCCLR_SCM_URI/${{ inputs.srcclr-project-ext }}" 28 | fi 29 | 30 | echo "SRCCLR_SCM_URI=$SRCCLR_SCM_URI" >> $GITHUB_ENV 31 | - name: "Run scanning" 32 | run: ${{ github.action_path }}/source_clear.sh 33 | shell: bash 34 | env: 35 | SRCCLR_API_TOKEN: ${{ inputs.srcclr-api-token }} 36 | SRCCLR_SCM_REF: ${{ github.event_name == 'pull_request' && github.ref || github.ref_name }} 37 | SRCCLR_SCM_REF_TYPE: ${{ github.event_name == 'pull_request' && 'tag' || 'branch' }} 38 | SRCCLR_SCM_REV: ${{ github.sha }} 39 | -------------------------------------------------------------------------------- /.github/actions/veracode/source_clear.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "=========================== Starting SourceClear Script ===========================" 4 | PS4="\[\e[35m\]+ \[\e[m\]" 5 | set +e -v -x 6 | 7 | srcclr scan \ 8 | --scm-uri="$SRCCLR_SCM_URI" \ 9 | --scm-ref="$SRCCLR_SCM_REF" \ 10 | --scm-ref-type="$SRCCLR_SCM_REF_TYPE" \ 11 | --scm-rev="$SRCCLR_SCM_REV" > scan.log 12 | 13 | SUCCESS=$? # this will read exit code of the previous command 14 | 15 | grep -e 'Full Report Details' scan.log 16 | 17 | set +vex 18 | echo "=========================== Finishing SourceClear Script ==========================" 19 | 20 | exit ${SUCCESS} 21 | -------------------------------------------------------------------------------- /.github/dependabot.template.yml: -------------------------------------------------------------------------------- 1 | # Documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | # Edit should be made in the dependabot.template.yml 4 | version: 2 5 | updates: 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | interval: "weekly" 10 | groups: 11 | # https://github.com/dflook/terraform-github-actions 12 | # multiple action always released together 13 | dflook: 14 | patterns: 15 | - "dflook/*" 16 | - package-ecosystem: "pip" 17 | directory: "/.github/actions/pipenv" 18 | schedule: 19 | interval: "monthly" 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | ### Checklist 3 | 4 | - Jira Reference (also in PR title): 5 | - [README](https://github.com/Alfresco/alfresco-build-tools/blob/master/docs/README.md) updated after adding/changing behaviour of an action 6 | - Proposed version increment for [release](https://github.com/Alfresco/alfresco-build-tools/blob/master/docs/README.md#release): 7 | - [ ] Patch (bugfix) 8 | - [ ] Minor (new feature) 9 | - [ ] Major (breaking changes) 10 | - External PR link where changes has been tested: 11 | 12 | ### Description 13 | 14 | 15 | -------------------------------------------------------------------------------- /.github/tests/actions/test-setup-helm-docs/action.yml: -------------------------------------------------------------------------------- 1 | name: Test setup-helm-docs 2 | description: > 3 | Just a test for setup-helm-docs 4 | inputs: 5 | expected-version: 6 | description: 'Version of helm-docs' 7 | required: false 8 | runs: 9 | using: composite 10 | steps: 11 | - name: Check helm-docs version 12 | shell: bash 13 | run: | 14 | [ "$(helm-docs -v | awk '{print $NF}')" = "${{ inputs.expected-version }}" ] 15 | -------------------------------------------------------------------------------- /.github/tests/env-load-from-yaml/env.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | - TRAVIS_BRANCH=whatever 4 | - APP_SETTING_ONE=value 5 | -------------------------------------------------------------------------------- /.github/workflows/helm-publish-new-package-version.yml: -------------------------------------------------------------------------------- 1 | name: Publish helm package 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | next-version: 7 | description: "Next final version to be release" 8 | type: string 9 | required: true 10 | chart-dir: 11 | description: "Path to the directory holding Chart.yml file" 12 | type: string 13 | required: false 14 | helm-charts-repo: 15 | description: "The name of the repository where the package will be added" 16 | type: string 17 | required: true 18 | helm-charts-repo-branch: 19 | description: "The name of the branch where the package will be added" 20 | type: string 21 | required: true 22 | helm-charts-repo-subfolder: 23 | description: "The name of the subfolder inside the charts repository where the package should be added" 24 | type: string 25 | required: false 26 | helm-charts-repo-base-url: 27 | description: "Helm chart repo base url" 28 | type: string 29 | required: false 30 | helm-docs-version: 31 | description: 'Version of helm-docs' 32 | type: string 33 | required: false 34 | outputs: 35 | version: 36 | description: "The version of the new published package" 37 | value: ${{ jobs.publish.outputs.version }} 38 | 39 | jobs: 40 | publish: 41 | runs-on: ubuntu-latest 42 | outputs: 43 | version: ${{ steps.next-release.outputs.next-prerelease }} 44 | steps: 45 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 46 | 47 | - id: next-release 48 | name: Calculate next internal release 49 | uses: Alfresco/alfresco-build-tools/.github/actions/calculate-next-internal-version@v8.23.2 50 | with: 51 | next-version: ${{ inputs.next-version }} 52 | 53 | - name: Set version env variable 54 | env: 55 | VERSION: ${{ steps.next-release.outputs.next-prerelease }} 56 | run: | 57 | echo "VERSION=$VERSION" >> "$GITHUB_ENV" 58 | 59 | - name: Update chart version 60 | uses: Alfresco/alfresco-build-tools/.github/actions/helm-update-chart-version@v8.23.2 61 | with: 62 | new-version: ${{ env.VERSION }} 63 | chart-dir: ${{ inputs.chart-dir }} 64 | helm-docs-version: ${{ inputs.helm-docs-version }} 65 | 66 | - uses: Alfresco/alfresco-build-tools/.github/actions/git-commit-changes@v8.23.2 67 | with: 68 | username: ${{ secrets.BOT_GITHUB_USERNAME }} 69 | add-options: -u 70 | commit-message: "release $VERSION" 71 | 72 | - name: Create local tag 73 | run: git tag -a "$VERSION" -m "Release version $VERSION" 74 | 75 | - name: Package Helm Chart 76 | id: package-helm-chart 77 | uses: Alfresco/alfresco-build-tools/.github/actions/helm-package-chart@v8.23.2 78 | with: 79 | chart-dir: ${{ inputs.chart-dir }} 80 | 81 | - name: Push tag 82 | run: git push origin "$VERSION" 83 | 84 | - name: Publish Helm chart 85 | uses: Alfresco/alfresco-build-tools/.github/actions/helm-publish-chart@v8.23.2 86 | with: 87 | helm-charts-repo: ${{ inputs.helm-charts-repo }} 88 | helm-charts-repo-branch: ${{ inputs.helm-charts-repo-branch }} 89 | chart-package: ${{ steps.package-helm-chart.outputs.package-file-path }} 90 | token: ${{ secrets.BOT_GITHUB_TOKEN }} 91 | git-username: ${{ secrets.BOT_GITHUB_USERNAME }} 92 | -------------------------------------------------------------------------------- /.github/workflows/publish-artifacts-for-veracode.yml: -------------------------------------------------------------------------------- 1 | #Deploy SNAPSHOTS artifacts once a day to Nexus, so they can be consumed by Veracode 2 | name: Produces artifacts for Veracode 3 | 4 | on: 5 | workflow_call: 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 13 | - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 14 | with: 15 | path: ~/.m2/repository 16 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 17 | restore-keys: | 18 | ${{ runner.os }}-maven- 19 | 20 | - name: Set up JDK 21 21 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 22 | with: 23 | java-version: '21' 24 | distribution: 'temurin' 25 | 26 | - name: Login to DockerHub Registry 27 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 28 | with: 29 | registry: docker.io 30 | username: ${{ secrets.DOCKER_USERNAME }} 31 | password: ${{ secrets.DOCKER_PASSWORD }} 32 | 33 | - name: Build and Deploy 34 | run: mvn deploy ${{ env.MAVEN_CLI_OPTS}} 35 | env: 36 | MAVEN_CLI_OPTS: -DskipTests --show-version --no-transfer-progress --settings settings.xml -Dlogging.root.level=off -Dspring.main.banner-mode=off -Ddocker.skip -Dswagger.skip 37 | MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }} 38 | MAVEN_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - closed 7 | workflow_dispatch: 8 | 9 | jobs: 10 | release: 11 | name: Release 12 | runs-on: ubuntu-latest 13 | if: github.event.pull_request.merged == true 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | with: 17 | fetch-depth: 0 18 | ref: master 19 | token: ${{ secrets.BOT_GITHUB_TOKEN }} 20 | 21 | - name: Fetch next version 22 | run: | 23 | echo "VERSION=$(cat version.txt)" >> "$GITHUB_ENV" 24 | 25 | - name: Check if release is necessary 26 | id: release_guard 27 | run: | 28 | if git tag | grep -q "^${VERSION}$"; then 29 | echo "do_release=false" >> "$GITHUB_OUTPUT" 30 | else 31 | echo "do_release=true" >> "$GITHUB_OUTPUT" 32 | fi 33 | 34 | - name: Apply release changes 35 | if: steps.release_guard.outputs.do_release == 'true' 36 | run: | 37 | ./release.sh "$VERSION" 38 | 39 | - uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0 40 | with: 41 | branch: master 42 | skip_checkout: true 43 | commit_message: Release ${{ env.VERSION }} 44 | commit_user_name: ${{ vars.BOT_GITHUB_USERNAME }} 45 | commit_user_email: ${{ vars.BOT_GITHUB_EMAIL }} 46 | 47 | - name: Generate release notes 48 | if: steps.release_guard.outputs.do_release == 'true' 49 | env: 50 | GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} 51 | run: gh release create "$VERSION" --generate-notes -t "$VERSION" 52 | -------------------------------------------------------------------------------- /.github/workflows/test-with-bats.yml: -------------------------------------------------------------------------------- 1 | name: CI with BATS 🦇 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | test: 11 | name: test 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | 17 | - uses: mig4/setup-bats@af9a00deb21b5d795cabfeaa8d9060410377686d # v1.2.0 18 | with: 19 | bats-version: 1.8.0 20 | 21 | - name: 🦇🦇🦇 22 | run: bats -r --print-output-on-failure . 23 | -------------------------------------------------------------------------------- /.github/workflows/updatecli.yml: -------------------------------------------------------------------------------- 1 | name: Updatecli 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 6 * * 1' 7 | push: 8 | paths: 9 | - '.updatecli/**' 10 | - .github/workflows/updatecli.yml 11 | 12 | permissions: 13 | contents: write 14 | pull-requests: write 15 | id-token: write # This is required for requesting the JWT 16 | deployments: write # This is required for deployment statuses management 17 | 18 | jobs: 19 | build-matrix-github-releases: 20 | runs-on: ubuntu-latest 21 | if: github.actor != 'dependabot[bot]' 22 | outputs: 23 | matrix: ${{ steps.set-matrix.outputs.matrix }} 24 | steps: 25 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 26 | 27 | - name: Build Matrix 28 | id: set-matrix 29 | run: | 30 | FILES_JSON=$(find .updatecli/values/github_releases -type f -exec basename {} \; | jq -R -s -c 'split("\n")[:-1]') 31 | echo "Files: $FILES_JSON" 32 | echo "matrix=$FILES_JSON" >> "$GITHUB_OUTPUT" 33 | 34 | update-github-releases: 35 | needs: build-matrix-github-releases 36 | runs-on: ubuntu-latest 37 | strategy: 38 | max-parallel: 1 39 | matrix: 40 | file: ${{ fromJson(needs.build-matrix-github-releases.outputs.matrix) }} 41 | steps: 42 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 43 | 44 | - name: Install Updatecli 45 | uses: ./.github/actions/setup-updatecli 46 | 47 | - name: Run Updatecli 48 | run: updatecli apply -c .updatecli/templates/github_releases.yaml -v .updatecli/values/github_releases/${{ matrix.file }} 49 | env: 50 | UPDATECLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | UPDATECLI_USERNAME: ${{ vars.BOT_GITHUB_USERNAME }} 52 | UPDATECLI_EMAIL: ${{ vars.BOT_GITHUB_EMAIL }} 53 | UPDATECLI_REPO_OWNER: ${{ github.repository_owner }} 54 | UPDATECLI_REPO_NAME: ${{ github.event.repository.name }} 55 | UPDATECLI_REPO_BRANCH: ${{ github.event.repository.default_branch }} 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ 2 | .idea/ 3 | out/ 4 | target/ 5 | *.iml 6 | 7 | ## File-based project format: 8 | *.iws 9 | 10 | ## Plugin-specific files: 11 | 12 | # mpeltonen/sbt-idea plugin 13 | .idea_modules/ 14 | 15 | # JIRA plugin 16 | atlassian-ide-plugin.xml 17 | 18 | # Cursive Clojure plugin 19 | .idea/replstate.xml 20 | 21 | # Crashlytics plugin (for Android Studio and IntelliJ) 22 | com_crashlytics_export_strings.xml 23 | crashlytics.properties 24 | crashlytics-build.properties 25 | fabric.properties 26 | 27 | ### Java template 28 | # Compiled class file 29 | *.class 30 | 31 | # Log file 32 | *.log 33 | 34 | # BlueJ files 35 | *.ctxt 36 | 37 | # Mobile Tools for Java (J2ME) 38 | .mtj.tmp/ 39 | 40 | # Package Files # 41 | *.jar 42 | *.war 43 | *.ear 44 | *.zip 45 | *.tar.gz 46 | *.rar 47 | 48 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 49 | hs_err_pid* 50 | 51 | #mac osx 52 | *.DS_Store 53 | 54 | # Node packages and dependencies 55 | node_modules 56 | 57 | # vscode settings 58 | .vscode 59 | -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | default: true 2 | MD013: false 3 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-yaml 6 | args: [--allow-multiple-documents] 7 | exclude: '.updatecli/templates' 8 | - id: check-json 9 | - id: check-xml 10 | - id: check-merge-conflict 11 | - id: fix-byte-order-marker 12 | - id: mixed-line-ending 13 | args: ['--fix=lf'] 14 | exclude: .github/actions/send-slack-notification/tests/sample-commit-message.txt 15 | - id: end-of-file-fixer 16 | exclude: '.*/dist/.*' 17 | - id: trailing-whitespace 18 | exclude: '.*/dist/.*' 19 | - repo: https://github.com/sirosen/check-jsonschema 20 | rev: 0.31.0 21 | hooks: 22 | - id: check-dependabot 23 | - id: check-github-actions 24 | - id: check-github-workflows 25 | - repo: https://github.com/igorshubovych/markdownlint-cli 26 | rev: v0.43.0 27 | hooks: 28 | - id: markdownlint 29 | - repo: https://github.com/rhysd/actionlint 30 | rev: v1.7.7 31 | hooks: 32 | - id: actionlint 33 | - repo: local 34 | hooks: 35 | - id: generate-dependabot 36 | name: Generate dependabot config for actions 37 | language: system 38 | entry: ./update-dependabot.sh 39 | pass_filenames: false 40 | - id: check-readme 41 | name: Check README entries 42 | language: system 43 | entry: ./check_readme.sh 44 | pass_filenames: false 45 | -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: helm-deps 2 | name: Helm Dependency Update 3 | entry: bash -c 'find . -name Chart.yaml | xargs -I% bash -c "dirname %" | xargs -t -I% helm dep up %' 4 | language: system 5 | pass_filenames: false 6 | - id: helm-deps-build 7 | name: Helm Dependency Build 8 | entry: bash -c 'find . -name Chart.yaml | xargs -I% bash -c "dirname %" | xargs -t -I% helm dep build %' 9 | language: system 10 | pass_filenames: false 11 | - id: helm-lint 12 | name: Helm Lint 13 | entry: bash -c 'find . -name Chart.yaml | xargs -I% bash -c "dirname %" | xargs -t -I% helm lint %' 14 | language: system 15 | pass_filenames: false 16 | - id: kubepug-minimum 17 | name: KubePug - k8s v1.15 minimum 18 | entry: bash -c 'find . -name Chart.yaml | xargs -I% bash -c "dirname %" | xargs -t -I% bash -c "helm template % --kube-version 1.15 | kubepug --error-on-deprecated --error-on-deleted --k8s-version v1.15.0 --input-file=-"' 19 | language: system 20 | pass_filenames: false 21 | - id: kubepug-recommended 22 | name: KubePug - k8s v1.21 recommended 23 | entry: bash -c 'find . -name Chart.yaml | xargs -I% bash -c "dirname %" | xargs -t -I% bash -c "helm template % --kube-version 1.21 | kubepug --error-on-deprecated --error-on-deleted --k8s-version v1.21.0 --input-file=-"' 24 | language: system 25 | pass_filenames: false 26 | - id: kubepug-latest 27 | name: KubePug - k8s latest 28 | entry: bash -c 'find . -name Chart.yaml | xargs -I% bash -c "dirname %" | xargs -t -I% bash -c "helm template % | kubepug --error-on-deprecated --error-on-deleted --input-file=-"' 29 | language: system 30 | pass_filenames: false 31 | - id: md-toc 32 | name: Markdown Table of Contents 33 | entry: >- 34 | bash -eu -o pipefail -c 35 | "MDTOC_ARGS=\"\"; 36 | for f in $@; do 37 | [[ \"x$f\" = x--* ]] && MDTOC_ARGS=\"$f $MDTOC_ARGS\" && continue; 38 | [ -f \"$f\" ] && markdown-toc $MDTOC_ARGS -i $f; 39 | done" 40 | language: system 41 | -------------------------------------------------------------------------------- /.updatecli/templates/github_releases.yaml: -------------------------------------------------------------------------------- 1 | name: GitHub Releases Update 2 | 3 | pipelineid: '{{ .github_release.repo }}' 4 | 5 | scms: 6 | github: 7 | kind: 'github' 8 | spec: 9 | user: '{{ requiredEnv "UPDATECLI_USERNAME" }}' 10 | email: '{{ requiredEnv "UPDATECLI_EMAIL" }}' 11 | username: '{{ requiredEnv "UPDATECLI_USERNAME" }}' 12 | token: '{{ requiredEnv "UPDATECLI_GITHUB_TOKEN" }}' 13 | owner: '{{ requiredEnv "UPDATECLI_REPO_OWNER" }}' 14 | repository: '{{ requiredEnv "UPDATECLI_REPO_NAME" }}' 15 | branch: '{{ requiredEnv "UPDATECLI_REPO_BRANCH" }}' 16 | commitmessage: 17 | type: '{{ .github.prefix }}' 18 | message: '{{ .github.message }}' 19 | 20 | actions: 21 | open-pull-request: 22 | kind: 'github/pullrequest' 23 | scmid: 'github' 24 | spec: 25 | automerge: true 26 | mergemethod: squash 27 | draft: false 28 | title: '{{ .github.prefix }}: {{ .github.message }}' 29 | description: '{{ .github.message }}' 30 | labels: 31 | - dependencies 32 | - github_releases 33 | 34 | sources: 35 | lastRelease: 36 | kind: githubrelease 37 | spec: 38 | owner: '{{ .github_release.owner }}' 39 | repository: '{{ .github_release.repo }}' 40 | token: '{{ requiredEnv "UPDATECLI_GITHUB_TOKEN" }}' 41 | versionfilter: 42 | kind: semver 43 | strict: {{ .github_release.versionfilter.strict | default false }} 44 | pattern: '{{ .github_release.versionfilter.pattern | default "*" }}' 45 | 46 | targets: 47 | update-file: 48 | name: 'Update version' 49 | scmid: 'github' 50 | kind: yaml 51 | spec: 52 | file: '{{ .target.file }}' 53 | key: '{{ .target.key }}' 54 | transformers: 55 | - trimprefix: '{{ .target.trimprefix | default "" }}' 56 | -------------------------------------------------------------------------------- /.updatecli/values/github_releases/helm_docs.yaml: -------------------------------------------------------------------------------- 1 | github: 2 | prefix: 'build(deps)' 3 | message: 'bump helm-docs to {{ source "lastRelease" }}' 4 | 5 | github_release: 6 | owner: 'norwoodj' 7 | repo: 'helm-docs' 8 | 9 | target: 10 | file: '.github/actions/setup-helm-docs/action.yml' 11 | key: '$.runs.steps[0].env.DEFAULT_HELM_DOCS_VERSION' 12 | trimprefix: 'v' 13 | -------------------------------------------------------------------------------- /.updatecli/values/github_releases/kcadm.yaml: -------------------------------------------------------------------------------- 1 | github: 2 | prefix: 'build(deps)' 3 | message: 'bump kcadm to {{ source "lastRelease" }}' 4 | 5 | github_release: 6 | owner: 'keycloak' 7 | repo: 'keycloak' 8 | 9 | target: 10 | file: '.github/actions/setup-kcadm/action.yml' 11 | key: '$.runs.steps[0].env.DEFAULT_KEYCLOAK_VERSION' 12 | -------------------------------------------------------------------------------- /.updatecli/values/github_releases/rancher_cli.yaml: -------------------------------------------------------------------------------- 1 | github: 2 | prefix: 'build(deps)' 3 | message: 'bump rancher-cli to {{ source "lastRelease" }}' 4 | 5 | github_release: 6 | owner: 'rancher' 7 | repo: 'cli' 8 | 9 | target: 10 | file: '.github/actions/setup-rancher-cli/action.yml' 11 | key: '$.runs.steps[0].env.DEFAULT_RANCHER_CLI_VERSION' 12 | trimprefix: 'v' 13 | -------------------------------------------------------------------------------- /.updatecli/values/github_releases/terraform_docs.yaml: -------------------------------------------------------------------------------- 1 | github: 2 | prefix: 'build(deps)' 3 | message: 'bump terraform-docs to {{ source "lastRelease" }}' 4 | 5 | github_release: 6 | owner: 'terraform-docs' 7 | repo: 'terraform-docs' 8 | 9 | target: 10 | file: '.github/actions/setup-terraform-docs/action.yml' 11 | key: '$.inputs.version.default' 12 | trimprefix: 'v' 13 | -------------------------------------------------------------------------------- /.updatecli/values/github_releases/updatecli.yaml: -------------------------------------------------------------------------------- 1 | github: 2 | prefix: 'build(deps)' 3 | message: 'bump updatecli to {{ source "lastRelease" }}' 4 | 5 | github_release: 6 | owner: 'updatecli' 7 | repo: 'updatecli' 8 | 9 | target: 10 | file: '.github/actions/setup-updatecli/action.yml' 11 | key: '$.inputs.version.default' 12 | trimprefix: 'v' 13 | -------------------------------------------------------------------------------- /check_readme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | actions_dir=".github/actions" 4 | readme_file="docs/README.md" 5 | missing_entries=0 6 | 7 | # List all folders under .github/actions 8 | folders=$(ls -d $actions_dir/*/) 9 | 10 | # Check each folder 11 | for folder in $folders; do 12 | action_name=$(basename $folder) 13 | search_string="### $action_name" 14 | if ! grep -q "$search_string" "$readme_file"; then 15 | echo "No entry found for $search_string in README.md" 16 | ((missing_entries++)) 17 | fi 18 | done 19 | 20 | # Report the number of missing entries 21 | if [ $missing_entries -gt 0 ]; then 22 | echo "$missing_entries entries not found in README.md" 23 | exit 1 24 | fi 25 | -------------------------------------------------------------------------------- /docs/images/rp-gh-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/rp-gh-summary.png -------------------------------------------------------------------------------- /docs/images/rp-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/rp-sample.png -------------------------------------------------------------------------------- /docs/images/send-slack-custom-message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-slack-custom-message.png -------------------------------------------------------------------------------- /docs/images/send-slack-pr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-slack-pr.png -------------------------------------------------------------------------------- /docs/images/send-slack-push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-slack-push.png -------------------------------------------------------------------------------- /docs/images/send-teams-get-tag-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-teams-get-tag-id.png -------------------------------------------------------------------------------- /docs/images/send-teams-pr-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-teams-pr-success.png -------------------------------------------------------------------------------- /docs/images/send-teams-push-failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-teams-push-failure.png -------------------------------------------------------------------------------- /docs/images/send-teams-push-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alfresco/alfresco-build-tools/3d656a453714a40052886d698f3950741890e159/docs/images/send-teams-push-success.png -------------------------------------------------------------------------------- /docs/pre-commit-hooks.md: -------------------------------------------------------------------------------- 1 | # Pre-commit Hooks 2 | 3 | Git hooks are scripts that run automatically every time a particular event 4 | occurs in a Git repository. They let you customize Git’s internal behavior and 5 | trigger customizable actions at key points in the development life cycle. Git 6 | hooks are a useful way to run scripts when an action such as a commit, merge, or 7 | push occurs. 8 | 9 | To prevent the developer from committing bad code and running CI builds that 10 | would break the environment, we decided to use the pre-commit library to manage 11 | hooks and run some basic checks on the code. All the information about the 12 | pre-commit library can be found in the official documentation. 13 | 14 | The goal of this guide is to provide a quick starting point to the developer and 15 | explain how we are using it on the single pipeline repository and how we can 16 | configure it for other projects 17 | 18 | pre-commit runs locally while performing a commit, but with a small effort, it 19 | is possible to run it in CI too, during the CI build. 20 | 21 | Below are the hooks available in this repository and defined in 22 | [.pre-commit-hooks.yaml](../.pre-commit-hooks.yaml) 23 | 24 | ## Helm-deps (Helm Dependency Update) 25 | 26 | Validate the dependencies of a chart. 27 | 28 | Add to your `.pre-commit-config.yaml`: 29 | 30 | ```yaml 31 | - repo: https://github.com/Alfresco/alfresco-build-tools 32 | rev: v1.22.0 33 | hooks: 34 | - id: helm-deps 35 | ``` 36 | 37 | ## Helm Lint 38 | 39 | Validate the liniting of a chart. 40 | 41 | Add to your `.pre-commit-config.yaml`: 42 | 43 | ```yaml 44 | - repo: https://github.com/Alfresco/alfresco-build-tools 45 | rev: v1.22.0 46 | hooks: 47 | - id: helm-lint 48 | ``` 49 | 50 | Helm lint examine a chart for potential issues and verify the chart is well-formed. 51 | 52 | ## Kubepug 53 | 54 | KubePug is a kubectl plugin checking for deprecated Kubernetes clusters or 55 | deprecated versions of Kubernetes manifests. 56 | 57 | Validate this hook. 58 | 59 | Add to your `.pre-commit-config.yaml`: 60 | 61 | ```yaml 62 | - repo: https://github.com/Alfresco/alfresco-build-tools 63 | rev: v1.22.0 64 | hooks: 65 | - id: kubepug-latest 66 | ``` 67 | 68 | Note:- Some more kubepug hooks are available like kubepug-minimum, and kubepug-recommend. 69 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ -z "$GITHUB_WORKSPACE" ]; then 5 | echo "You should not run anymore this script from your machine, see updated README" 6 | exit 1 7 | fi 8 | 9 | if [ -z "$1" ] || [[ ! "$1" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then 10 | echo 'First argument should be next version to release with a leading v char' 11 | exit 1 12 | fi 13 | 14 | CURRENT_VERSION=$(git tag | sort -r --version-sort | head -n1) 15 | if [ -z "$CURRENT_VERSION" ]; then 16 | echo "Can't retrieve tags" 17 | exit 1 18 | fi 19 | 20 | echo "Current version is $CURRENT_VERSION" 21 | echo "Going to flip refs to $1" 22 | 23 | grep -Rl "Alfresco/alfresco-build-tools.*@$CURRENT_VERSION" | xargs sed -i -e "s/\(Alfresco\/alfresco-build-tools.*@\)$CURRENT_VERSION/\1$1/g" 24 | sed -i -e "s/$CURRENT_VERSION/$1/" .pre-commit-config.yaml 25 | 26 | echo "Rename completed succesfully" 27 | -------------------------------------------------------------------------------- /update-dependabot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Directory containing composite actions 4 | actions_dir='.github/actions' 5 | 6 | # Dependabot source config file 7 | master_config='.github/dependabot.template.yml' 8 | 9 | # Dependabot target config file 10 | dependabot_config='.github/dependabot.yml' 11 | 12 | # Temp file for new Dependabot config section 13 | temp_config='temp_dependabot.yml' 14 | 15 | # Function to generate Dependabot config section for a composite action 16 | generate_dependabot_section() { 17 | local action_dir=$1 18 | cat < /dev/null; then 38 | echo "yq is not installed. Please install it to continue." 39 | exit 1 40 | fi 41 | 42 | # Start building the new config section 43 | echo "version: 2" > "$temp_config" 44 | echo "updates:" >> "$temp_config" 45 | 46 | # Loop through composite actions and append to temp config 47 | for action_filename in $(find "$actions_dir" -mindepth 2 -type f -name action.yml | env -i LC_COLLATE=C sort -n); do 48 | action_dir=$(dirname $action_filename) 49 | generate_dependabot_section "$action_dir" >> "$temp_config" 50 | done 51 | 52 | # Merge new section with existing Dependabot config using yq 53 | yq eval-all '. as $item ireduce ({}; . *+ $item)' $master_config $temp_config > "$dependabot_config" 54 | 55 | # Clean up 56 | rm "$temp_config" 57 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | v8.23.2 2 | --------------------------------------------------------------------------------