1- from collections import namedtuple
21import copy
32import json
4- import os
53from pathlib import Path
64import subprocess as sp
75import tempfile
86import re
97from glob import glob
108from itertools import chain
11- import github
12- from urllib3 .util .retry import Retry
139import random
10+ from typing import Optional
1411
1512from packaging import version as packaging_version
1613import yaml
17- from github import Github , GithubException
18- from reretry import retry
1914
2015from snakedeploy .exceptions import UserError
2116from snakedeploy .logger import logger
17+ from snakedeploy .prs import PR , get_repo
2218from snakedeploy .utils import YamlDumper
2319from snakedeploy .conda_version import VersionOrder
2420
@@ -66,9 +62,6 @@ def update_conda_envs(
6662 )
6763
6864
69- File = namedtuple ("File" , "path, content, is_updated, msg" )
70-
71-
7265class CondaEnvProcessor :
7366 def __init__ (self , conda_frontend = "mamba" ):
7467 self .conda_frontend = conda_frontend
@@ -84,22 +77,16 @@ def __init__(self, conda_frontend="mamba"):
8477 def process (
8578 self ,
8679 conda_env_paths ,
87- create_prs = False ,
88- update_envs = True ,
89- pin_envs = True ,
90- pr_add_label = False ,
91- entity_regex = None ,
92- warn_on_error = False ,
80+ create_prs : bool = False ,
81+ update_envs : bool = True ,
82+ pin_envs : bool = True ,
83+ pr_add_label : bool = False ,
84+ entity_regex : Optional [ str ] = None ,
85+ warn_on_error : bool = False ,
9386 ):
9487 repo = None
9588 if create_prs :
96- g = Github (
97- os .environ ["GITHUB_TOKEN" ],
98- retry = Retry (
99- total = 10 , status_forcelist = (500 , 502 , 504 ), backoff_factor = 0.3
100- ),
101- )
102- repo = g .get_repo (os .environ ["GITHUB_REPOSITORY" ]) if create_prs else None
89+ repo = get_repo ()
10390 conda_envs = list (chain .from_iterable (map (glob , conda_env_paths )))
10491 random .shuffle (conda_envs )
10592
@@ -109,19 +96,6 @@ def process(
10996 )
11097 for conda_env_path in conda_envs :
11198 if create_prs :
112- entity = conda_env_path
113- if entity_regex is not None :
114- m = re .match (entity_regex , conda_env_path )
115- if m is None :
116- raise UserError (
117- f"Given --entity-regex did not match any { conda_env_path } ."
118- )
119- try :
120- entity = m .group ("entity" )
121- except IndexError :
122- raise UserError (
123- "No group 'entity' found in given --entity-regex."
124- )
12599 if pr_add_label and not entity_regex :
126100 raise UserError (
127101 "Cannot add label to PR without --entity-regex specified."
@@ -132,11 +106,12 @@ def process(
132106 )
133107 mode = "bump" if update_envs else "pin"
134108 pr = PR (
135- f"perf: auto{ mode } { entity } " ,
136- f"Automatic { mode } of { entity } ." ,
137- f"auto{ mode } /{ entity .replace ('/' , '-' )} " ,
109+ f"perf: auto{ mode } { conda_env_path } " ,
110+ f"Automatic { mode } of { conda_env_path } ." ,
111+ f"auto{ mode } /{ conda_env_path .replace ('/' , '-' )} " ,
138112 repo ,
139- label = entity if pr_add_label else None ,
113+ entity = conda_env_path ,
114+ label_entity_regex = entity_regex if pr_add_label else None ,
140115 )
141116 else :
142117 pr = None
@@ -161,6 +136,7 @@ def process(
161136 else :
162137 raise UserError (msg )
163138 if create_prs :
139+ assert pr is not None
164140 pr .create ()
165141
166142 def update_env (
@@ -303,83 +279,3 @@ def exec_conda(self, subcmd):
303279 universal_newlines = True ,
304280 check = True ,
305281 )
306-
307-
308- class PR :
309- def __init__ (self , title , body , branch , repo , label = None ):
310- self .title = title
311- self .body = body
312- self .files = []
313- self .branch = branch
314- self .repo = repo
315- self .base_ref = (
316- os .environ .get ("GITHUB_BASE_REF" ) or os .environ ["GITHUB_REF_NAME" ]
317- )
318- self .label = label
319-
320- def add_file (self , filepath , content , is_updated , msg ):
321- self .files .append (File (str (filepath ), content , is_updated , msg ))
322-
323- @retry (tries = 2 , delay = 60 )
324- def create (self ):
325- if not self .files :
326- logger .info ("No files to commit." )
327- return
328-
329- branch_exists = False
330- try :
331- b = self .repo .get_branch (self .branch )
332- logger .info (f"Branch { b } already exists." )
333- branch_exists = True
334- except GithubException as e :
335- if e .status != 404 :
336- raise e
337- logger .info (f"Creating branch { self .branch } ..." )
338- self .repo .create_git_ref (
339- ref = f"refs/heads/{ self .branch } " ,
340- sha = self .repo .get_branch (self .base_ref ).commit .sha ,
341- )
342- for file in self .files :
343- sha = None
344- if branch_exists :
345- logger .info (f"Obtaining sha of { file .path } on branch { self .branch } ..." )
346- try :
347- # try to get sha if file exists
348- sha = self .repo .get_contents (file .path , self .branch ).sha
349- except github .GithubException .UnknownObjectException as e :
350- if e .status != 404 :
351- raise e
352- elif file .is_updated :
353- logger .info (
354- f"Obtaining sha of { file .path } on branch { self .base_ref } ..."
355- )
356- sha = self .repo .get_contents (file .path , self .base_ref ).sha
357-
358- if sha is not None :
359- self .repo .update_file (
360- file .path ,
361- file .msg ,
362- file .content ,
363- sha ,
364- branch = self .branch ,
365- )
366- else :
367- self .repo .create_file (
368- file .path , file .msg , file .content , branch = self .branch
369- )
370-
371- pr_exists = any (
372- pr .head .label .split (":" , 1 )[1 ] == self .branch
373- for pr in self .repo .get_pulls (state = "open" , base = self .base_ref )
374- )
375- if pr_exists :
376- logger .info ("PR already exists." )
377- else :
378- pr = self .repo .create_pull (
379- title = self .title ,
380- body = self .body ,
381- head = self .branch ,
382- base = self .base_ref ,
383- )
384- pr .add_to_labels (self .label )
385- logger .info (f"Created PR: { pr .html_url } " )
0 commit comments