app.rb 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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. NO_WORKFLOW_RUNNING_INFO = 'All nightly cron job were not run. Please make sure there at least exists one cron job running.'.freeze
  21. EXCLUDED_WORKFLOWS = []
  22. ISSUE_LABELS = ""
  23. ISSUE_TITLE = "Auto-Generated Testing Report"
  24. if not ENV['INPUT_EXCLUDE-WORKFLOW-FILES'].nil?
  25. EXCLUDED_WORKFLOWS = ENV['INPUT_EXCLUDE-WORKFLOW-FILES'].split(/[ ,]/)
  26. end
  27. if not ENV['INPUT_ISSUE-LABELS'].nil?
  28. ISSUE_LABELS = ENV['INPUT_ISSUE-LABELS']
  29. end
  30. if not ENV['INPUT_ISSUE-TITLE'].nil?
  31. ISSUE_TITLE = ENV['INPUT_ISSUE-TITLE']
  32. end
  33. ASSIGNEE = ENV['INPUT_ASSIGNEES']
  34. TIMEZONE = 'US/Pacific'
  35. class Table
  36. def initialize(title)
  37. # tz is to help adjust daylight saving time and regular time.
  38. tz = TZInfo::Timezone.get(TIMEZONE)
  39. # tz.to_local(Time.new(2018, 3, 11, 2, 30, 0, "-08:00")) will return
  40. # 2018-03-11 03:30:00 -0700
  41. cur_time = tz.to_local(Time.now.utc.localtime("-08:00"))
  42. @is_empty_table = true
  43. @text = String.new ""
  44. @text << "# %s\n" % [title]
  45. @text << "This issue is generated at %s\n" % [cur_time.strftime('%m/%d/%Y %H:%M %p') ]
  46. # get a table with two columns, workflow and the date of yesterday.
  47. @text << "| Workflow |"
  48. @text << (cur_time - 86400).strftime('%m/%d') + "|"
  49. @text << "\n| -------- |"
  50. @text << " -------- |"
  51. @text << "\n"
  52. end
  53. def add_workflow_run_and_result(workflow, result)
  54. @is_empty_table = false if @is_empty_table
  55. record = "| %s | %s |\n" % [workflow, result]
  56. @text << record
  57. end
  58. def get_report()
  59. if @is_empty_table
  60. return nil
  61. end
  62. return @text
  63. end
  64. end
  65. def get_workflows(client, repo_name)
  66. workflow_page = 0
  67. workflows = []
  68. loop do
  69. workflow_page += 1
  70. cur_page_workflows = client.workflows(repo_name, :page => workflow_page).workflows
  71. if cur_page_workflows.length == 0
  72. break
  73. end
  74. workflows.push(*cur_page_workflows)
  75. end
  76. return workflows
  77. end
  78. failure_report = Table.new(ISSUE_TITLE)
  79. success_report = Table.new(ISSUE_TITLE)
  80. client = Octokit::Client.new(access_token: ENV["INPUT_ACCESS-TOKEN"])
  81. last_issue = client.list_issues(REPO_NAME_WITH_OWNER, :labels => ISSUE_LABELS, :state => "all")[0]
  82. puts "Excluded workflow files: " + EXCLUDED_WORKFLOWS.join(",")
  83. for wf in get_workflows(client, REPO_NAME_WITH_OWNER) do
  84. # skip if it is the issue generation workflow.
  85. if wf.name == ENV["GITHUB_WORKFLOW"]
  86. next
  87. end
  88. workflow_file = File.basename(wf.path)
  89. puts "------------"
  90. puts "workflow_file: %s" % [workflow_file]
  91. workflow_text = "[%s](%s)" % [wf.name, wf.html_url]
  92. runs = client.workflow_runs(REPO_NAME_WITH_OWNER, File.basename(wf.path), :event => "schedule").workflow_runs
  93. runs = runs.sort_by { |run| -run.created_at.to_i }
  94. latest_run = runs[0]
  95. if latest_run.nil?
  96. puts "no schedule runs found."
  97. elsif EXCLUDED_WORKFLOWS.include?(workflow_file)
  98. puts workflow_file + " is excluded in the report."
  99. # Involved workflow runs triggered within one day.
  100. elsif Time.now.utc - latest_run.created_at < 86400
  101. puts "created_at: %s" % [latest_run.created_at]
  102. puts "conclusion: %s" % [latest_run.conclusion]
  103. result_text = "[%s](%s)" % [latest_run.conclusion.nil? ? "in_process" : latest_run.conclusion, latest_run.html_url]
  104. if latest_run.conclusion == "success"
  105. success_report.add_workflow_run_and_result(workflow_text, result_text)
  106. else
  107. failure_report.add_workflow_run_and_result(workflow_text, result_text)
  108. end
  109. end
  110. end
  111. # Check if there exists any cron jobs.
  112. if failure_report.get_report.nil? && success_report.get_report.nil?
  113. if last_issue.state == "open"
  114. client.add_comment(REPO_NAME_WITH_OWNER, last_issue.number, NO_WORKFLOW_RUNNING_INFO)
  115. else
  116. client.create_issue(REPO_NAME_WITH_OWNER, ISSUE_TITLE, NO_WORKFLOW_RUNNING_INFO, labels: ISSUE_LABELS, assignee: ASSIGNEE)
  117. end
  118. # Close an issue if all workflows succeed.
  119. elsif failure_report.get_report.nil? and last_issue.state == "open"
  120. client.add_comment(REPO_NAME_WITH_OWNER, last_issue.number, success_report.get_report)
  121. client.close_issue(REPO_NAME_WITH_OWNER, last_issue.number)
  122. # If the last issue is open, then failed report will be commented to the issue.
  123. elsif !last_issue.nil? and last_issue.state == "open"
  124. client.add_comment(REPO_NAME_WITH_OWNER, last_issue.number,failure_report.get_report)
  125. # Create a new issue if there exists failed workflows.
  126. else
  127. client.create_issue(REPO_NAME_WITH_OWNER, ISSUE_TITLE, failure_report.get_report, labels: ISSUE_LABELS, assignee: ASSIGNEE) unless failure_report.get_report.nil?
  128. end