name: '[CI/CD] CI Pipeline' on: # rebuild any PRs and main branch changes pull_request_target: types: - synchronize - labeled branches: - main - bitnami:main permissions: {} # Avoid concurrency over the same PR concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} jobs: get-containers: runs-on: ubuntu-latest name: Get modified containers permissions: pull-requests: read if: | github.event.pull_request.state != 'closed' && ( contains(github.event.pull_request.labels.*.name, 'verify') || (github.event.action == 'labeled' && github.event.label.name == 'verify') ) outputs: result: ${{ steps.get-containers.outputs.result }} containers: ${{ steps.get-containers.outputs.containers }} dockerfiles: ${{ steps.get-containers.outputs.dockerfiles }} steps: - id: get-containers name: Get modified containers env: PULL_REQUEST_NUMBER: "${{ github.event.pull_request.number }}" GITHUB_TOKEN: "${{ github.token }}" run: | files_changed="$(gh api --paginate /repos/${GITHUB_REPOSITORY}/pulls/${PULL_REQUEST_NUMBER}/files | jq -r '.[] | .filename')" # Adding || true to avoid "Process exited with code 1" errors flavors=($(echo "$files_changed" | xargs dirname | grep -o "^bitnami/[^/]*/[^/]*/[^/]*" | sort | uniq || true)) assets=($(echo "$files_changed" | xargs dirname | sed -nr "s|bitnami/([^/]*)/.*|\1|p" | sort | uniq || true)) non_readme_files=$(echo "$files_changed" | grep -vc "\.md" || true) dockerfiles=($(echo "$files_changed" | grep -oE ".*/Dockerfile$" | sort | uniq || true)) if [[ "$non_readme_files" -le "0" ]]; then # The only changes are .md files -> SKIP echo "result=skip" >> $GITHUB_OUTPUT elif [[ "${#assets[@]}" -ne "1" ]]; then echo "Changes should affect to only one asset. You are currently modifying: ${assets[@]}" echo "result=skip" >> $GITHUB_OUTPUT else containers_json=$(printf "%s\n" "${flavors[@]}" | jq -R . | jq -cs .) dockerfiles_json=$(printf "%s\n" "${dockerfiles[@]}" | jq -R . | jq -cs .) echo "result=ok" >> $GITHUB_OUTPUT echo "containers=${containers_json}" >> $GITHUB_OUTPUT echo "dockerfiles=${dockerfiles_json}" >> $GITHUB_OUTPUT fi license-headers-linter: runs-on: ubuntu-latest name: License Headers Linter permissions: contents: read pull-requests: write needs: get-containers steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 name: Checkout Repository with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} - id: get-modified-files name: 'Get modified files' env: DOCKERFILES: "${{ needs.get-containers.outputs.dockerfiles }}" run: | if [[ -n "${DOCKERFILES}" ]]; then # Overwrite configuration file to analyze only changed dockerfiles yq -i '. | .header.paths=env(DOCKERFILES)' .licenserc.yaml echo "result=success" >> $GITHUB_OUTPUT else echo "result=skip" >> $GITHUB_OUTPUT fi - name: Check license Headers uses: apache/skywalking-eyes/header@cd7b195c51fd3d6ad52afceb760719ddc6b3ee91 if: ${{ steps.get-modified-files.outputs.result == 'success' }} vib-verify: runs-on: ubuntu-latest needs: get-containers # Automatic PRs do not need to be re-tested in GitHub if: | needs.get-containers.outputs.result == 'ok' && github.event.pull_request.user.login != 'bitnami-bot' name: VIB Verify permissions: contents: read env: CSP_API_URL: https://console.cloud.vmware.com CSP_API_TOKEN: ${{ secrets.CSP_API_TOKEN }} VIB_PUBLIC_URL: https://cp.bromelia.vmware.com continue-on-error: false strategy: fail-fast: false max-parallel: 2 matrix: container: ${{ fromJSON(needs.get-containers.outputs.containers) }} steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 name: Checkout Repository with: # Full history is not required anymore fetch-depth: 1 # labeled events trigger the event with the latest commit in main ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} - id: get-container-metadata name: Get image tag and container name run: | if [[ -d "${{ matrix.container }}" ]]; then name="$(echo "${{ matrix.container }}" | awk -F '/' '{print $2}')" branch="$(echo "${{ matrix.container }}" | awk -F '/' '{print $3}')" tag="" if [[ "${{ github.event.pull_request.user.login }}" == "bitnami-bot" ]]; then tag="$(grep -oE "org.opencontainers.image.ref.name=\".+\"" ${{ matrix.container }}/Dockerfile | sed -nr "s|org.opencontainers.image.ref.name=\"(.+)\"|\1|p")" else # Build a tag based on current RUN number tag="$(echo "${{ matrix.container }}" | awk -F '/' -v run_number="${GITHUB_RUN_NUMBER}" '{printf "%s-rc.%s", $3, run_number}')" fi if [[ -z "${tag}" ]]; then echo "No tag found for: ${{ matrix.container }}" exit 1 else dsl_path="${name}" if [[ -d ".vib/${dsl_path}/${branch}" ]]; then dsl_path="${dsl_path}/${branch}" fi echo "tag=${tag}" >> $GITHUB_OUTPUT echo "name=${name}" >> $GITHUB_OUTPUT echo "dsl_path=${dsl_path}" >> $GITHUB_OUTPUT echo "result=ok" >> $GITHUB_OUTPUT fi else # Container folder doesn't exists we are assuming a deprecation echo "result=skip" >> $GITHUB_OUTPUT fi - uses: vmware-labs/vmware-image-builder-action@v0 name: Verify if: ${{ steps.get-container-metadata.outputs.result == 'ok' }} with: pipeline: ${{ steps.get-container-metadata.outputs.dsl_path }}/vib-verify.json env: # Path with docker resources VIB_ENV_PATH: ${{ matrix.container }} # Container name VIB_ENV_CONTAINER: ${{ steps.get-container-metadata.outputs.name }} VIB_ENV_TAG: ${{ steps.get-container-metadata.outputs.tag }} verification-summary: # Ensure all containers passed the verification runs-on: ubuntu-latest name: Check Matrix Outcome permissions: statuses: write needs: - get-containers - vib-verify outputs: result: ${{ steps.get-status.outputs.result }} if: ${{ always() && github.event.pull_request.user.login != 'bitnami-bot' }} steps: - id: get-status name: Check Status uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: result-encoding: string script: | state = 'success' description = 'Well done! Everything looks good. Please wait for the Bitnami Team review.' if ("${{ needs.get-containers.result }}" != "success" ) { description = "If you've just created this PR, don't worry about this message. The Bitnami Team has to review it and make the verification possible." core.warning(description) state = 'pending' } else if ("${{ needs.get-containers.outputs.result }}" == "skip" ) { description = "It seems these changes don't involve any container" core.warning(description) } else if ("${{ needs.vib-verify.result }}" != "success" ) { description = "Please review previous jobs to get more information" core.error(description) state = 'error' } else { core.notice(description) } try { await github.rest.repos.createCommitStatus({ context: `${context.workflow} / Verification Summary (${context.eventName})`, owner: context.payload.repository.owner.login, repo: context.payload.repository.name, sha: context.payload.pull_request.head.sha, target_url: `${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`, description: description, state: state }) core.info(`Updated build status: ${state}`) } catch (error) { core.setFailed(error.message) } return state auto-pr-review: runs-on: ubuntu-latest name: Reviewal for automated PRs permissions: pull-requests: write needs: - license-headers-linter # This job will be executed when the PR was created by bitnami-bot and it has the 'auto-merge' label if: | contains(github.event.pull_request.labels.*.name, 'auto-merge') && github.event.pull_request.user.login == 'bitnami-bot' steps: # Approve the CI's PR automatically, as it has been tested in our internal pipeline already # Approved by the 'github-actions' user; a PR can't be approved by its author - name: PR Approval uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: result-encoding: string retries: 3 script: | github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, event: 'APPROVE', }); - name: Merge id: merge uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: result-encoding: string retries: 3 # Necessary to trigger CD workflows github-token: ${{ secrets.BITNAMI_BOT_TOKEN }} script: | github.rest.pulls.merge({ pull_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, merge_method: 'squash' }) # If the merge process did not succeed, # post a comment on the PR and assign a maintainer agent to review it - name: Manual review required if: ${{ always() && steps.merge.outcome != 'success' }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: BODY: | There has been an error during the automated release process. Manual revision is now required. Please check the related [action_run#${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more information. with: retries: 3 script: | const {BODY} = process.env github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `${BODY}` })