1#

2# Copyright (C) 2019-2025 Mathieu Parent <math.parent@gmail.com>

3#

4# This program is free software: you can redistribute it and/or modify

5# it under the terms of the GNU Lesser General Public License as published by

6# the Free Software Foundation, either version 3 of the License, or

7# (at your option) any later version.

8#

9# This program is distributed in the hope that it will be useful,

10# but WITHOUT ANY WARRANTY; without even the implied warranty of

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

12# GNU Lesser General Public License for more details.

13#

14# You should have received a copy of the GNU Lesser General Public License

15# along with this program. If not, see <http://www.gnu.org/licenses/>.

16

17 import logging

18 from copy import deepcopy

19

20 from gitlabracadabra.objects.object import GitLabracadabraObject

21

22 logger = logging.getLogger(__name__)

23

24

25 class PipelineSchedulesMixin(GitLabracadabraObject):

26 """Object with pipeline schedules."""

27

28 """_process_pipeline_schedules()

29

30 Process the pipeline_schedules param.

31 """

32

33 def _process_pipeline_schedules(self, param_name, param_value, *, dry_run=False, skip_save=False):

34 assert param_name == "pipeline_schedules" # noqa: S101

35 assert not skip_save # noqa: S101

36 unknown_pipeline_schedules = self._content.get("unknown_pipeline_schedules", "warn")

37 current_pipeline_schedules = dict(

38 [

39 [current_pipeline_schedule.description, current_pipeline_schedule]

40 for current_pipeline_schedule in self._obj.pipelineschedules.list(all=True)

41 ]

42 )

43 target_pipeline_schedules = dict(

44 [

45 [target_pipeline_schedule["description"], deepcopy(target_pipeline_schedule)]

46 for target_pipeline_schedule in param_value

47 ]

48 )

49 unknown_pipeline_schedule_variables = self._content.get("unknown_pipeline_schedule_variables", "warn")

50 # We first check for already existing pipeline schedules

51 for current_pipeline_schedule_description, current_pipeline_schedule in sorted(

52 current_pipeline_schedules.items()

53 ):

54 if current_pipeline_schedule_description in target_pipeline_schedules:

55 target_pipeline_schedule = target_pipeline_schedules[current_pipeline_schedule_description]

56 for (

57 target_pipeline_schedule_param_name,

58 target_pipeline_schedule_param_value,

59 ) in target_pipeline_schedule.items():

60 if target_pipeline_schedule_param_name == "variables":

61 unknown_variables = target_pipeline_schedule.get(

62 "unknown_variables", unknown_pipeline_schedule_variables

63 )

64 self._handle_pipeline_schedule_variables(

65 current_pipeline_schedule,

66 target_pipeline_schedule_param_value,

67 unknown_variables,

68 dry_run=dry_run,

69 )

70 continue

71 if target_pipeline_schedule_param_name == "unknown_variables": 71 ↛ 72 line 71 didn't jump to line 72 because the condition on line 71 was never true

72 continue

73 try:

74 current_pipeline_schedule_param_value = getattr(

75 current_pipeline_schedule, target_pipeline_schedule_param_name

76 )

77 except AttributeError:

78 logger.info(

79 "[%s] NOT Changing pipeline schedules %s %s: %s -> %s " "(current value is not available)",

80 self._name,

81 current_pipeline_schedule_description,

82 target_pipeline_schedule_param_name,

83 None,

84 target_pipeline_schedule_param_value,

85 )

86 continue

87 if current_pipeline_schedule_param_value != target_pipeline_schedule_param_value:

88 if dry_run: 88 ↛ 89 line 88 didn't jump to line 89 because the condition on line 88 was never true

89 logger.info(

90 "[%s] NOT Changing pipeline schedule %s %s: %s -> %s (dry-run)",

91 self._name,

92 current_pipeline_schedule_description,

93 target_pipeline_schedule_param_name,

94 current_pipeline_schedule_param_value,

95 target_pipeline_schedule_param_value,

96 )

97 else:

98 logger.info(

99 "[%s] Changing pipeline schedule %s %s: %s -> %s",

100 self._name,

101 current_pipeline_schedule_description,

102 target_pipeline_schedule_param_name,

103 current_pipeline_schedule_param_value,

104 target_pipeline_schedule_param_value,

105 )

106 setattr(

107 current_pipeline_schedule,

108 target_pipeline_schedule_param_name,

109 target_pipeline_schedule_param_value,

110 )

111 current_pipeline_schedule.save()

112 target_pipeline_schedules.pop(current_pipeline_schedule_description)

113 elif unknown_pipeline_schedules in ["delete", "remove"]: 113 ↛ 123 line 113 didn't jump to line 123 because the condition on line 113 was always true

114 if dry_run: 114 ↛ 115 line 114 didn't jump to line 115 because the condition on line 114 was never true

115 logger.info(

116 "[%s] NOT Removing pipeline schedule %s (dry-run)",

117 self._name,

118 current_pipeline_schedule_description,

119 )

120 else:

121 logger.info("[%s] Removing pipeline schedule %s", self._name, current_pipeline_schedule_description)

122 current_pipeline_schedule.delete()

123 elif unknown_pipeline_schedules not in ["ignore", "skip"]:

124 logger.warning(

125 "[%s] NOT Removing pipeline schedule: %s", self._name, current_pipeline_schedule_description

126 )

127 # Remaining pipeline_schedules

128 for target_pipeline_schedule_name, target_pipeline_schedule in sorted(target_pipeline_schedules.items()):

129 target_pipeline_schedule_variables = target_pipeline_schedule.pop("variables", [])

130 unknown_variables = target_pipeline_schedule.pop("unknown_variables", unknown_pipeline_schedule_variables)

131 if dry_run: 131 ↛ 132 line 131 didn't jump to line 132 because the condition on line 131 was never true

132 logger.info(

133 "[%s] NOT Adding pipeline schedule %s: %s -> %s (dry-run)",

134 self._name,

135 target_pipeline_schedule_name,

136 None,

137 target_pipeline_schedule,

138 )

139 else:

140 logger.info(

141 "[%s] Adding pipeline schedule %s: %s -> %s",

142 self._name,

143 target_pipeline_schedule_name,

144 None,

145 target_pipeline_schedule,

146 )

147 pipeline_schedule = self._obj.pipelineschedules.create(target_pipeline_schedule)

148 self._handle_pipeline_schedule_variables(

149 pipeline_schedule, target_pipeline_schedule_variables, unknown_variables, dry_run=dry_run

150 )

151

152 """_handle_pipeline_schedule_variables()

153

154 Handle pipeline schedule variables.

155 """

156

157 def _handle_pipeline_schedule_variables(self, pipeline_schedule, variables, unknown_variables, *, dry_run=False):

158 if len(variables) == 0 and unknown_variables in ["ignore", "skip"]:

159 return

160 pipeline_schedule = self._obj.pipelineschedules.get(pipeline_schedule.id)

161 current_variables = dict(

162 [

163 [current_variable["key"], current_variable]

164 for current_variable in pipeline_schedule.attributes["variables"]

165 ]

166 )

167 target_variables = dict([[target_variable["key"], deepcopy(target_variable)] for target_variable in variables])

168 # We first check for already existing variables

169 for current_variable_key, current_variable in sorted(current_variables.items()):

170 if current_variable_key in target_variables:

171 for target_variable_param_name, target_variable_param_value in target_variables[

172 current_variable_key

173 ].items():

174 try:

175 current_variable_param_value = current_variable[target_variable_param_name]

176 except KeyError:

177 logger.info(

178 "[%s] NOT Changing pipeline schedule variable %s %s: %s -> %s "

179 "(current value is not available)",

180 self._name,

181 current_variable_key,

182 target_variable_param_name,

183 None,

184 target_variable_param_value,

185 )

186 continue

187 if current_variable_param_value != target_variable_param_value:

188 if dry_run: 188 ↛ 189 line 188 didn't jump to line 189 because the condition on line 188 was never true

189 logger.info(

190 "[%s] NOT Changing pipeline schedule variable %s %s: %s -> %s (dry-run)",

191 self._name,

192 current_variable_key,

193 target_variable_param_name,

194 current_variable_param_value,

195 target_variable_param_value,

196 )

197 else:

198 logger.info(

199 "[%s] Changing pipeline schedule variable %s %s: %s -> %s",

200 self._name,

201 current_variable_key,

202 target_variable_param_name,

203 current_variable_param_value,

204 target_variable_param_value,

205 )

206 new_data = {

207 "key": current_variable_key,

208 "value": target_variables[current_variable_key]["value"],

209 }

210 new_data[target_variable_param_name] = target_variable_param_value

211 pipeline_schedule.variables.update(current_variable_key, new_data)

212 target_variables.pop(current_variable_key)

213 elif unknown_variables in ["delete", "remove"]: 213 ↛ 221 line 213 didn't jump to line 221 because the condition on line 213 was always true

214 if dry_run: 214 ↛ 215 line 214 didn't jump to line 215 because the condition on line 214 was never true

215 logger.info(

216 "[%s] NOT Removing pipeline schedule variable %s (dry-run)", self._name, current_variable_key

217 )

218 else:

219 logger.info("[%s] Removing pipeline schedule variable %s", self._name, current_variable_key)

220 pipeline_schedule.variables.delete(current_variable_key)

221 elif unknown_variables not in ["ignore", "skip"]:

222 logger.warning("[%s] NOT Removing variable: %s", self._name, current_variable_key)

223 # Remaining variables

224 for target_variable_name, target_variable in sorted(target_variables.items()):

225 if dry_run: 225 ↛ 226 line 225 didn't jump to line 226 because the condition on line 225 was never true

226 logger.info(

227 "[%s] NOT Adding pipeline schedule variable %s: %s -> %s (dry-run)",

228 self._name,

229 target_variable_name,

230 None,

231 target_variable,

232 )

233 else:

234 logger.info(

235 "[%s] Adding pipeline schedule variable %s: %s -> %s",

236 self._name,

237 target_variable_name,

238 None,

239 target_variable,

240 )

241 pipeline_schedule.variables.create(target_variable)