app.rb 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. # frozen_string_literal: true
  2. # Copyright 2020 Google LLC
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. require 'octokit'
  16. require 'optparse'
  17. require 'json'
  18. require 'tzinfo'
  19. REPO_NAME_WITH_OWNER = ENV['GITHUB_REPOSITORY']
  20. GITHUB_WORKFLOW_URL = "https://github.com/#{REPO_NAME_WITH_OWNER}/actions/runs/#{ENV['GITHUB_RUN_ID']}"
  21. TESTS_TIME_INTERVAL_IN_HOURS = 24
  22. TESTS_TIME_INTERVAL_IN_SECS = TESTS_TIME_INTERVAL_IN_HOURS * 3600
  23. NO_WORKFLOW_RUNNING_INFO = "All nightly cron job were not run in the last #{TESTS_TIME_INTERVAL_IN_HOURS} hrs. Please review [log](#{GITHUB_WORKFLOW_URL}) make sure there at least exists one cron job running.".freeze
  24. EXCLUDED_WORKFLOWS = []
  25. ISSUE_LABELS = ""
  26. ISSUE_TITLE = "Auto-Generated Testing Report"
  27. if not ENV['INPUT_EXCLUDE-WORKFLOW-FILES'].nil?
  28. EXCLUDED_WORKFLOWS = ENV['INPUT_EXCLUDE-WORKFLOW-FILES'].split(/[ ,]/)
  29. end
  30. if not ENV['INPUT_ISSUE-LABELS'].nil?
  31. ISSUE_LABELS = ENV['INPUT_ISSUE-LABELS']
  32. end
  33. if not ENV['INPUT_ISSUE-TITLE'].nil?
  34. ISSUE_TITLE = ENV['INPUT_ISSUE-TITLE']
  35. end
  36. ASSIGNEE = ENV['INPUT_ASSIGNEES']
  37. TIMEZONE = 'US/Pacific'
  38. class Table
  39. def initialize(title)
  40. # tz is to help adjust daylight saving time and regular time.
  41. tz = TZInfo::Timezone.get(TIMEZONE)
  42. # tz.to_local(Time.new(2018, 3, 11, 2, 30, 0, "-08:00")) will return
  43. # 2018-03-11 03:30:00 -0700
  44. cur_time = tz.to_local(Time.now.utc.localtime("-08:00"))
  45. @is_empty_table = true
  46. @text = String.new ""
  47. @text << "# %s\n" % [title]
  48. @text << "This issue([log](%s)) is generated at %s, fetching workflow runs triggered in the last %s hrs.\n" % [GITHUB_WORKFLOW_URL, cur_time.strftime('%m/%d/%Y %H:%M %p'), TESTS_TIME_INTERVAL_IN_HOURS ]
  49. # get a table with two columns, workflow and the date of yesterday.
  50. @text << "| Workflow |"
  51. @text << (cur_time - TESTS_TIME_INTERVAL_IN_SECS).strftime('%m/%d') + "|"
  52. @text << "\n| -------- |"
  53. @text << " -------- |"
  54. @text << "\n"
  55. end
  56. def add_workflow_run_and_result(workflow, result)
  57. @is_empty_table = false if @is_empty_table
  58. record = "| %s | %s |\n" % [workflow, result]
  59. @text << record
  60. end
  61. def get_report()
  62. if @is_empty_table
  63. return nil
  64. end
  65. return @text
  66. end
  67. end
  68. def get_workflows(client, repo_name)
  69. workflow_page = 0
  70. workflows = []
  71. loop do
  72. workflow_page += 1
  73. cur_page_workflows = client.workflows(repo_name, :page => workflow_page).workflows
  74. if cur_page_workflows.length == 0
  75. break
  76. end
  77. workflows.push(*cur_page_workflows)
  78. end
  79. return workflows
  80. end
  81. failure_report = Table.new(ISSUE_TITLE)
  82. success_report = Table.new(ISSUE_TITLE)
  83. client = Octokit::Client.new(access_token: ENV["INPUT_ACCESS-TOKEN"])
  84. last_issue = client.list_issues(REPO_NAME_WITH_OWNER, :labels => ISSUE_LABELS, :state => "all")[0]
  85. puts "Excluded workflow files: " + EXCLUDED_WORKFLOWS.join(",")
  86. for wf in get_workflows(client, REPO_NAME_WITH_OWNER) do
  87. # skip if it is the issue generation workflow.
  88. if wf.name == ENV["GITHUB_WORKFLOW"]
  89. next
  90. end
  91. workflow_file = File.basename(wf.path)
  92. puts "------------"
  93. puts "workflow_file: %s" % [workflow_file]
  94. if EXCLUDED_WORKFLOWS.include?(workflow_file)
  95. puts workflow_file + " is excluded in the report."
  96. next
  97. end
  98. workflow_text = "[%s](%s)" % [wf.name, wf.html_url]
  99. runs = client.workflow_runs(REPO_NAME_WITH_OWNER, File.basename(wf.path), :event => "schedule").workflow_runs
  100. runs = runs.sort_by { |run| -run.created_at.to_i }
  101. latest_run = runs[0]
  102. if latest_run.nil?
  103. puts "no schedule runs found."
  104. # Involved workflow runs triggered within one day.
  105. elsif Time.now.utc - latest_run.created_at < TESTS_TIME_INTERVAL_IN_SECS
  106. puts "created_at: %s" % [latest_run.created_at]
  107. puts "conclusion: %s" % [latest_run.conclusion]
  108. result_text = "[%s](%s)" % [latest_run.conclusion.nil? ? "in_process" : latest_run.conclusion, latest_run.html_url]
  109. if latest_run.conclusion == "success"
  110. success_report.add_workflow_run_and_result(workflow_text, result_text)
  111. else
  112. failure_report.add_workflow_run_and_result(workflow_text, result_text)
  113. end
  114. else
  115. puts "created_at: %s" % [latest_run.created_at]
  116. puts "conclusion: %s" % [latest_run.conclusion]
  117. end
  118. end
  119. # Check if there exists any cron jobs.
  120. if failure_report.get_report.nil? && success_report.get_report.nil?
  121. if last_issue.state == "open"
  122. client.add_comment(REPO_NAME_WITH_OWNER, last_issue.number, NO_WORKFLOW_RUNNING_INFO)
  123. else
  124. client.create_issue(REPO_NAME_WITH_OWNER, ISSUE_TITLE, NO_WORKFLOW_RUNNING_INFO, labels: ISSUE_LABELS, assignee: ASSIGNEE)
  125. end
  126. # Close an issue if all workflows succeed.
  127. elsif failure_report.get_report.nil? and last_issue.state == "open"
  128. client.add_comment(REPO_NAME_WITH_OWNER, last_issue.number, success_report.get_report)
  129. client.close_issue(REPO_NAME_WITH_OWNER, last_issue.number)
  130. # If the last issue is open, then failed report will be commented to the issue.
  131. elsif !last_issue.nil? and last_issue.state == "open"
  132. client.add_comment(REPO_NAME_WITH_OWNER, last_issue.number,failure_report.get_report)
  133. # Create a new issue if there exists failed workflows.
  134. else
  135. client.create_issue(REPO_NAME_WITH_OWNER, ISSUE_TITLE, failure_report.get_report, labels: ISSUE_LABELS, assignee: ASSIGNEE) unless failure_report.get_report.nil?
  136. end