diff --git a/.github/actions/create-jira-ticket/action.yml b/.github/actions/create-jira-ticket/action.yml new file mode 100644 index 0000000000..f05a1e81e1 --- /dev/null +++ b/.github/actions/create-jira-ticket/action.yml @@ -0,0 +1,142 @@ +name: Workflow incident tracking +description: Create Jira ticket on incident + +inputs: + jira_base_url: + required: true + description: jira base url + jira_user_email: + required: true + description: jira user email + jira_api_token: + required: true + description: jira api token + module_name: + required: true + description: module name + ticket_labels: + required: true + description: ticket labels, usually Pipeline + Nightly/Veracode + x + default: 'Pipeline' + +runs: + using: "composite" + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Get ticket elements from context + id: get_context + run: | + # Safely set/unset IFS in order to parse the table of labels properly + [ -n "${IFS+set}" ] && saved_IFS=$IFS + IFS=', ' read -a ticket_labels <<< $(echo "${{ inputs.ticket_labels }}" | tr -d "[],'") + unset IFS + [ -n "${saved_IFS+set}" ] && { IFS=$saved_IFS; unset saved_IFS; } + + # Change context elements (summary, parent epic, etc.) that is checked depending on the ticket labels in the input + if [[ "${ticket_labels[@]}" =~ "Veracode" ]]; then + parent_epic_id=83818 + parent_epic_key="AT-268" + ticket_summary="PR-${{ github.event.pull_request.number }} incident on ${{ inputs.module_name }}" + + JSON_TEMPLATE_FILE="./.github/actions/create-jira-ticket/veracode-ticket-template.json" + sed -i \ + -e 's|@PULL_REQUEST_NUMBER@|${{ github.event.pull_request.number }}|g' \ + -e 's|@PULL_REQUEST_URL@|${{ github.event.pull_request.html_url }}|g' $JSON_TEMPLATE_FILE + elif [[ "${ticket_labels[@]}" =~ "Nightly" ]]; then + parent_epic_id=206242 + parent_epic_key="MON-151547" + ticket_summary="$(date '+%Y-%m-%d') ${{ inputs.module_name }}-${{ github.ref_name }} nightly build failure" + + JSON_TEMPLATE_FILE="./.github/actions/create-jira-ticket/nightly-ticket-template.json" + sed -i \ + -e 's|@MODULE_NAME@|${{ inputs.module_name }}|g' \ + -e "s|@DATE@|$(date '+%Y-%m-%d')|g" $JSON_TEMPLATE_FILE + else + echo "::error::Cannot find a valid labelling option for the ticket." + exit 1 + fi + + sed -i \ + -e 's|@GITHUB_BRANCH@|${{ github.base_ref || github.ref_name }}|g' \ + -e 's|@GITHUB_SERVER_URL@|${{ github.server_url }}|g' \ + -e 's|@GITHUB_REPOSITORY@|${{ github.repository }}|g' \ + -e 's|@GITHUB_RUN_ID@|${{ github.run_id }}|g' \ + -e 's|@GITHUB_RUN_ATTEMPT@|${{ github.run_attempt }}|g' $JSON_TEMPLATE_FILE + + echo "parent_epic_id=$parent_epic_id" >> $GITHUB_OUTPUT + echo "parent_epic_key=$parent_epic_key" >> $GITHUB_OUTPUT + echo "ticket_summary=$ticket_summary" >> $GITHUB_OUTPUT + echo "json_template_file=$JSON_TEMPLATE_FILE" >> $GITHUB_OUTPUT + + cat $JSON_TEMPLATE_FILE + cat $GITHUB_OUTPUT + shell: bash + env: + GH_TOKEN: ${{ github.token }} + + - name: Check if the ticket already exists + id: check_ticket + run: | + # Checking if an incident ticket already exists + response=$(curl \ + --write-out "%{http_code}" \ + --request POST \ + --url "${{ inputs.jira_base_url }}/rest/api/3/search" \ + --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \ + --header "Accept:application/json" \ + --header "Content-Type:application/json" \ + --data '{ + "fields": ["summary"], + "jql": "project = MON AND parentEpic = ${{ steps.get_context.outputs.parent_epic_key }} AND issueType = Technical AND summary ~ \"${{ steps.get_context.outputs.ticket_summary }}\" AND component = \"${{ inputs.module_name }}\" AND resolution = unresolved ORDER BY key ASC", + "maxResults": 1 + }' + ) + echo "[DEBUG] $response" + if [[ $(echo "$response" | tr -d '\n' | tail -c 3) -ne 200 ]]; then + echo "::error:: Jira API request was not completed properly." + fi + check_if_ticket_exists=$(echo "$response" | head -c -4 | jq .issues[0].key) + if [[ "$check_if_ticket_exists" != "null" ]]; then + echo "abort_ticket_creation=true" >> $GITHUB_ENV + echo "::error::ticket found as $check_if_ticket_exists aborting ticket creation" + fi + shell: bash + + - name: Create Jira Issue + if: ${{ env.abort_ticket_creation != 'true' }} + run: | + # Creating a new incident ticket on Jira + DATA=$( cat <<-EOF + { + "fields": { + "summary": "${{ steps.get_context.outputs.ticket_summary }}", + "project": {"key": "MON"}, + "issuetype": {"id": "10209"}, + "parent": {"id": "${{ steps.get_context.outputs.parent_epic_id }}", "key": "${{ steps.get_context.outputs.parent_epic_key }}"}, + "labels": ${{ inputs.ticket_labels }}, + "components":[{"name": "${{ inputs.module_name }}"}], + "customfield_10902": {"id": "10524", "value": "DevSecOps"}, + "customfield_10005": 1.0, + "description": $(cat ${{ steps.get_context.outputs.json_template_file }}) + } + } + EOF + ) + + response=$(curl \ + --request POST \ + --url "${{ inputs.jira_base_url }}/rest/api/3/issue" \ + --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json' \ + --data "$DATA") + echo $response + if [ $? -ne 0 ]; then + echo "::error::Failed to create ticket: $response" + exit 1 + fi + + ticket_key=$(echo "$response" | jq -r .key) + echo "::notice::Created ticket: $ticket_key" + shell: bash diff --git a/.github/actions/create-jira-ticket/nightly-ticket-template.json b/.github/actions/create-jira-ticket/nightly-ticket-template.json new file mode 100644 index 0000000000..aed95eed37 --- /dev/null +++ b/.github/actions/create-jira-ticket/nightly-ticket-template.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "type": "doc", + "content": [ + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "This incident ticket relates to the @MODULE_NAME@ nightly on the @GITHUB_BRANCH@ branch which failed on @DATE@." + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Link to the failed nightly", + "marks": [ + { + "type": "link", + "attrs": { + "href": "@GITHUB_SERVER_URL@/@GITHUB_REPOSITORY@/actions/runs/@GITHUB_RUN_ID@/attempts/@GITHUB_RUN_ATTEMPT@" + } + } + ] + } + ] + } + ] +} diff --git a/.github/workflows/centreon-collect.yml b/.github/workflows/centreon-collect.yml index dfc5b5fe60..816b7c25ab 100644 --- a/.github/workflows/centreon-collect.yml +++ b/.github/workflows/centreon-collect.yml @@ -1,7 +1,7 @@ name: Centreon collect run-name: | ${{ - (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_nightly == 'true')) + (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.nightly_manual_trigger == 'true')) && format('collect nightly {0}', github.ref_name) || '' }} @@ -13,7 +13,7 @@ concurrency: on: workflow_dispatch: inputs: - is_nightly: + nightly_manual_trigger: description: 'Set to true for nightly run' required: true default: false @@ -116,6 +116,7 @@ jobs: uses: ./.github/workflows/get-environment.yml with: version_file: CMakeLists.txt + nightly_manual_trigger: ${{ inputs.nightly_manual_trigger }} veracode-analysis: needs: [get-environment] @@ -136,12 +137,10 @@ jobs: unit-test: needs: [get-environment] if: ${{ github.event.inputs.unit_tests == 'true' && ! contains(fromJson('["stable"]'), needs.get-environment.outputs.stability) }} - strategy: fail-fast: false matrix: distrib: [alma8, alma9, debian-bookworm] - runs-on: [self-hosted, collect] env: SCCACHE_PATH: "/usr/bin/sccache" @@ -290,12 +289,22 @@ jobs: package_extension: ${{ matrix.package_extension }} runner: ${{ matrix.runner }} arch: ${{ matrix.arch }} - secrets: inherit - + is_nightly: ${{ needs.get-environment.outputs.is_nightly }} + secrets: + collect_s3_access_key: ${{ secrets.COLLECT_S3_ACCESS_KEY }} + collect_s3_secret_key: ${{ secrets.COLLECT_S3_SECRET_KEY }} + registry_username: ${{ secrets.HARBOR_CENTREON_PULL_USERNAME }} + registry_password: ${{ secrets.HARBOR_CENTREON_PULL_TOKEN }} + rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} + rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} + rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + jira_base_url: ${{ secrets.JIRA_BASE_URL }} + jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} + jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} robot-test: needs: [get-environment, package] if: | - (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_nightly == 'true')) && + needs.get-environment.outputs.is_nightly == 'true' && ! cancelled() && ! contains(needs.*.result, 'failure') && ! contains(needs.*.result, 'cancelled') @@ -350,10 +359,11 @@ jobs: image_test: ${{ matrix.image }}:${{ needs.get-environment.outputs.test_img_version }} image_version: ${{ needs.get-environment.outputs.img_version }} package_cache_key: ${{ github.run_id }}-${{ github.sha }}-${{ matrix.package_extension }}-centreon-collect-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} - package_cache_path: ./*.${{ matrix.package_extension}} + package_cache_path: ./*.${{ matrix.package_extension }} database_type: ${{ matrix.database_type }} - tests_params: ${{matrix.tests_params}} - test_group_name: ${{matrix.test_group_name}} + tests_params: ${{ matrix.tests_params }} + test_group_name: ${{ matrix.test_group_name }} + is_nightly: ${{ needs.get-environment.outputs.is_nightly }} secrets: registry_username: ${{ secrets.HARBOR_CENTREON_PULL_USERNAME }} registry_password: ${{ secrets.HARBOR_CENTREON_PULL_TOKEN }} @@ -361,7 +371,9 @@ jobs: collect_s3_secret_key: ${{ secrets.COLLECT_S3_SECRET_KEY }} xray_client_id: ${{ secrets.XRAY_CLIENT_ID }} xray_client_secret: ${{ secrets.XRAY_CLIENT_SECRET }} - + jira_base_url: ${{ secrets.JIRA_BASE_URL }} + jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} + jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} deliver-sources: runs-on: [self-hosted, common] needs: [get-environment, package] @@ -422,6 +434,19 @@ jobs: release_type: ${{ needs.get-environment.outputs.release_type }} is_cloud: ${{ needs.get-environment.outputs.is_cloud }} + - name: Create Jira ticket if nightly build failure + if: | + needs.get-environment.outputs.is_nightly == 'true' && github.run_attempt == 1 && + failure() && + startsWith(github.ref_name, 'dev') + uses: ./.github/actions/create-jira-ticket + with: + jira_base_url: ${{ secrets.JIRA_BASE_URL }} + jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} + jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} + module_name: "centreon-collect" + ticket_labels: '["Nightly", "Pipeline", "nightly-${{ github.ref_name }}", "${{ github.job }}"]' + deliver-deb: if: | contains(fromJson('["unstable", "testing"]'), needs.get-environment.outputs.stability) && @@ -456,6 +481,19 @@ jobs: release_type: ${{ needs.get-environment.outputs.release_type }} is_cloud: ${{ needs.get-environment.outputs.is_cloud }} + - name: Create Jira ticket if nightly build failure + if: | + needs.get-environment.outputs.is_nightly == 'true' && github.run_attempt == 1 && + failure() && + startsWith(github.ref_name, 'dev') + uses: ./.github/actions/create-jira-ticket + with: + jira_base_url: ${{ secrets.JIRA_BASE_URL }} + jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} + jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} + module_name: "centreon-collect" + ticket_labels: '["Nightly", "Pipeline", "nightly-${{ github.ref_name }}", "${{ github.job }}"]' + promote: needs: [get-environment, deliver-rpm, deliver-deb] if: | diff --git a/.github/workflows/get-environment.yml b/.github/workflows/get-environment.yml index 4b48812dc8..0f5f57b6d0 100644 --- a/.github/workflows/get-environment.yml +++ b/.github/workflows/get-environment.yml @@ -5,6 +5,9 @@ on: required: false type: string default: CMakeLists.txt + nightly_manual_trigger: + required: false + type: boolean outputs: latest_major_version: description: "latest major version" @@ -33,6 +36,9 @@ on: is_targeting_feature_branch: description: "if it is a PR, check if targeting a feature branch" value: ${{ jobs.get-environment.outputs.is_targeting_feature_branch }} + is_nightly: + description: "if the current workflow run is considered a nightly" + value: ${{ jobs.get-environment.outputs.is_nightly }} img_version: description: "docker image version (vcpkg checksum)" value: ${{ jobs.get-environment.outputs.img_version }} @@ -53,6 +59,7 @@ jobs: target_stability: ${{ steps.get_stability.outputs.target_stability }} release_type: ${{ steps.get_release_type.outputs.release_type }} is_targeting_feature_branch: ${{ steps.get_stability.outputs.is_targeting_feature_branch }} + is_nightly: ${{ steps.get_nightly_status.outputs.is_nightly }} img_version: ${{ steps.get_docker_images_version.outputs.img_version }} test_img_version: ${{ steps.get_docker_images_version.outputs.test_img_version }} @@ -226,6 +233,25 @@ jobs: return false; + - name: Detect nightly status + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: get_nightly_status + env: + NIGHTLY_MANUAL_TRIGGER: ${{ inputs.nightly_manual_trigger }} + with: + script: | + const getNightlyInput = () => { + const nightly_manual_trigger = process.env.NIGHTLY_MANUAL_TRIGGER; + console.log(nightly_manual_trigger); + if (typeof nightly_manual_trigger === 'undefined' || nightly_manual_trigger === '') { + return 'false'; + } else if (context.eventName === 'schedule' || context.eventName === 'workflow_dispatch' && nightly_manual_trigger === 'true' ) { + return 'true'; + } + return 'false'; + }; + core.setOutput('is_nightly', getNightlyInput()); + - name: Get docker images version id: get_docker_images_version run: | @@ -251,6 +277,7 @@ jobs: ['stability', '${{ steps.get_stability.outputs.stability }}'], ['release_type', '${{ steps.get_release_type.outputs.release_type || 'not defined because this is not a release' }}'], ['is_targeting_feature_branch', '${{ steps.get_stability.outputs.is_targeting_feature_branch }}'], + ['is_nightly', '${{ steps.get_nightly_status.outputs.is_nightly }}'], ['img_version', '${{ steps.get_docker_images_version.outputs.img_version }}'], ['test_img_version', '${{ steps.get_docker_images_version.outputs.test_img_version }}'], ]; diff --git a/.github/workflows/package-collect.yml b/.github/workflows/package-collect.yml index 56746f1b15..fb47c28cd0 100644 --- a/.github/workflows/package-collect.yml +++ b/.github/workflows/package-collect.yml @@ -42,8 +42,30 @@ on: arch: required: true type: string - - + is_nightly: + required: false + type: string + secrets: + collect_s3_access_key: + required: true + collect_s3_secret_key: + required: true + registry_username: + required: true + registry_password: + required: true + rpm_gpg_key: + required: true + rpm_gpg_signing_key_id: + required: true + rpm_gpg_signing_passphrase: + required: true + jira_base_url: + required: true + jira_user_email: + required: true + jira_api_token: + required: true jobs: package: runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner)) }} @@ -52,14 +74,14 @@ jobs: SCCACHE_PATH: "/usr/bin/sccache" SCCACHE_BUCKET: "centreon-github-sccache" SCCACHE_REGION: "eu-west-1" - AWS_ACCESS_KEY_ID: ${{ secrets.COLLECT_S3_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.COLLECT_S3_SECRET_KEY }} + AWS_ACCESS_KEY_ID: ${{ secrets.collect_s3_access_key }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.collect_s3_secret_key }} container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ inputs.image }}:${{ inputs.img_version }} credentials: - username: ${{ secrets.HARBOR_CENTREON_PULL_USERNAME }} - password: ${{ secrets.HARBOR_CENTREON_PULL_TOKEN }} + username: ${{ secrets.registry_username }} + password: ${{ secrets.registry_password }} name: package ${{ inputs.distrib }} ${{ inputs.arch }} @@ -194,9 +216,9 @@ jobs: arch: ${{ inputs.arch }} commit_hash: ${{ inputs.commit_hash }} cache_key: ${{ github.run_id }}-${{ github.sha }}-${{ inputs.package_extension}}-centreon-collect-${{ inputs.distrib }}-${{ inputs.arch }}-${{ github.head_ref || github.ref_name }} - rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} - rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} - rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + rpm_gpg_key: ${{ secrets.rpm_gpg_key }} + rpm_gpg_signing_key_id: ${{ secrets.rpm_gpg_signing_key_id }} + rpm_gpg_signing_passphrase: ${{ secrets.rpm_gpg_signing_passphrase }} stability: ${{ inputs.stability }} - name: Cleaning not needed packages @@ -209,5 +231,22 @@ jobs: uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: packages-${{ inputs.distrib }}-${{ inputs.arch }} - path: ./*.${{ inputs.package_extension}} + path: ./*.${{ inputs.package_extension }} retention-days: 1 + + create-jira-nightly-ticket: + needs: [package] + runs-on: ubuntu-24.04 + if: | + inputs.is_nightly == 'true' && github.run_attempt == 1 && + (failure() || cancelled()) && + startsWith(github.ref_name, 'dev') + steps: + - name: Create Jira ticket if nightly build failure + uses: ./.github/actions/create-jira-ticket + with: + jira_base_url: ${{ secrets.jira_base_url }} + jira_user_email: ${{ secrets.jira_user_email }} + jira_api_token: ${{ secrets.jira_api_token }} + module_name: "centreon-collect" + ticket_labels: '["Nightly", "Pipeline", "nightly-${{ github.ref_name }}", "package"]' diff --git a/.github/workflows/robot-test.yml b/.github/workflows/robot-test.yml index 2b34168ae2..fb0ecbe781 100644 --- a/.github/workflows/robot-test.yml +++ b/.github/workflows/robot-test.yml @@ -31,6 +31,9 @@ on: test_group_name: required: true type: string + is_nightly: + required: false + type: string secrets: registry_username: required: true @@ -44,7 +47,12 @@ on: required: true xray_client_secret: required: true - + jira_base_url: + required: true + jira_user_email: + required: true + jira_api_token: + required: true jobs: test-image-to-cache: runs-on: ${{ contains(inputs.image, 'arm') && fromJson('["self-hosted", "collect-arm64"]') || 'ubuntu-24.04' }} @@ -265,3 +273,23 @@ jobs: gh_access_token: ${{ secrets.GITHUB_TOKEN }} report_path: reports show_passed_tests: false + + create-jira-nightly-ticket: + needs: [robot-test-list, robot-test, robot-test-report] + runs-on: ubuntu-24.04 + if: | + inputs.is_nightly == 'true' && github.run_attempt == 1 && + (failure() || cancelled()) && + startsWith(github.ref_name, 'dev') + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Create Jira ticket if nightly build failure + uses: ./.github/actions/create-jira-ticket + with: + jira_base_url: ${{ secrets.jira_base_url }} + jira_user_email: ${{ secrets.jira_user_email }} + jira_api_token: ${{ secrets.jira_api_token }} + module_name: "centreon-collect" + ticket_labels: '["Nightly", "Pipeline", "nightly-${{ github.ref_name }}", "robot-test"]'