LEFT | RIGHT |
1 /* | 1 /* |
2 Copyright 2013 Google Inc | 2 Copyright 2013 Google Inc |
3 | 3 |
4 Licensed under the Apache License, Version 2.0 (the "License"); | 4 Licensed under the Apache License, Version 2.0 (the "License"); |
5 you may not use this file except in compliance with the License. | 5 you may not use this file except in compliance with the License. |
6 You may obtain a copy of the License at | 6 You may obtain a copy of the License at |
7 | 7 |
8 http://www.apache.org/licenses/LICENSE-2.0 | 8 http://www.apache.org/licenses/LICENSE-2.0 |
9 | 9 |
10 Unless required by applicable law or agreed to in writing, software | 10 Unless required by applicable law or agreed to in writing, software |
(...skipping 13 matching lines...) Expand all Loading... |
24 using System.Text.RegularExpressions; | 24 using System.Text.RegularExpressions; |
25 using Microsoft.Build.Evaluation; | 25 using Microsoft.Build.Evaluation; |
26 using Microsoft.Build.Framework; | 26 using Microsoft.Build.Framework; |
27 using Microsoft.Build.Logging; | 27 using Microsoft.Build.Logging; |
28 | 28 |
29 using CommandLine; | 29 using CommandLine; |
30 using CommandLine.Text; | 30 using CommandLine.Text; |
31 using Ionic.Zip; | 31 using Ionic.Zip; |
32 | 32 |
33 using Google.Apis.Release.Repositories; | 33 using Google.Apis.Release.Repositories; |
| 34 using Google.Apis.Release.Wiki; |
34 using Google.Apis.Utils; | 35 using Google.Apis.Utils; |
35 using Google.Apis.Release.Wiki; | 36 using Google.Apis.Utils.Trace; |
36 | 37 |
37 namespace Google.Apis.Release | 38 namespace Google.Apis.Release |
38 { | 39 { |
39 /// <summary>The main program for creating a new Google.Apis release.</summa
ry> | 40 /// <summary>The main program for creating a new Google.Apis release.</summa
ry> |
40 class Program | 41 class Program |
41 { | 42 { |
42 /// <summary>The options class which contains the different options to t
his publish release utility.</summary> | 43 /// <summary>The options class which contains the different options to t
his publish release utility.</summary> |
43 public class Options | 44 public class Options |
44 { | 45 { |
45 #region HelpText | 46 #region HelpText |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 | 103 |
103 /// <summary>Gets or sets the "contrib" repository.</summary> | 104 /// <summary>Gets or sets the "contrib" repository.</summary> |
104 private Hg ContribRepository { get; set; } | 105 private Hg ContribRepository { get; set; } |
105 | 106 |
106 /// <summary>Gets all four repositories.</summary> | 107 /// <summary>Gets all four repositories.</summary> |
107 private IEnumerable<Hg> AllRepositories | 108 private IEnumerable<Hg> AllRepositories |
108 { | 109 { |
109 get { return new List<Hg> { DefaultRepository, SamplesRepository, Wi
kiRepository, ContribRepository }; } | 110 get { return new List<Hg> { DefaultRepository, SamplesRepository, Wi
kiRepository, ContribRepository }; } |
110 } | 111 } |
111 | 112 |
| 113 /// <summary> |
| 114 /// Clones URL format which expects one parameter of the repository name
(the default repository should be· |
| 115 /// empty). |
| 116 /// </summary> |
| 117 private const string CloneUrlFormat = "https://code.google.com/p/google-
api-dotnet-client{0}/"; |
| 118 |
112 static void Main(string[] args) | 119 static void Main(string[] args) |
113 { | 120 { |
| 121 bool valid = true; |
| 122 |
114 var options = new Options(); | 123 var options = new Options(); |
115 if (!CommandLine.Parser.Default.ParseArguments(args, options)) | 124 if (!CommandLine.Parser.Default.ParseArguments(args, options)) |
116 { | 125 { |
117 Console.ReadKey(); | 126 Console.ReadKey(); |
118 return; | 127 return; |
119 } | 128 } |
120 | 129 |
| 130 if (options.Step > 2 || options.Step < 1) |
| 131 { |
| 132 TraceSource.TraceEvent(TraceEventType.Error, "Invalid Step. Vali
d step is '1' or '2'."); |
| 133 valid = false; |
| 134 } |
| 135 |
121 var match = Regex.Match(options.Version, @"^(\d+)\.(\d+)\.(\d)+$"); | 136 var match = Regex.Match(options.Version, @"^(\d+)\.(\d+)\.(\d)+$"); |
122 if (!match.Success) | 137 if (!match.Success) |
123 { | 138 { |
124 TraceSource.TraceEvent(TraceEventType.Error, | 139 TraceSource.TraceEvent(TraceEventType.Error, |
125 "Invalid version Number. Version should be in <Major>.<Minor
>.<Build> form."); | 140 "Invalid version Number. Version should be in <Major>.<Minor
>.<Build> form."); |
| 141 valid = false; |
126 } | 142 } |
127 | 143 |
128 var program = new Program(options) | 144 var program = new Program(options) |
129 { | 145 { |
130 MajorVersion = int.Parse(match.Groups[1].Value), | 146 MajorVersion = int.Parse(match.Groups[1].Value), |
131 MinorVersion = int.Parse(match.Groups[2].Value), | 147 MinorVersion = int.Parse(match.Groups[2].Value), |
132 BuildVersion = int.Parse(match.Groups[3].Value), | 148 BuildVersion = int.Parse(match.Groups[3].Value), |
133 }; | 149 }; |
134 | 150 |
135 try | 151 if (valid) |
136 { | 152 { |
137 program.Run(); | 153 try |
138 } | 154 { |
139 catch (Exception ex) | 155 program.Run(); |
140 { | 156 } |
141 TraceSource.TraceEvent(TraceEventType.Error, "Exception occurred
while running. Exception is: {0}", | 157 catch (Exception ex) |
142 ex.Message); | 158 { |
| 159 TraceSource.TraceEvent(TraceEventType.Error, "Exception occu
rred while running. Exception is: {0}", |
| 160 ex.Message); |
| 161 } |
143 } | 162 } |
144 | 163 |
145 Console.WriteLine("Press any key to continue..."); | 164 Console.WriteLine("Press any key to continue..."); |
146 Console.ReadKey(); | 165 Console.ReadKey(); |
147 } | 166 } |
148 | 167 |
149 /// <summary>The main release logic for creating a new release of Google
.Apis.</summary> | 168 /// <summary>The main release logic for creating a new release of Google
.Apis.</summary> |
150 private void Run() | 169 private void Run() |
151 { | 170 { |
152 const string CloneUrl = "https://code.google.com/p/google-api-dotnet
-client{0}/"; | 171 DefaultRepository = new Hg(new Uri(string.Format(CloneUrlFormat, "")
), "default"); |
153 | |
154 DefaultRepository = new Hg(new Uri(string.Format(CloneUrl, "")), "de
fault"); | |
155 | 172 |
156 // Step 1 is only for creating Google.Apis and Google.Apis.Authentic
ation packages | 173 // Step 1 is only for creating Google.Apis and Google.Apis.Authentic
ation packages |
157 if (options.Step == 1) | 174 if (options.Step == 1) |
158 { | 175 { |
159 if (BuildVersion != 0) | 176 DoStep1(); |
160 { | 177 } |
161 DefaultRepository.Update(string.Format("{0}.{1}", MajorVersi
on, MinorVersion)); | |
162 } | |
163 | |
164 if (!HasIncomingChanges(new List<Hg> { DefaultRepository })) | |
165 { | |
166 if (BuildDefaultRepository()) | |
167 { | |
168 CreateNuGetPackages(); | |
169 // TODO(peleyal): release notes should be part of the pa
ckage | |
170 } | |
171 } | |
172 } | |
173 | |
174 // Step 2 should be done after the NuGet publisher generated all the
APIs and the samples repository was· | 178 // Step 2 should be done after the NuGet publisher generated all the
APIs and the samples repository was· |
175 // updated with the new packages | 179 // updated with the new packages |
176 else if (options.Step == 2) | 180 else if (options.Step == 2) |
177 { | 181 { |
178 Console.WriteLine(); | 182 DoStep2(); |
179 Console.WriteLine(); | 183 } |
| 184 } |
| 185 |
| 186 /// <summary>Creates Google.Apis and Google.Apis.Authentication packages
.</summary> |
| 187 private void DoStep1() |
| 188 { |
| 189 if (BuildVersion != 0) |
| 190 { |
| 191 DefaultRepository.Update(string.Format("{0}.{1}", MajorVersion,
MinorVersion)); |
| 192 } |
| 193 |
| 194 // if there are incoming changes those changes will be printed, othe
rwise we can continue in the process |
| 195 if (!HasIncomingChanges(new List<Hg> { DefaultRepository })) |
| 196 { |
| 197 // in case build fails the method will print its failures |
| 198 if (BuildDefaultRepository()) |
| 199 { |
| 200 CreateCoreNuGetPackages(); |
| 201 // TODO(peleyal): release notes should be part of the packag
e |
| 202 } |
| 203 } |
| 204 } |
| 205 |
| 206 /// <summary> |
| 207 /// Doing the following: |
| 208 /// <list type="number"> |
| 209 /// <item><description>Builds samples</description></item> |
| 210 /// <item><description>Creates a release notes</description></item> |
| 211 /// <item><description>Update wiki download page</description></item> |
| 212 /// <item><description>Create a new release in the contrib repository</d
escription></item> |
| 213 /// <item><description>Commits, Tags and Pushes</description></item> |
| 214 /// </list> |
| 215 /// </summary> |
| 216 private void DoStep2() |
| 217 { |
| 218 Console.WriteLine(); |
| 219 Console.WriteLine(); |
| 220 Console.WriteLine("========================="); |
| 221 Console.WriteLine("Prerequisites for Step 2:"); |
| 222 Console.WriteLine("You ran Step 1."); |
| 223 Console.WriteLine("You upgraded the Google.Apis NuGet packages for e
ach sample in the samples " + |
| 224 "repository and pushed that change."); |
| 225 Console.WriteLine("========================="); |
| 226 if (!CanContinue()) |
| 227 { |
| 228 return; |
| 229 } |
| 230 |
| 231 SamplesRepository = new Hg(new Uri(string.Format(CloneUrlFormat, ".s
amples")), "samples"); |
| 232 WikiRepository = new Hg(new Uri(string.Format(CloneUrlFormat, ".wiki
")), "wiki"); |
| 233 ContribRepository = new Hg(new Uri(string.Format(CloneUrlFormat, ".c
ontrib")), "contrib"); |
| 234 |
| 235 // if there are incoming changes those changes will be printed, othe
rwise we can continue in the· |
| 236 // process |
| 237 if (!HasIncomingChanges(AllRepositories)) |
| 238 { |
| 239 BuildSamples(); |
| 240 var notes = CreateContribNewRelease(); |
| 241 UpdateWiki(notes); |
| 242 |
| 243 foreach (var repository in AllRepositories) |
| 244 { |
| 245 repository.AddRemoveFiles(); |
| 246 } |
| 247 |
180 Console.WriteLine("========================="); | 248 Console.WriteLine("========================="); |
181 Console.WriteLine("Prerequisites for Step 2:"); | 249 Console.WriteLine("Commit, Tag and Push"); |
182 Console.WriteLine("You ran Step 1."); | |
183 Console.WriteLine("You upgraded the Google.Apis NuGet packages f
or each sample in the samples " + | |
184 "repository and pushed that change."); | |
185 Console.WriteLine("========================="); | 250 Console.WriteLine("========================="); |
186 if (CanContinue()) | 251 if (!CanContinue()) |
187 { | 252 { |
188 SamplesRepository = new Hg(new Uri(string.Format(CloneUrl, "
.samples")), "samples"); | 253 return; |
189 WikiRepository = new Hg(new Uri(string.Format(CloneUrl, ".wi
ki")), "wiki"); | 254 } |
190 ContribRepository = new Hg(new Uri(string.Format(CloneUrl, "
.contrib")), "contrib"); | 255 |
191 | 256 // commit |
192 // if there are incoming changes those changes will be print
ed, otherwise we can continue in the· | 257 CommitAndTag(); |
193 // process | 258 |
194 if (!HasIncomingChanges(AllRepositories)) | 259 // push |
195 { | 260 foreach (Hg repository in AllRepositories) |
196 BuildSamples(); | 261 { |
197 var notes = CreateContribNewRelease(); | 262 repository.Push(); |
198 UpdateWiki(notes); | 263 } |
199 | 264 |
200 foreach (var repository in AllRepositories) | 265 // create branch |
201 { | 266 PrintCreateBranch(); |
202 repository.AddRemoveFiles(); | 267 |
203 } | 268 // publish core components to NuGet |
204 | 269 if (!string.IsNullOrEmpty(options.NuGetApiKey)) |
205 Console.WriteLine("========================="); | 270 { |
206 Console.WriteLine("Commit, Tag and Push"); | 271 PublishPackagesToNuGet(); |
207 Console.WriteLine("========================="); | 272 Console.WriteLine("Now... you should run the NuGet publisher
to publish a new PCL " |
208 if (CanContinue()) | 273 + "for each generated Google API. Run: " + |
209 { | 274 "Google.Apis.NuGet.Publisher --all_apis true -m publishe
r -k [NUGET_KEY]"); |
210 // commit | 275 } |
211 CommitAndTag(); | 276 else |
212 | 277 { |
213 // push | 278 TraceSource.TraceEvent(TraceEventType.Error, "NuGet API key
is empty!"); |
214 foreach (Hg repository in AllRepositories) | 279 } |
215 { | |
216 repository.Push(); | |
217 } | |
218 | |
219 // create branch | |
220 PrintCreateBranch(); | |
221 | |
222 // publish core components to NuGet | |
223 if (!string.IsNullOrEmpty(options.NuGetApiKey)) | |
224 { | |
225 PublishPackagesToNuGet(); | |
226 Console.WriteLine("Now... you should run the NuG
et publisher to publish a new PCL " | |
227 + "for each generated Google API. Run: " + | |
228 "Google.Apis.NuGet.Publisher --all_apis true
-m publisher -k [NUGET_KEY]"); | |
229 } | |
230 else | |
231 { | |
232 TraceSource.TraceEvent(TraceEventType.Error, "Nu
Get API key is empty!"); | |
233 } | |
234 } | |
235 } | |
236 } | |
237 } | |
238 else | |
239 { | |
240 TraceSource.TraceEvent(TraceEventType.Error, "Invalid step optio
n!"); | |
241 } | 280 } |
242 } | 281 } |
243 | 282 |
244 /// <summary>Asks the user if he wants to continue in the process.</summ
ary> | 283 /// <summary>Asks the user if he wants to continue in the process.</summ
ary> |
245 /// <returns><c>true</c> if the user to press 'y' or 'yes' to continue</
returns> | 284 /// <returns><c>true</c> if the user to press 'y' or 'yes' to continue</
returns> |
246 private bool CanContinue() | 285 private bool CanContinue() |
247 { | 286 { |
248 var yesOptions = new[] { "y", "yes" }; | 287 var yesOptions = new[] { "y", "yes" }; |
249 var noOptions = new[] { "n", "no" }; | 288 var noOptions = new[] { "n", "no" }; |
250 | 289 |
251 string input; | 290 string input; |
252 do | 291 do |
253 { | 292 { |
254 Console.WriteLine("Press 'y' | 'yes' to continue, or 'n' | 'no'
to stop"); | 293 Console.WriteLine("Press 'y' | 'yes' to continue, or 'n' | 'no'
to stop"); |
255 input = Console.ReadLine(); | 294 input = Console.ReadLine().ToLower(); |
256 } while (!yesOptions.Contains(input) && !noOptions.Contains(input)); | 295 } while (!yesOptions.Contains(input) && !noOptions.Contains(input)); |
257 | 296 |
258 return yesOptions.Contains(input); | 297 return yesOptions.Contains(input); |
259 } | 298 } |
260 | 299 |
261 /// <summary>Publishes the core packages to NuGet main repository.</summ
ary> | 300 /// <summary>Publishes the core packages to NuGet main repository.</summ
ary> |
262 private void PublishPackagesToNuGet() | 301 private void PublishPackagesToNuGet() |
263 { | 302 { |
264 var apiNupkgPath = Path.Combine(NuGetUtilities.LocalNuGetPackageFold
er, | 303 var apiNupkgPath = Path.Combine(NuGetUtilities.LocalNuGetPackageFold
er, |
265 string.Format("Google.Apis.{0}.nupkg", Tag)); | 304 string.Format("Google.Apis.{0}.nupkg", Tag)); |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 { | 530 { |
492 TraceSource.TraceEvent(TraceEventType.Error, | 531 TraceSource.TraceEvent(TraceEventType.Error, |
493 "[{0}] has incoming changes. Run hg pull & update first!
", repository.Name); | 532 "[{0}] has incoming changes. Run hg pull & update first!
", repository.Name); |
494 return true; | 533 return true; |
495 } | 534 } |
496 } | 535 } |
497 return false; | 536 return false; |
498 } | 537 } |
499 | 538 |
500 /// <summary>Creates the Google.Apis and Google.Apis.Authentication NuGe
t packages.</summary> | 539 /// <summary>Creates the Google.Apis and Google.Apis.Authentication NuGe
t packages.</summary> |
501 private void CreateNuGetPackages() | 540 private void CreateCoreNuGetPackages() |
502 { | 541 { |
503 // create a resource dir in the working folder | 542 // create a resource dir in the working folder |
504 var destDirectory = Path.Combine(Environment.CurrentDirectory, "Reso
urces"); | 543 var destDirectory = Path.Combine(Environment.CurrentDirectory, "Reso
urces"); |
505 if (Directory.Exists(destDirectory)) | 544 if (Directory.Exists(destDirectory)) |
506 { | 545 { |
507 Directory.Delete(destDirectory, true); | 546 Directory.Delete(destDirectory, true); |
508 } | 547 } |
509 | 548 |
510 FileInfo info = new FileInfo(Assembly.GetEntryAssembly().Location); | 549 FileInfo info = new FileInfo(Assembly.GetEntryAssembly().Location); |
511 DirectoryUtilities.CopyDirectory(Path.Combine(info.Directory.FullNam
e, "Resources"), destDirectory); | 550 DirectoryUtilities.CopyDirectory(Path.Combine(info.Directory.FullNam
e, "Resources"), destDirectory); |
512 | 551 |
513 var newVersion = options.Version + "-beta"; | 552 var newVersion = options.Version + "-beta"; |
514 | 553 |
| 554 // get the Google.Apis and Google.Apis.Authentication nuspec files a
nd replace the version in it |
515 var apiNuspec = Path.Combine(destDirectory, "Google.Apis.VERSION.nus
pec"); | 555 var apiNuspec = Path.Combine(destDirectory, "Google.Apis.VERSION.nus
pec"); |
516 var newApiNuspec = apiNuspec.Replace("VERSION", newVersion); | 556 var newApiNuspec = apiNuspec.Replace("VERSION", newVersion); |
517 var authenticationNuspec = Path.Combine(destDirectory, "Google.Apis.
Authentication.VERSION.nuspec"); | 557 var authenticationNuspec = Path.Combine(destDirectory, "Google.Apis.
Authentication.VERSION.nuspec"); |
518 var newAuthenticationNuspec = authenticationNuspec.Replace("VERSION"
, newVersion); | 558 var newAuthenticationNuspec = authenticationNuspec.Replace("VERSION"
, newVersion); |
519 | 559 |
520 File.Move(apiNuspec, newApiNuspec); | 560 File.Move(apiNuspec, newApiNuspec); |
521 File.Move(authenticationNuspec, newAuthenticationNuspec); | 561 File.Move(authenticationNuspec, newAuthenticationNuspec); |
522 | 562 |
523 var allLines = File.ReadAllText(newApiNuspec).Replace("VERSION", new
Version); | 563 var allLines = File.ReadAllText(newApiNuspec).Replace("VERSION", new
Version); |
524 File.WriteAllText(newApiNuspec, allLines); | 564 File.WriteAllText(newApiNuspec, allLines); |
(...skipping 16 matching lines...) Expand all Loading... |
541 return releaseProjects; | 581 return releaseProjects; |
542 } | 582 } |
543 | 583 |
544 var releasePaths = new[]· | 584 var releasePaths = new[]· |
545 { | 585 { |
546 DefaultRepository.Combine("Src", "GoogleApis", "GoogleApis.c
sproj"), | 586 DefaultRepository.Combine("Src", "GoogleApis", "GoogleApis.c
sproj"), |
547 DefaultRepository.Combine("Src", "GoogleApis.DotNet4", "Goog
leApis.DotNet4.csproj"), | 587 DefaultRepository.Combine("Src", "GoogleApis.DotNet4", "Goog
leApis.DotNet4.csproj"), |
548 DefaultRepository.Combine("Src", "GoogleApis.Authentication.
OAuth2",· | 588 DefaultRepository.Combine("Src", "GoogleApis.Authentication.
OAuth2",· |
549 "GoogleApis.Authentication.OAuth2.csproj") | 589 "GoogleApis.Authentication.OAuth2.csproj") |
550 }; | 590 }; |
551 releaseProjects = (from path in releasePaths | 591 return releaseProjects = (from path in releasePaths |
552 select new Project(path)).ToList(); | 592 select new Project(path)).ToList(); |
553 return releaseProjects; | |
554 } | 593 } |
555 } | 594 } |
556 | 595 |
557 /// <summary>Builds the "default" repository projects.</summary> | 596 /// <summary>Builds the "default" repository projects.</summary> |
558 /// <returns><c>true</c> if the default repository was build successfull
y</returns> | 597 /// <returns><c>true</c> if the default repository was build successfull
y</returns> |
559 private bool BuildDefaultRepository() | 598 private bool BuildDefaultRepository() |
560 { | 599 { |
561 TraceSource.TraceEvent(TraceEventType.Information, "Building project
s...."); | 600 TraceSource.TraceEvent(TraceEventType.Information, "Building project
s...."); |
562 | 601 |
563 var allProjects = new List<Project>(); | 602 var allProjects = new List<Project>(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 string path = Path.GetFullPath(options.OutputDirectory); | 642 string path = Path.GetFullPath(options.OutputDirectory); |
604 if (!Directory.Exists(path)) | 643 if (!Directory.Exists(path)) |
605 { | 644 { |
606 Directory.CreateDirectory(path); | 645 Directory.CreateDirectory(path); |
607 } | 646 } |
608 | 647 |
609 Environment.CurrentDirectory = path; | 648 Environment.CurrentDirectory = path; |
610 } | 649 } |
611 } | 650 } |
612 } | 651 } |
LEFT | RIGHT |