1
1
package com .redhat .labs .lodestar .service ;
2
2
3
- import java .util . Collections ;
4
- import java .util . HashMap ;
5
- import java .util . List ;
6
- import java .util . Map ;
7
- import java .util .Optional ;
3
+ import java .time . Instant ;
4
+ import java .time . LocalDateTime ;
5
+ import java .time . ZoneOffset ;
6
+ import java .time . format . DateTimeFormatter ;
7
+ import java .util .* ;
8
8
9
9
import javax .enterprise .context .ApplicationScoped ;
10
10
import javax .inject .Inject ;
11
11
12
+ import com .redhat .labs .lodestar .models .*;
13
+ import com .redhat .labs .lodestar .models .gitlab .*;
12
14
import org .eclipse .microprofile .config .inject .ConfigProperty ;
13
15
import org .slf4j .Logger ;
14
16
import org .slf4j .LoggerFactory ;
15
17
16
18
import com .redhat .labs .lodestar .config .JsonMarshaller ;
17
- import com .redhat .labs .lodestar .models .Artifact ;
18
- import com .redhat .labs .lodestar .models .Engagement ;
19
- import com .redhat .labs .lodestar .models .EngagementUser ;
20
- import com .redhat .labs .lodestar .models .HostingEnvironment ;
21
- import com .redhat .labs .lodestar .models .gitlab .File ;
22
- import com .redhat .labs .lodestar .models .gitlab .Project ;
23
19
24
20
@ ApplicationScoped
25
21
public class MigrationService {
26
22
private static final Logger LOGGER = LoggerFactory .getLogger (MigrationService .class );
27
-
23
+
28
24
private static final String ENGAGEMENT_DIR = "engagement/" ;
29
25
private static final String PARTICIPANT_JSON = ENGAGEMENT_DIR + "participants.json" ;
30
26
private static final String ARTIFACT_JSON = ENGAGEMENT_DIR + "artifacts.json" ;
31
27
private static final String HOSTING_JSON = ENGAGEMENT_DIR + "hosting.json" ;
28
+ private static final String ENGAGEMENT_JSON = ENGAGEMENT_DIR + "engagement.json" ;
32
29
33
30
@ Inject
34
31
EngagementService engagementService ;
@@ -54,51 +51,145 @@ public class MigrationService {
54
51
@ ConfigProperty (name = "commit.default.branch" )
55
52
String commitBranch ;
56
53
57
- private Map <Integer , Engagement > allEngagements = new HashMap <>();
54
+ private final Map <Integer , Engagement > allEngagements = new HashMap <>();
58
55
59
56
/**
60
57
* The migration is idempotent so no harm in rerunning. It will only update
61
58
* engagements that haven't been migrated.
62
59
*/
63
- public void migrate (boolean migrateUuids , boolean migrateParticipants , boolean migrateArtifacts , boolean migrateHosting ) {
60
+ public void migrate (boolean migrateUuids , boolean migrateParticipants , boolean migrateArtifacts , boolean migrateHosting ,
61
+ boolean migrateEngagements , boolean overwrite , String uuid ) {
62
+ LOGGER .debug ("uuids {} participants {} artifacts {} hosting {} engagements {} overwrite {} uuid {}" , migrateUuids ,
63
+ migrateParticipants , migrateArtifacts , migrateHosting , migrateEngagements , overwrite , uuid );
64
+
65
+ getAllEngagements (); //hydrate before stream
66
+
64
67
if (migrateUuids ) {
65
- LOGGER .info ("Start Migrate uuids: {}" , migrateUuids );
68
+ LOGGER .info ("Start Migrate uuids" );
66
69
migrateUuids ();
67
70
LOGGER .info ("End Migrate uuids" );
68
- }
69
-
70
- if (migrateParticipants ) {
71
- LOGGER .info ("Start Migrate participants: {}" , migrateParticipants );
72
- migrateParticipants ();
73
- LOGGER .info ("End Migrate participants" );
74
- }
75
-
76
- if (migrateArtifacts ) {
77
- LOGGER .info ("Start Migrate artifacts" );
78
- migrateArtifacts ();
79
- LOGGER .info ("End Migrate artifacts" );
80
71
}
81
-
82
- if (migrateHosting ) {
83
- LOGGER .info ("Start Migrate hosting" );
84
- migrateHosting ();
85
- LOGGER .info ("End Migrate hosting" );
72
+
73
+ LOGGER .info ("Start Migrate content" );
74
+ migrateAll (migrateParticipants , migrateArtifacts , migrateHosting , migrateEngagements , overwrite , uuid );
75
+ LOGGER .info ("End Migrate content" );
76
+
77
+ }
78
+
79
+ private void migrateAll (boolean migrateParticipants , boolean migrateArtifacts , boolean migrateHosting ,
80
+ boolean migrateEngagements , boolean overwrite , String uuid ) {
81
+ getAllEngagements ().values ().forEach (e -> {
82
+ LOGGER .debug ("Migrating {}" , e .getUuid ());
83
+ if (uuid == null || e .getUuid ().equals (uuid )) {
84
+ List <Action > actions = new ArrayList <>();
85
+ String content ;
86
+ if (migrateEngagements ) {
87
+ content = migrateEngagement (e );
88
+ actions .add (createAction (content , ENGAGEMENT_JSON , overwrite , e .getProjectId ()));
89
+ }
90
+
91
+ if (migrateParticipants ) {
92
+ content = migrateParticipantsToGitlab (e );
93
+ actions .add (createAction (content , PARTICIPANT_JSON , overwrite , e .getProjectId ()));
94
+ }
95
+
96
+ if (migrateHosting ) {
97
+ content = migrateHostingToGitlab (e );
98
+ actions .add (createAction (content , HOSTING_JSON , overwrite , e .getProjectId ()));
99
+ }
100
+
101
+ if (migrateArtifacts ) {
102
+ content = migrateArtifactsToGitlab (e );
103
+ actions .add (createAction (content , ARTIFACT_JSON , overwrite , e .getProjectId ()));
104
+ }
105
+
106
+ if (!actions .isEmpty ()) {
107
+ String commitMessage = "Migrating to v2" ;
108
+
109
+ CommitMultiple commit = CommitMultiple .builder ().id (e .getProjectId ()).branch (commitBranch ).commitMessage (commitMessage ).actions (actions )
110
+ .authorName (commitAuthor ).authorEmail (commitEmail ).build ();
111
+
112
+ fileService .createFiles (e .getProjectId (), commit );
113
+ }
114
+ }
115
+ });
116
+ }
117
+
118
+ /**
119
+ *
120
+ * @param content the new content to write
121
+ * @param filePath the file path to write to
122
+ * @param overwrite if true - will check for existence of file and overwrite if it exists
123
+ * @return the file to write to on commit
124
+ */
125
+ private Action createAction (String content , String filePath , boolean overwrite , int projectId ) {
126
+ FileAction action = FileAction .create ;
127
+ if (overwrite && fileService .getFile (projectId , filePath ).isPresent ()) {
128
+ action = FileAction .update ;
129
+
86
130
}
131
+ return Action .builder ().action (action ).filePath (filePath ).content (content ).encoding ("base64" ).build ();
87
132
}
88
133
89
134
/**
90
135
* Get all projects and split for individual update. This will add a description to any
91
- * project that doesn't have one. The description will included the uuid of the engagement
136
+ * project that doesn't have one. The description will include the uuid of the engagement
92
137
*/
93
138
private void migrateUuids () {
94
139
List <Project > allProjects = projectService .getProjectsByGroup (engagementRepositoryId , true );
95
- getAllEngagements (); //hydrate before stream
140
+
96
141
allProjects .parallelStream ().forEach (this ::updateProjectWithUuid );
97
142
}
143
+
144
+ private String migrateEngagement (Engagement engagement ) {
145
+ Engagement copy = clone (engagement , Engagement .class );
146
+
147
+ if (copy .getCategories () != null ) {
148
+ copy .getCategories ().forEach (cat -> {
149
+ try {
150
+ cat .setCreated (convertDateTime (cat .getCreated ()));
151
+ cat .setUpdated (convertDateTime (cat .getUpdated ()));
152
+ } catch (Exception ex ) {
153
+ LOGGER .error ("dtf exception {}" , cat .getCreated (), ex );
154
+ }
155
+ });
156
+ }
157
+
158
+ if (copy .getUseCases () != null ) {
159
+ copy .getUseCases ().forEach ((use -> {
160
+ try {
161
+ use .setCreated (convertDateTime (use .getCreated ()));
162
+ use .setUpdated (convertDateTime (use .getUpdated ()));
163
+ } catch (Exception ex ) {
164
+ LOGGER .error ("dtf exception {}" , use .getCreated (), ex );
165
+ }
166
+ }));
167
+ }
168
+
169
+ copy .setHostingEnvironments (null );
170
+ copy .setEngagementUsers (null );
171
+ copy .setCommits (null );
172
+ copy .setArtifacts (null );
173
+
174
+ return json .toJson (copy );
175
+ }
176
+
177
+ private <T > T clone (T toClone , Class <T > clazz ) {
178
+ return json .fromJson (json .toJson (toClone ), clazz );
179
+ }
180
+
181
+ private String convertDateTime (String oldDateTime ) {
182
+ LOGGER .trace ("Date In {}" , oldDateTime );
183
+ DateTimeFormatter formatter = DateTimeFormatter .ofPattern ("yyyy-MM-dd'T'HH:mm:ss.SSSSSS" );
184
+ LocalDateTime expected = LocalDateTime .parse (oldDateTime , formatter );
185
+ Instant instant = expected .toInstant (ZoneOffset .UTC );
186
+ LOGGER .trace ("Date Out {}" , instant );
187
+ return instant .toString ();
188
+ }
98
189
99
190
/**
100
191
* Update a single project if the description is not already set and an engagement has been found
101
- * @param project
192
+ * @param project the project to update
102
193
*/
103
194
private void updateProjectWithUuid (Project project ) {
104
195
@@ -112,34 +203,28 @@ private void updateProjectWithUuid(Project project) {
112
203
LOGGER .info ("Skipped uuid update because description is already set or the project {} is not in the engagement map" , project .getId ());
113
204
}
114
205
}
115
-
116
- /**
117
- * Get all engagements (engagement.json) and split for individual update
118
- */
119
- private void migrateParticipants () {
120
- getAllEngagements ().values ().parallelStream ().forEach (this ::migrateParticipantsToGitlab );
121
- }
122
-
123
- private void migrateArtifacts () {
124
- getAllEngagements ().values ().parallelStream ().forEach (this ::migrateArtifactsToGitlab );
125
- }
126
206
127
- private void migrateArtifactsToGitlab (Engagement engagement ) {
207
+ private String migrateArtifactsToGitlab (Engagement engagement ) {
128
208
List <Artifact > artifacts = engagement .getArtifacts () == null ? Collections .emptyList () : engagement .getArtifacts ();
129
- artifacts .forEach (a -> a .setRegion (engagement .getRegion ()));
130
- String content = json .toJson (artifacts );
131
- LOGGER .debug (content );
132
- migrateToGitlab (engagement , content , ARTIFACT_JSON , artifacts .size ());
133
-
134
- }
135
-
136
- private void migrateHosting () {
137
- getAllEngagements ().values ().parallelStream ().forEach (this ::migrateHostingToGitlab );
209
+ List <Artifact > copies = new ArrayList <>(artifacts .size ());
210
+ artifacts .forEach (a -> {
211
+ Artifact copy = clone (a , Artifact .class );
212
+ copy .setRegion (copy .getRegion ());
213
+ if (copy .getCreated () == null ) {
214
+ copy .setCreated (engagement .getEndDate ());
215
+ }
216
+
217
+ if (copy .getUpdated () == null ) {
218
+ copy .setUpdated (engagement .getEndDate ());
219
+ }
220
+ copies .add (copy );
221
+ });
222
+ return json .toJson (copies );
138
223
}
139
224
140
225
/**
141
226
* Get All engagements. This is run by migrate users and uuids so only run once if both are active
142
- * @return
227
+ * @return a map of engagements keyed by project id
143
228
*/
144
229
private Map <Integer , Engagement > getAllEngagements () {
145
230
LOGGER .debug ("Engagement count (pre-fetch) {}" , allEngagements .size ());
@@ -154,7 +239,7 @@ private Map<Integer, Engagement> getAllEngagements() {
154
239
155
240
/**
156
241
* Do a quick project id to engagement mapping to easily find the engagement by project id
157
- * @param engagement
242
+ * @param engagement map this
158
243
*/
159
244
private void addToMap (Engagement engagement ) {
160
245
allEngagements .put (engagement .getProjectId (), engagement );
@@ -163,34 +248,19 @@ private void addToMap(Engagement engagement) {
163
248
/**
164
249
* This will write the user json to gitlab. Should you wish to rollback or redo you could add this code
165
250
* fileService.deleteFile(engagement.getProjectId(), userJson);
166
- * @param engagement
251
+ * @param engagement participants of this engagement
167
252
*/
168
- private void migrateParticipantsToGitlab (Engagement engagement ) {
253
+ private String migrateParticipantsToGitlab (Engagement engagement ) {
169
254
170
255
List <EngagementUser > participants = engagement .getEngagementUsers () == null ? Collections .emptyList () : engagement .getEngagementUsers ();
171
256
participants .forEach (p -> p .setRegion (engagement .getRegion ()));
172
- String content = json .toJson (participants );
173
- migrateToGitlab (engagement , content , PARTICIPANT_JSON , participants .size ());
257
+ return json .toJson (participants );
174
258
}
175
259
176
- private void migrateHostingToGitlab (Engagement engagement ) {
260
+ private String migrateHostingToGitlab (Engagement engagement ) {
177
261
List <HostingEnvironment > hosting = engagement .getHostingEnvironments () == null ? Collections .emptyList () : engagement .getHostingEnvironments ();
178
262
hosting .forEach (h -> h .setRegion (engagement .getRegion ()));
179
- String content = json .toJson (hosting );
180
- migrateToGitlab (engagement , content , HOSTING_JSON , hosting .size ());
181
- }
182
-
183
- /**
184
- * This will write the user json to gitlab. Should you wish to rollback or redo you could add this code
185
- * fileService.deleteFile(engagement.getProjectId(), userJson);
186
- * @param engagement
187
- */
188
- private void migrateToGitlab (Engagement engagement , String content , String fileName , int size ) {
189
-
190
- if (fileService .getFile (engagement .getProjectId (), fileName ).isEmpty ()) {
191
- File file = File .builder ().content (content ).authorEmail (commitEmail ).authorName (commitAuthor ).branch (commitBranch ).commitMessage (String .format ("migrating %s" , fileName )).build ();
192
- fileService .createFile (engagement .getProjectId (), fileName , file );
193
- LOGGER .info ("Migrated {} {} for engagement {}" , size , fileName , engagement .getUuid ());
194
- }
263
+ return json .toJson (hosting );
195
264
}
265
+
196
266
}
0 commit comments