diff --git a/README.md b/README.md index 81cd47d..ce1e0c5 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,9 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ORGANIZATION: + + - name: Post evergreen job summary + run: cat summary.md >> $GITHUB_STEP_SUMMARY ``` #### Advanced @@ -249,6 +252,9 @@ jobs: TITLE: "Add dependabot configuration" BODY: "Please add this dependabot configuration so that we can keep the dependencies in this repo up to date and secure. for help, contact XXX" CREATED_AFTER_DATE: ${{ env.one_week_ago }} + + - name: Post evergreen job summary + run: cat summary.md >> $GITHUB_STEP_SUMMARY ``` #### Using GitHub app @@ -281,6 +287,9 @@ jobs: ORGANIZATION: your_organization UPDATE_EXISTING: True GROUP_DEPENDENCIES: True + + - name: Post evergreen job summary + run: cat summary.md >> $GITHUB_STEP_SUMMARY ``` ## Local usage without Docker diff --git a/evergreen.py b/evergreen.py index 9ddbadc..7c41baa 100644 --- a/evergreen.py +++ b/evergreen.py @@ -77,6 +77,28 @@ def main(): # pragma: no cover organization, team_name, repository_list, github_connection ) + # Setting up the action summary content + summary_content = f""" + ## 🚀 Job Summary + - **Organization:** {organization} + - **Follow Up Type:** {follow_up_type} + - **Dry Run:** {dry_run} + - **Enable Security Updates:** {enable_security_updates} + """ + # Add optional parameters to the summary + if project_id: + project_link = f"https://github.com/orgs/{organization}/projects/{project_id}" + summary_content += f"- **Project ID:** [{project_id}]({project_link})\n" + if batch_size: + summary_content += f"- **Batch Size:** {batch_size}\n" + + # Add the updated repositories table header + summary_content += ( + "\n\n## 📋 Updated Repositories\n\n" + "| Repository | 🔒 Security Updates Enabled | 🔄 Follow Up Type | 🔗 Link |\n" + "| --- | --- | --- | --- |\n" + ) + # Iterate through the repositories and open an issue/PR if dependabot is not enabled count_eligible = 0 for repo in repos: @@ -187,12 +209,14 @@ def main(): # pragma: no cover ): enable_dependabot_security_updates(ghe, repo.owner, repo.name, token) + link = "" if follow_up_type == "issue": skip = check_pending_issues_for_duplicates(title, repo) if not skip: count_eligible += 1 body_issue = f"{body}\n\n```yaml\n# {dependabot_filename_to_use} \n{dependabot_file}\n```" issue = repo.create_issue(title, body_issue) + link = issue.html_url print(f"\tCreated issue {issue.html_url}") if project_id: issue_id = get_global_issue_id( @@ -217,6 +241,7 @@ def main(): # pragma: no cover dependabot_filename_to_use, existing_config, ) + link = pull.html_url print(f"\tCreated pull request {pull.html_url}") if project_id: pr_id = get_global_pr_id( @@ -228,6 +253,12 @@ def main(): # pragma: no cover except github3.exceptions.NotFoundError: print("\tFailed to create pull request. Check write permissions.") continue + # Append the repository to the summary content + summary_content += f"| {repo.full_name} | {'✅' if enable_security_updates else '❌'} | {follow_up_type} | [Link]({link}) |\n" + + print(f"Done. {str(count_eligible)} repositories were eligible.") + # Append the summary content to the GitHub step summary file + append_to_github_summary(summary_content) print(f"Done. {str(count_eligible)} repositories were eligible.") @@ -496,5 +527,14 @@ def link_item_to_project(ghe, token, project_id, item_id): return None +def append_to_github_summary(content, summary_file="summary.md"): + """ + Append content to the GitHub step summary file + """ + if summary_file: + with open(summary_file, "a", encoding="utf-8") as f: + f.write(content + "\n") + + if __name__ == "__main__": main() # pragma: no cover diff --git a/test_evergreen.py b/test_evergreen.py index f0a9a0e..41dc08f 100644 --- a/test_evergreen.py +++ b/test_evergreen.py @@ -7,6 +7,7 @@ import github3 import requests from evergreen import ( + append_to_github_summary, check_existing_config, check_pending_issues_for_duplicates, check_pending_pulls_for_duplicates, @@ -738,5 +739,40 @@ def test_check_existing_config_without_existing_config(self): self.assertIsNone(result) +class TestAppendToGithubSummary(unittest.TestCase): + """Test the append_to_github_summary function in evergreen.py""" + + @patch("builtins.open", new_callable=unittest.mock.mock_open) + def test_append_to_github_summary_with_file(self, mock_file): + """Test that content is appended to the specified summary file.""" + content = "Test summary content" + summary_file = "summary.md" + + append_to_github_summary(content, summary_file) + + mock_file.assert_called_once_with(summary_file, "a", encoding="utf-8") + mock_file().write.assert_called_once_with(content + "\n") + + @patch("builtins.open", new_callable=unittest.mock.mock_open) + def test_append_to_github_summary_without_summary_file(self, mock_file): + """Test that content is not written when summary_file is None or empty.""" + content = "Test summary content" + summary_file = "" + + append_to_github_summary(content, summary_file) + + mock_file.assert_not_called() + + @patch("builtins.open", new_callable=unittest.mock.mock_open) + def test_append_to_github_summary_with_default_file(self, mock_file): + """Test that content is appended to the default summary file when summary_file is not provided.""" + content = "Test summary content" + + append_to_github_summary(content) + + mock_file.assert_called_once_with("summary.md", "a", encoding="utf-8") + mock_file().write.assert_called_once_with(content + "\n") + + if __name__ == "__main__": unittest.main()