Skip to content

Commit 3e09c1c

Browse files
authored
Merge branch 'main' into copilot/fix-377
2 parents 8c74c03 + 4229a2d commit 3e09c1c

File tree

8 files changed

+192
-15
lines changed

8 files changed

+192
-15
lines changed

.github/copilot-instructions.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copilot Instructions
2+
3+
This is a GitHub Action that given an organization, team, or specified repositories, opens an issue/PR if dependabot is not enabled, or there are more package ecosystems that could be added. It also enables [automated security updates](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#managing-dependabot-security-updates-for-your-repositories) for the repository. Please follow these guidelines when contributing:
4+
5+
## Code Standards
6+
7+
### Required Before Each Commit
8+
9+
- Run `make lint` before committing any changes to ensure proper code linting and formatting.
10+
11+
### Development Flow
12+
13+
- Lint: `make lint`
14+
- Test: `make test`
15+
16+
## Repository Structure
17+
18+
- `Makefile`: Contains commands for linting, testing, and other tasks
19+
- `requirements.txt`: Python dependencies for the project
20+
- `requirements-test.txt`: Python dependencies for testing
21+
- `README.md`: Project documentation and setup instructions
22+
- `setup.py`: Python package setup configuration
23+
- `test_*.py`: Python test files matching the naming convention for test discovery
24+
25+
## Key Guidelines
26+
27+
1. Follow Python best practices and idiomatic patterns
28+
2. Maintain existing code structure and organization
29+
3. Write unit tests for new functionality.
30+
4. Document changes to environment variables in the `README.md` file.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: "Copilot Setup Steps"
2+
3+
# Automatically run the setup steps when they are changed to allow for easy validation, and
4+
# allow manual testing through the repository's "Actions" tab
5+
on:
6+
workflow_dispatch:
7+
push:
8+
paths:
9+
- .github/workflows/copilot-setup-steps.yml
10+
pull_request:
11+
paths:
12+
- .github/workflows/copilot-setup-steps.yml
13+
14+
# Set the permissions to the lowest permissions possible needed for your steps.
15+
# Copilot will be given its own token for its operations.
16+
permissions:
17+
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
18+
contents: read
19+
20+
jobs:
21+
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
22+
copilot-setup-steps:
23+
runs-on: ubuntu-latest
24+
25+
# You can define any steps you want, and they will run before the agent starts.
26+
# If you do not check out your code, Copilot will do this for you.
27+
steps:
28+
- name: Checkout code
29+
uses: actions/[email protected]
30+
31+
- name: Set up Python
32+
uses: actions/[email protected]
33+
with:
34+
python-version: 3.12
35+
36+
- name: Install dependencies
37+
run: |
38+
pip install -r requirements.txt -r requirements-test.txt

.github/workflows/super-linter.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ jobs:
3535
DEFAULT_BRANCH: main
3636
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3737
GITHUB_ACTIONS_COMMAND_ARGS: -shellcheck=
38+
FIX_MARKDOWN_PRETTIER: true

README.md

Lines changed: 48 additions & 5 deletions
Large diffs are not rendered by default.

env.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def get_env_vars(
9999
) -> tuple[
100100
str | None,
101101
list[str],
102+
str | None,
102103
int | None,
103104
int | None,
104105
bytes,
@@ -135,6 +136,7 @@ def get_env_vars(
135136
Returns:
136137
organization (str): The organization to search for repositories in
137138
repository_list (list[str]): A list of repositories to search for
139+
search_query (str): A search query string to filter repositories by
138140
gh_app_id (int | None): The GitHub App ID to use for authentication
139141
gh_app_installation_id (int | None): The GitHub App Installation ID to use for authentication
140142
gh_app_private_key_bytes (bytes): The GitHub App Private Key as bytes to use for authentication
@@ -162,18 +164,19 @@ def get_env_vars(
162164
dependabot_config_file (str): Dependabot extra configuration file location path
163165
"""
164166

165-
if not test:
167+
if not test: # pragma: no cover
166168
# Load from .env file if it exists and not testing
167169
dotenv_path = join(dirname(__file__), ".env")
168170
load_dotenv(dotenv_path)
169171

170172
organization = os.getenv("ORGANIZATION")
171173
repositories_str = os.getenv("REPOSITORY")
174+
search_query = os.getenv("REPOSITORY_SEARCH_QUERY", "").strip()
172175
team_name = os.getenv("TEAM_NAME")
173-
# Either organization or repository must be set
174-
if not organization and not repositories_str:
176+
# Either organization, repository, or search_query must be set
177+
if not organization and not repositories_str and not search_query:
175178
raise ValueError(
176-
"ORGANIZATION and REPOSITORY environment variables were not set. Please set one"
179+
"ORGANIZATION, REPOSITORY, and REPOSITORY_SEARCH_QUERY environment variables were not set. Please set one"
177180
)
178181
# Team name and repository are mutually exclusive
179182
if repositories_str and team_name:
@@ -352,6 +355,7 @@ def get_env_vars(
352355
return (
353356
organization,
354357
repositories_list,
358+
search_query,
355359
gh_app_id,
356360
gh_app_installation_id,
357361
gh_app_private_key_bytes,

evergreen.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def main(): # pragma: no cover
2020
(
2121
organization,
2222
repository_list,
23+
search_query,
2324
gh_app_id,
2425
gh_app_installation_id,
2526
gh_app_private_key,
@@ -77,7 +78,7 @@ def main(): # pragma: no cover
7778

7879
# Get the repositories from the organization, team name, or list of repositories
7980
repos = get_repos_iterator(
80-
organization, team_name, repository_list, github_connection
81+
organization, team_name, repository_list, search_query, github_connection
8182
)
8283

8384
# Setting up the action summary content
@@ -341,9 +342,21 @@ def enable_dependabot_security_updates(ghe, owner, repo, access_token):
341342
print("\tFailed to enable Dependabot security updates.")
342343

343344

344-
def get_repos_iterator(organization, team_name, repository_list, github_connection):
345-
"""Get the repositories from the organization, team_name, or list of repositories"""
345+
def get_repos_iterator(
346+
organization, team_name, repository_list, search_query, github_connection
347+
):
348+
"""Get the repositories from the organization, team_name, repository_list, or via search query"""
349+
# Use GitHub search API if REPOSITORY_SEARCH_QUERY is set
350+
if search_query:
351+
# Return repositories matching the search query
352+
repos = []
353+
# Search results need to be converted to a list of repositories since they are returned as a search iterator
354+
for repo in github_connection.search_repositories(search_query):
355+
repos.append(repo.repository)
356+
return repos
357+
346358
repos = []
359+
# Default behavior: list all organization/team repositories or specific repository list
347360
if organization and not repository_list and not team_name:
348361
repos = github_connection.organization(organization).repositories()
349362
elif team_name and organization:

test_env.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def setUp(self):
3939
"TYPE",
4040
"UPDATE_EXISTING",
4141
"REPO_SPECIFIC_EXEMPTIONS",
42+
"REPOSITORY_SEARCH_QUERY",
4243
"SCHEDULE",
4344
"SCHEDULE_DAY",
4445
"LABELS",
@@ -68,6 +69,7 @@ def test_get_env_vars_with_org(self):
6869
expected_result = (
6970
"my_organization",
7071
[],
72+
"", # search_query
7173
None,
7274
None,
7375
b"",
@@ -120,6 +122,7 @@ def test_get_env_vars_with_org_and_repo_specific_exemptions(self):
120122
expected_result = (
121123
"my_organization",
122124
[],
125+
"", # search_query
123126
None,
124127
None,
125128
b"",
@@ -232,6 +235,7 @@ def test_get_env_vars_with_repos(self):
232235
expected_result = (
233236
None,
234237
["org/repo1", "org2/repo2"],
238+
"", # search_query
235239
None,
236240
None,
237241
b"",
@@ -289,6 +293,7 @@ def test_get_env_vars_with_team(self):
289293
expected_result = (
290294
"my_organization",
291295
[],
296+
"", # search_query
292297
None,
293298
None,
294299
b"",
@@ -364,6 +369,7 @@ def test_get_env_vars_optional_values(self):
364369
expected_result = (
365370
"my_organization",
366371
[],
372+
"", # search_query
367373
None,
368374
None,
369375
b"",
@@ -410,6 +416,7 @@ def test_get_env_vars_with_update_existing(self):
410416
expected_result = (
411417
"my_organization",
412418
[],
419+
"", # search_query
413420
None,
414421
None,
415422
b"",
@@ -450,7 +457,7 @@ def test_get_env_vars_missing_org_or_repo(self):
450457
the_exception = cm.exception
451458
self.assertEqual(
452459
str(the_exception),
453-
"ORGANIZATION and REPOSITORY environment variables were not set. Please set one",
460+
"ORGANIZATION, REPOSITORY, and REPOSITORY_SEARCH_QUERY environment variables were not set. Please set one",
454461
)
455462

456463
@patch.dict(
@@ -470,6 +477,7 @@ def test_get_env_vars_auth_with_github_app_installation(self):
470477
expected_result = (
471478
"my_organization",
472479
[],
480+
"", # search_query
473481
12345,
474482
678910,
475483
b"hello",
@@ -559,6 +567,7 @@ def test_get_env_vars_with_repos_no_dry_run(self):
559567
expected_result = (
560568
"my_organization",
561569
[],
570+
"", # search_query
562571
None,
563572
None,
564573
b"",
@@ -605,6 +614,7 @@ def test_get_env_vars_with_repos_disabled_security_updates(self):
605614
expected_result = (
606615
"my_organization",
607616
[],
617+
"", # search_query
608618
None,
609619
None,
610620
b"",
@@ -652,6 +662,7 @@ def test_get_env_vars_with_repos_filter_visibility_multiple_values(self):
652662
expected_result = (
653663
"my_organization",
654664
[],
665+
"", # search_query
655666
None,
656667
None,
657668
b"",
@@ -699,6 +710,7 @@ def test_get_env_vars_with_repos_filter_visibility_single_value(self):
699710
expected_result = (
700711
"my_organization",
701712
[],
713+
"", # search_query
702714
None,
703715
None,
704716
b"",
@@ -776,6 +788,7 @@ def test_get_env_vars_with_repos_filter_visibility_no_duplicates(self):
776788
expected_result = (
777789
"my_organization",
778790
[],
791+
"", # search_query
779792
None,
780793
None,
781794
b"",
@@ -824,6 +837,7 @@ def test_get_env_vars_with_repos_exempt_ecosystems(self):
824837
expected_result = (
825838
"my_organization",
826839
[],
840+
"", # search_query
827841
None,
828842
None,
829843
b"",
@@ -871,6 +885,7 @@ def test_get_env_vars_with_no_batch_size(self):
871885
expected_result = (
872886
"my_organization",
873887
[],
888+
"", # search_query
874889
None,
875890
None,
876891
b"",
@@ -919,6 +934,7 @@ def test_get_env_vars_with_batch_size(self):
919934
expected_result = (
920935
"my_organization",
921936
[],
937+
"", # search_query
922938
None,
923939
None,
924940
b"",
@@ -1056,6 +1072,7 @@ def test_get_env_vars_with_valid_schedule_and_schedule_day(self):
10561072
expected_result = (
10571073
"my_organization",
10581074
[],
1075+
"", # search_query
10591076
None,
10601077
None,
10611078
b"",
@@ -1141,6 +1158,7 @@ def test_get_env_vars_with_a_valid_label(self):
11411158
expected_result = (
11421159
"my_organization",
11431160
[],
1161+
"", # search_query
11441162
None,
11451163
None,
11461164
b"",
@@ -1187,6 +1205,7 @@ def test_get_env_vars_with_valid_labels_containing_spaces(self):
11871205
expected_result = (
11881206
"my_organization",
11891207
[],
1208+
"", # search_query
11901209
None,
11911210
None,
11921211
b"",

0 commit comments

Comments
 (0)