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_reason_for_creation:
    required: true
    description: reason for ticket creation
    default: "Nightly"

runs:
  using: "composite"
  steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

    - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
      with:
        node-version: 24

    - if: inputs.ticket_reason_for_creation == 'Nightly'
      name: Create nightly epic if it does not exist already
      uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
      env:
        GH_TOKEN: ${{ github.token }}
      id: get_nightly_epic
      with:
        script: |
          const fs = require('fs');
          const { execSync } = require('child_process');
          const now = new Date();
          const month = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
          const path = './epic-payload.json';

          let ticket_summary = `centreon-collect nightly incidents on ${month}`
          let nightly_epic_id, nightly_epic_key;

          const encodedJql = encodeURIComponent(`project = "MON" AND summary ~ "${ticket_summary}" AND type = Epic`);

          let response = JSON.parse(
            execSync(
              `curl --request GET \
                --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
                --header "Accept: application/json" \
                --url "${{ inputs.jira_base_url }}/rest/api/3/search/jql?jql=${encodedJql}&fields=summary,key&maxResults=1"`,
            { encoding: 'utf-8' }
            )
          );

          console.log("response:\n", response);
          total = response.issues.length;
          console.log(`Number of epics with this name: ${total}`);

          if (total === 0) {
            ticket_data =
              {
                "fields": {
                  "summary": ticket_summary,
                  "project": {"key": "MON"},
                  "issuetype": {"id": "10000"},
                  "labels": ["Pipeline", "${{ inputs.ticket_reason_for_creation }}" ]
                }
              }

            fs.writeFileSync(path, JSON.stringify(ticket_data));

            let response = execSync(
              `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 @${path}
              `,
              { encoding: 'utf8' }
            );

            nightly_epic_id = JSON.parse(response).id;
            nightly_epic_key = JSON.parse(response).key;
            console.log(`An epic for the current month and project (ID ${nightly_epic_id}, key ${nightly_epic_key}) has been created.`);
          } else {
            nightly_epic_id = response.issues[0].id;
            nightly_epic_key = response.issues[0].key;
            console.log(`An epic for the current month and project (ID ${nightly_epic_id}, key ${nightly_epic_key}) has already been found.`);
          }

          core.setOutput('nightly_epic_id', nightly_epic_id);
          core.setOutput('nightly_epic_key', nightly_epic_key);

    - name: Get ticket elements from context and create the incident ticket
      uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
      env:
        GH_TOKEN: ${{ github.token }}
      id: get_context
      with:
        script: |
          const fs = require('fs');
          const { execSync } = require('child_process');
          function formatDate(date) {
            return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
          }
          function getIsoWeek(date) {
            const temp = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
            const dayNumber = temp.getUTCDay() || 7;
            temp.setUTCDate(temp.getUTCDate() + 4 - dayNumber);
            const yearStart = new Date(Date.UTC(temp.getUTCFullYear(), 0, 1));
            return Math.ceil((((temp - yearStart) / 86400000) + 1) / 7);
          }
          const now = new Date();
          const date = formatDate(now);
          const isoWeekNumber = getIsoWeek(now);
          const nightly_epic_id = ${{ steps.get_nightly_epic.outputs.nightly_epic_id }}
          const nightly_epic_key = "${{ steps.get_nightly_epic.outputs.nightly_epic_key }}"
          const JSON_TEMPLATE_FILE = "./.github/actions/create-jira-ticket/nightly-ticket-template.json";
          const path = './ticket-payload.json';
          let contents, data, ticket_summary, ticket_squad_id, ticket_board_id, squad_name, ticket_labels, current_sprint, ticket_data, ticket_key;

          let failed_jobs = JSON.parse(execSync(
            `gh run view ${{ github.run_id }} --json jobs -q '[.jobs[] | select(.conclusion == "failure") | .name | split(" ")[0] ] | unique'`,
            { encoding: 'utf8' }
          ));
          console.log(failed_jobs);

          for (const failed_job of failed_jobs) {
            ticket_labels = ["Pipeline", "${{ inputs.ticket_reason_for_creation }}" ]
            console.log(`Failed job: ${failed_job}`);
            if (ticket_labels.includes("Nightly")) {
              ticket_summary = `${{ inputs.module_name }}-${{ github.base_ref || github.ref_name }} nightly build failure on ${failed_job}`

              data = fs.readFileSync(JSON_TEMPLATE_FILE, { encoding: 'utf8' });
              data = data.replace(/@MODULE_NAME@/g, '${{ inputs.module_name }}');
              data = data.replace(/@DATE@/g, date);

              data = data.replace(/@GITHUB_BRANCH@/g, '${{ github.base_ref || github.ref_name }}');
              data = data.replace(/@GITHUB_SERVER_URL@/g, '${{ github.server_url }}');
              data = data.replace(/@FAILED_JOB@/g, failed_job);
              data = data.replace(/@GITHUB_REPOSITORY@/g, '${{ github.repository }}');
              data = data.replace(/@GITHUB_RUN_ID@/g, '${{ github.run_id }}');
              data = data.replace(/@GITHUB_RUN_ATTEMPT@/g, '${{ github.run_attempt }}');
            } else {
              throw new Error(`❌ Could not find any labelling option for the ticket.`);
            }

            console.log(data);

            if (["get-environment", "package", "deliver-sources", "deliver-rpm", "deliver-deb"].includes(failed_job)) {
              ticket_squad_id = 10524
              ticket_board_id = 184
              squad_name = "DEVSECOPS"
            } else if (["unit-test", "robot-test"].includes(failed_job)) {
              ticket_squad_id=10255
              ticket_board_id=118
              squad_name = "COLLECT"
            } else {
              core.setFailed(`Not finding any squad association with job ${failed_job}.`);
              continue;
            }

            console.log(`Ticket summary: ${ticket_summary}`);
            console.log(`Ticket will be attributed to the ${squad_name} team. (Squad ID ${ticket_squad_id}, Board ID ${ticket_board_id})`)

            const encodedJql = encodeURIComponent(`project = "MON" AND summary ~ "${ticket_summary}" AND statusCategory NOT IN (Done)`);
            let response = JSON.parse(
              execSync(
                `curl --request GET \
                  --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
                  --header "Accept: application/json" \
                  --url "${{ inputs.jira_base_url }}/rest/api/3/search/jql?jql=${encodedJql}&fields=summary,key&maxResults=1"`,
              { encoding: 'utf-8' }
              )
            );
            console.log("response:\n", response);

            total = response.issues.length;
            console.log(`Number of tickets with this name: ${total}`);

            if (total === 0) {
              ticket_summary = `${date} ${ticket_summary}`;

              // Disabled temporarily, to reenable when the pipeline is more stable
              // current_sprint = execSync(
              //   `curl --request GET \
              //     --url ${{ inputs.jira_base_url }}/rest/agile/1.0/board/${ticket_board_id}/sprint?state=active \
              //     --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
              //     --header "Accept: application/json" | jq --arg squad_name "$squad_name" '.values[] | select(.name | test($squad_name; "i")) | .id'
              //   `,
              //   { encoding: 'utf8' }
              // );

              // console.log(`Current sprint: ${current_sprint}`);

              // Creating a new incident ticket on Jira
              data = JSON.parse(data);
              ticket_data =
                {
                  "fields": {
                    "summary": ticket_summary,
                    "project": {"key": "MON"},
                    "issuetype": {"id": "10209"},
                    "parent": {"id": `${nightly_epic_id}`, "key": `${nightly_epic_key}`},
                    "labels": ticket_labels,
                    "components": [{"name": "${{ inputs.module_name }}"}],
                    "customfield_10902": {"id": `${ticket_squad_id}`, "value": `${squad_name}`},
                    "description": data
                  }
                }

              // Desactivated temporarily, activating when the pipeline is more stable
              // if (current_sprint !== null) {
              //   ticket_data.fields.customfield_10007 = parseInt(current_sprint, 10);
              // }

              fs.writeFileSync(path, JSON.stringify(ticket_data));
              contents = fs.readFileSync(path, 'utf8');
              console.log("Ticket Payload:\n", contents);
              let response = execSync(
                `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 @${path}
                `,
                { encoding: 'utf8' }
              );

              console.log(`Response on ticket creation:\n ${response}`);

              ticket_key = JSON.parse(response).key;
              core.notice(`Created ticket: ${ticket_key}`);

              // Update priority on newly created ticket since you cannot create a ticket with another priority than medium
              response = execSync(
                `curl --request PUT \
                  --url "${{ inputs.jira_base_url }}/rest/api/3/issue/${ticket_key}" \
                  --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
                  --header 'Accept: application/json' \
                  --header 'Content-Type: application/json' \
                  --data '{ "fields": { "priority": { "id": "2" } } }'
                `,
                { encoding: 'utf8' }
              );

              console.log(`Response on priority change:\n ${response}`);

              // Update ticket status to NEED REFINEMENT and then SPRINT READY so that squad members can see it in their respective sprints
              // for (const transition_id of [11, 21]) {
              //  response = execSync(
              //    `curl --request POST \
              //    --url "${{ inputs.jira_base_url }}/rest/api/latest/issue/${ticket_key}/transitions" \
              //    --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
              //    --header 'Accept: application/json' \
              //    --header 'Content-Type: application/json' \
              //    --data '{"transition": {"id": "${transition_id}"} }'
              //  `,
              //  { encoding: 'utf8' }
              // )

              // console.log(`Response on ticket status change: ${response}`);
              // }
            } else {
              const ticket_key = response.issues[0].key;
              console.log(`A ticket (ID ${ticket_key}) has already been found. Adding new entry in the description...`);

              data = JSON.parse(data).content[2].content[0];
              console.log("data after shrinking:\n ", data);

              let ticket_description = JSON.parse(
                execSync(
                  `curl --request GET \
                  --url "${{ inputs.jira_base_url }}/rest/api/3/issue/${ticket_key}" \
                  --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
                  --header "Accept: application/json" | jq '.fields.description'`,
                  { encoding: 'utf8' }
                )
              );

              ticket_description.content[2].content.push(data);
              console.log("ticket_description:\n", ticket_description);

              ticket_description = { fields: { description: ticket_description } };

              fs.writeFileSync(path, JSON.stringify(ticket_description));
              console.log("complete ticket description:\n", JSON.stringify(JSON.parse(fs.readFileSync(path, "utf8")), null, 2));

              response = execSync(
                `curl --request PUT \
                  --url "${{ inputs.jira_base_url }}/rest/api/3/issue/${ticket_key}" \
                  --user "${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}" \
                  --header "Accept: application/json" \
                  --header "Content-Type: application/json" \
                  --data @${path}`,
                { encoding: 'utf8' }
              )

              console.log(`Response on ticket description change: ${response}`);
            }
          }
