diff --git a/.gitignore b/.gitignore index 5172c43eb4..70585dec2b 100644 --- a/.gitignore +++ b/.gitignore @@ -196,8 +196,6 @@ Gemfile.lock src/generator/AutoRest.Go.Tests/pkg/* src/generator/AutoRest.Go.Tests/bin/* src/generator/AutoRest.Go.Tests/src/github.com/* -src/generator/AutoRest.Go.Tests/src/test/vendor/* -src/generator/AutoRest.Go.Tests/src/test/generated/* src/generator/AutoRest.Go.Tests/src/tests/generated/* src/generator/AutoRest.Go.Tests/src/tests/vendor/* src/generator/AutoRest.Go.Tests/src/tests/glide.lock diff --git a/CodeGenerator.sln b/CodeGenerator.sln index e7f94bb10c..3600202f96 100644 --- a/CodeGenerator.sln +++ b/CodeGenerator.sln @@ -37,6 +37,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRest.Ruby", "src\genera EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRest.Ruby.Azure", "src\generator\AutoRest.Ruby.Azure\AutoRest.Ruby.Azure.csproj", "{31931998-7543-41DA-9E58-D9670D810352}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutoRest.Go", "src\generator\AutoRest.Go\AutoRest.Go.xproj", "{BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Go", "Go", "{49002B6B-C3F6-490E-874A-3113905DF17B}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{04E8E124-852C-4B5D-83EB-0B8ADDE825CB}" ProjectSection(SolutionItems) = preProject build.proj = build.proj @@ -247,6 +251,16 @@ Global {31931998-7543-41DA-9E58-D9670D810352}.Portable-Release|Any CPU.ActiveCfg = Portable-Release|Any CPU {31931998-7543-41DA-9E58-D9670D810352}.Portable-Release|Any CPU.Build.0 = Portable-Release|Any CPU {31931998-7543-41DA-9E58-D9670D810352}.Release|Any CPU.ActiveCfg = Portable-Release|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Debug|Any CPU.ActiveCfg = Portable-Debug|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Net45-Debug|Any CPU.ActiveCfg = Net45-Debug|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Net45-Debug|Any CPU.Build.0 = Net45-Debug|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Net45-Release|Any CPU.ActiveCfg = Net45-Release|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Net45-Release|Any CPU.Build.0 = Net45-Release|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Portable-Debug|Any CPU.ActiveCfg = Portable-Debug|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Portable-Debug|Any CPU.Build.0 = Portable-Debug|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Portable-Release|Any CPU.ActiveCfg = Portable-Release|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Portable-Release|Any CPU.Build.0 = Portable-Release|Any CPU + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5}.Release|Any CPU.ActiveCfg = Portable-Release|Any CPU {34B82690-0083-4F4C-8ABF-2D2A09304915}.Debug|Any CPU.ActiveCfg = Portable-Debug|Any CPU {34B82690-0083-4F4C-8ABF-2D2A09304915}.Net45-Debug|Any CPU.ActiveCfg = Net45-Debug|Any CPU {34B82690-0083-4F4C-8ABF-2D2A09304915}.Net45-Debug|Any CPU.Build.0 = Net45-Debug|Any CPU @@ -440,6 +454,8 @@ Global {DE95444A-F6FD-46DC-BBDC-A1A6886A6F2D} = {EF9E346D-70C6-45F5-8FF9-9B734F4A1298} {A7780698-3072-486E-A105-81EDDF552598} = {DE95444A-F6FD-46DC-BBDC-A1A6886A6F2D} {31931998-7543-41DA-9E58-D9670D810352} = {DE95444A-F6FD-46DC-BBDC-A1A6886A6F2D} + {BEDCF556-6CEA-4EAE-ACE3-8B9EFE0818E5} = {49002B6B-C3F6-490E-874A-3113905DF17B} + {49002B6B-C3F6-490E-874A-3113905DF17B} = {EF9E346D-70C6-45F5-8FF9-9B734F4A1298} {5989E210-AE15-4DF4-8CEE-DEE609740FD2} = {04E8E124-852C-4B5D-83EB-0B8ADDE825CB} {9750C692-C2D0-4D0F-9F73-D45DB9E906CE} = {5989E210-AE15-4DF4-8CEE-DEE609740FD2} {A9C01442-1E93-4C2D-9182-B61C9F53C3FF} = {EF9E346D-70C6-45F5-8FF9-9B734F4A1298} diff --git a/Documentation/building-code.md b/Documentation/building-code.md index 4aa722a7e9..70d6445508 100644 --- a/Documentation/building-code.md +++ b/Documentation/building-code.md @@ -14,6 +14,8 @@ To set up a machine with the necessary tools for building AutoRest, run `.\Tools - Gradle - Python - tox +- Go +- glide - Visual Studio 2015 - .NET CoreCLR @@ -89,6 +91,15 @@ gem install bundler Install [Python 2.7 and Python 3.5](https://www.python.org/downloads/), and add one of them to your PATH (we recommend 3.5). >set PATH=PATH;C:\Python35 +### Go +Install [Go 1.7](https://golang.org/dl/). Ensure Go is in your `PATH`. +>set PATH=PATH;C:\Go\bin +Add your [GOPATH](https://golang.org/doc/code.html#GOPATH) to your environment variables. + +#### Glide + +Install [glide](https://github.com/Masterminds/glide). Add glide to your `PATH`. + ### Testing Your Environment To make sure you've set up all the prerequisites correctly, run `.\Tools\Verify-Settings.ps1` before you attempt to build. diff --git a/gulpfile.js b/gulpfile.js index 64d763fdeb..572fe1bd85 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -131,6 +131,8 @@ var goMappings = { 'required-optional':['../../dev/TestServer/swagger/required-optional.json','optionalgroup'], 'url':['../../dev/TestServer/swagger/url.json','urlgroup'], 'validation':['../../dev/TestServer/swagger/validation.json', 'validationgroup'], + 'paging':['../../dev/TestServer/swagger/paging.json', 'paginggroup'], + 'azurereport':['../../dev/TestServer/swagger/azure-report.json', 'azurereport'] }; var defaultAzureMappings = { diff --git a/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/paginggrouptest/paging_test.go b/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/paginggrouptest/paging_test.go new file mode 100644 index 0000000000..554c265400 --- /dev/null +++ b/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/paginggrouptest/paging_test.go @@ -0,0 +1,138 @@ +package paginggrouptest + +import ( + "net/http" + "testing" + + chk "gopkg.in/check.v1" + + "tests/acceptancetests/utils" + . "tests/generated/paging" +) + +func Test(t *testing.T) { chk.TestingT(t) } + +type PagingGroupSuite struct{} + +var _ = chk.Suite(&PagingGroupSuite{}) + +var pagingClient = getPagingClient() +var clientID = "client-id" + +func getPagingClient() PagingClient { + c := NewPagingClient() + c.BaseURI = utils.GetBaseURI() + return c +} + +func (s *PagingGroupSuite) TestGetMultiplePages(c *chk.C) { + res, err := pagingClient.GetMultiplePages(clientID, nil, nil) + c.Assert(err, chk.IsNil) + c.Assert(res.NextLink, chk.NotNil) + count := 1 + for res.NextLink != nil { + count++ + resNext, err := pagingClient.GetMultiplePagesNextResults(res) + c.Assert(err, chk.IsNil) + res = resNext + } + c.Assert(count, chk.Equals, 10) +} + +func (s *PagingGroupSuite) TestGetSinglePages(c *chk.C) { + res, err := pagingClient.GetSinglePages() + c.Assert(err, chk.IsNil) + c.Assert(res.NextLink, chk.IsNil) +} + +func (s *PagingGroupSuite) TestGetOdataMultiplePages(c *chk.C) { + res, err := pagingClient.GetOdataMultiplePages(clientID, nil, nil) + c.Assert(err, chk.IsNil) + c.Assert(res.OdataNextLink, chk.NotNil) + count := 1 + for res.OdataNextLink != nil { + count++ + resNext, err := pagingClient.GetOdataMultiplePagesNextResults(res) + c.Assert(err, chk.IsNil) + res = resNext + } + c.Assert(count, chk.Equals, 10) +} + +func (s *PagingGroupSuite) TestGetMultiplePagesWithOffset(c *chk.C) { + res, err := pagingClient.GetMultiplePagesWithOffset(100, clientID, nil, nil) + c.Assert(err, chk.IsNil) + c.Assert(res.NextLink, chk.NotNil) + count := 1 + for res.NextLink != nil { + count++ + resNext, err := pagingClient.GetMultiplePagesWithOffsetNextResults(res) + c.Assert(err, chk.IsNil) + res = resNext + } + c.Assert(count, chk.Equals, 10) + c.Assert(*(*res.Values)[0].Properties.ID, chk.Equals, int32(110)) +} + +func (s *PagingGroupSuite) TestGetMultiplePagesRetryFirst(c *chk.C) { + res, err := pagingClient.GetMultiplePagesRetryFirst() + c.Assert(err, chk.IsNil) + count := 1 + for res.NextLink != nil { + count++ + resNext, err := pagingClient.GetMultiplePagesRetryFirstNextResults(res) + c.Assert(err, chk.IsNil) + res = resNext + } + c.Assert(count, chk.Equals, 10) +} + +func (s *PagingGroupSuite) TestGetMultiplePagesRetrySecond(c *chk.C) { + res, err := pagingClient.GetMultiplePagesRetrySecond() + c.Assert(err, chk.IsNil) + count := 1 + for res.NextLink != nil { + count++ + resNext, err := pagingClient.GetMultiplePagesRetrySecondNextResults(res) + c.Assert(err, chk.IsNil) + res = resNext + } + c.Assert(count, chk.Equals, 10) +} + +func (s *PagingGroupSuite) TestGetSinglePagesFailure(c *chk.C) { + res, err := pagingClient.GetSinglePagesFailure() + c.Assert(err, chk.NotNil) + c.Assert(res.StatusCode, chk.Equals, http.StatusBadRequest) +} + +func (s *PagingGroupSuite) TestGetMultiplePagesFailure(c *chk.C) { + res, err := pagingClient.GetMultiplePagesFailure() + c.Assert(err, chk.IsNil) + c.Assert(res.NextLink, chk.NotNil) + res, err = pagingClient.GetMultiplePagesFailureNextResults(res) + c.Assert(err, chk.NotNil) + c.Assert(res.StatusCode, chk.Equals, http.StatusBadRequest) +} + +func (s *PagingGroupSuite) TestGetMultiplePagesFailureURI(c *chk.C) { + res, err := pagingClient.GetMultiplePagesFailureURI() + c.Assert(err, chk.IsNil) + c.Assert(*res.NextLink, chk.Equals, "*&*#&$") + _, err = pagingClient.GetMultiplePagesFailureURINextResults(res) + c.Assert(err, chk.NotNil) + c.Assert(err, chk.ErrorMatches, ".*No scheme detected in URL.*") +} + +func (s *PagingGroupSuite) TestGetMultiplePagesFragmentNextLink(c *chk.C) { + res, err := pagingClient.GetMultiplePagesFragmentNextLink("1.6", "test_user") + c.Assert(err, chk.IsNil) + count := 1 + for res.OdataNextLink != nil { + count++ + resNext, err := pagingClient.NextFragment("1.6", "test_user", *res.OdataNextLink) + c.Assert(err, chk.IsNil) + res = resNext + } + c.Assert(count, chk.Equals, 10) +} diff --git a/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/utils/utils.go b/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/utils/utils.go index 4b93d292c8..9693677a41 100644 --- a/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/utils/utils.go +++ b/src/generator/AutoRest.Go.Tests/src/tests/acceptancetests/utils/utils.go @@ -18,13 +18,5 @@ func ToDateTime(s string) date.Time { } func GetBaseURI() string { - /* - if strings.HasPrefix(baseURI, "https") { - baseURI = "http://localhost:3000" - } else { - baseURI += ":3000" - } - return baseURI - */ return "http://localhost:3000" } diff --git a/src/generator/AutoRest.Go.Tests/src/tests/runner.go b/src/generator/AutoRest.Go.Tests/src/tests/runner.go index 48450a4dac..ee92b83f43 100644 --- a/src/generator/AutoRest.Go.Tests/src/tests/runner.go +++ b/src/generator/AutoRest.Go.Tests/src/tests/runner.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "tests/acceptancetests/utils" + "tests/generated/azurereport" "tests/generated/report" ) @@ -17,6 +18,7 @@ func main() { allPass := true runTests(&allPass) getReport() + getAzureReport() server.Kill() if !allPass { fmt.Println("Not all tests passed") @@ -64,7 +66,7 @@ func runTests(allPass *bool) { "custombaseurlgroup", "filegroup", // "formdatagroup", - } + "paginggroup"} for _, suite := range testSuites { fmt.Printf("Run test (go test ./acceptancetests/%vtest -v) ...\n", suite) @@ -78,7 +80,7 @@ func runTests(allPass *bool) { fmt.Printf("Error! %v\n", err) *allPass = false } - if stderr.String()[:2] != "OK" { + if len(stderr.String()) >= 2 && stderr.String()[:2] != "OK" { *allPass = false } } @@ -90,15 +92,28 @@ func getReport() { if err != nil { fmt.Println("Error:", err) } + printReport(res.Value, "") +} +func getAzureReport() { + var reportClient = azurereport.NewWithBaseURI(utils.GetBaseURI()) + res, err := reportClient.GetReport() + if err != nil { + fmt.Println("Error:", err) + } + printReport(res.Value, "Azure") +} + +func printReport(res *map[string]*int32, report string) { count := 0 - for key, val := range *res.Value { + for key, val := range *res { if *val <= 0 { fmt.Println(key, *val) count++ } } - total := len(*res.Value) + total := len(*res) fmt.Printf("\nReport: Passed(%v) Failed(%v)\n", total-count, count) - fmt.Println("Go Done.......\n") + fmt.Printf("Go %s Done.......\n\n", report) + } diff --git a/src/generator/AutoRest.Go/Extensions.cs b/src/generator/AutoRest.Go/Extensions.cs index 494a8620f1..eb12878698 100644 --- a/src/generator/AutoRest.Go/Extensions.cs +++ b/src/generator/AutoRest.Go/Extensions.cs @@ -6,11 +6,13 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Newtonsoft.Json; using AutoRest.Core.ClientModel; using AutoRest.Core.Utilities; using AutoRest.Go.TemplateModels; using AutoRest.Extensions.Azure; +using AutoRest.Extensions.Azure.Model; namespace AutoRest.Go { @@ -380,7 +382,7 @@ private static string GetSeparator(this CollectionFormat format) public static bool IsClientProperty(this Parameter parameter) { - return parameter.ClientProperty != null; + return parameter.ClientProperty != null || parameter.SerializedName.IsApiVersion(); } public static string GetParameterName(this Parameter parameter) @@ -397,7 +399,7 @@ public static bool IsMethodArgument(this Parameter parameter) public static bool IsApiVersion(this string name) { - string rgx = @"^api[^a-zA-Z0-9]?version"; + string rgx = @"^api[^a-zA-Z0-9_]?version"; return Regex.IsMatch(name, rgx, RegexOptions.IgnoreCase); } @@ -560,7 +562,13 @@ public static string Fields(this CompositeType compositeType) && !String.IsNullOrEmpty((compositeType as ModelTemplateModel).NextLink)) { var nextLinkField = (compositeType as ModelTemplateModel).NextLink; - if (!properties.Any(p => p.Name == nextLinkField)) + foreach (Property p in properties) { + p.Name = GoCodeNamer.PascalCaseWithoutChar(p.Name, '.'); + if (p.Name.Equals(nextLinkField, StringComparison.OrdinalIgnoreCase)) { + p.Name = nextLinkField; + } + } + if (!properties.Any(p => p.Name.Equals(nextLinkField, StringComparison.OrdinalIgnoreCase))) { var property = new Property(); property.Name = nextLinkField; @@ -983,6 +991,24 @@ public static bool IsPageable(this Method method) return !string.IsNullOrEmpty(method.NextLink()); } + /// + /// Checks if method for next page of results on paged methods is already present in the method list. + /// + /// + /// + /// + public static bool NextMethodExists(this Method method, List methods) { + if (method.Extensions.ContainsKey(AzureExtensions.PageableExtension)) + { + var pageableExtension = JsonConvert.DeserializeObject(method.Extensions[AzureExtensions.PageableExtension].ToString()); + if (pageableExtension != null && !string.IsNullOrWhiteSpace(pageableExtension.OperationName)) + { + return methods.Any(m => m.SerializedName.Equals(pageableExtension.OperationName, StringComparison.OrdinalIgnoreCase)); + } + } + return false; + } + /// /// Check if method has long running extension (x-ms-long-running-operation) enabled. /// @@ -1022,7 +1048,7 @@ public static string NextLink(this Method method) var nextLinkName = (string)pageableExtension["nextLinkName"]; if (!string.IsNullOrEmpty(nextLinkName)) { - nextLink = GoCodeNamer.PascalCase(nextLinkName); + nextLink = GoCodeNamer.PascalCaseWithoutChar(nextLinkName, '.'); } } } diff --git a/src/generator/AutoRest.Go/GoCodeNamer.cs b/src/generator/AutoRest.Go/GoCodeNamer.cs index 9968e431c4..93aa9eb42f 100644 --- a/src/generator/AutoRest.Go/GoCodeNamer.cs +++ b/src/generator/AutoRest.Go/GoCodeNamer.cs @@ -214,7 +214,7 @@ public GoCodeNamer() "unsafe", // Other reserved names and packages (defined by the base libraries this code uses) - "autorest", "client", "date", "err", "req", "resp", "result", "sender" + "autorest", "client", "date", "err", "req", "resp", "result", "sender", "to", "validation" }.ToList().ForEach(s => ReservedWords.Add(s)); @@ -533,6 +533,27 @@ private IType NormalizeDictionaryType(DictionaryType dictionaryType) return new MapType(NormalizeTypeReference(dictionaryType.ValueType)); } + /// + /// Formats a string to pascal case using a specific character as splitter + /// + /// + /// + /// The formatted string + public static string PascalCaseWithoutChar(string name, char splitter) + { + if (string.IsNullOrWhiteSpace(name)) + { + return name; + } + + return + name.Split(splitter) + .Where(s => !string.IsNullOrEmpty(s)) + .Select(s => char.ToUpperInvariant(s[0]) + s.Substring(1, s.Length - 1)) + .DefaultIfEmpty("") + .Aggregate(string.Concat); + } + public override string GetEnumMemberName(string name) { return EnsureNameCase(base.GetEnumMemberName(name)); diff --git a/src/generator/AutoRest.Go/MethodScopeProvider.cs b/src/generator/AutoRest.Go/MethodScopeProvider.cs index c3d59831c8..544052f1f4 100644 --- a/src/generator/AutoRest.Go/MethodScopeProvider.cs +++ b/src/generator/AutoRest.Go/MethodScopeProvider.cs @@ -43,7 +43,7 @@ public void AddGroupedMethods(IEnumerable methodNames, string methodGrou /// /// The method prefix /// The method group - /// The suffux added to the variable - a simple counter is used to generate new method names + /// The suffix added to the variable - a simple counter is used to generate new method names /// A method name unique in this scope public string GetMethodName(string prefix, string group, int suffix = 0) { diff --git a/src/generator/AutoRest.Go/TemplateModels/MethodTemplateModel.cs b/src/generator/AutoRest.Go/TemplateModels/MethodTemplateModel.cs index b039cd4ace..ff48674c6f 100644 --- a/src/generator/AutoRest.Go/TemplateModels/MethodTemplateModel.cs +++ b/src/generator/AutoRest.Go/TemplateModels/MethodTemplateModel.cs @@ -22,14 +22,16 @@ public class MethodTemplateModel : Method private readonly string lroDescription = " This method may poll for completion. Polling can be canceled by passing the cancel channel argument. " + "The channel will be used to cancel polling and any outstanding HTTP requests."; + public readonly bool NextAlreadyDefined = true; - public MethodTemplateModel(Method source, string owner, string packageName, MethodScopeProvider methodScope) + public MethodTemplateModel(Method source, string owner, string packageName, MethodScopeProvider methodScope, bool next) { this.LoadFrom(source); MethodScope = methodScope; Owner = owner; PackageName = packageName; + NextAlreadyDefined = next; var parameter = Parameters.Find(p => p.Type.IsPrimaryType(KnownPrimaryType.Stream) && !(p.Location == ParameterLocation.Body || p.Location == ParameterLocation.FormData)); @@ -151,7 +153,7 @@ public string HelperInvocationParameters } /// - /// Return the parameters as they apopear in the method signature excluding global parameters. + /// Return the parameters as they appear in the method signature excluding global parameters. /// public IEnumerable LocalParameters { @@ -159,8 +161,8 @@ public IEnumerable LocalParameters { return Parameters.Where( - p => p != null && p.IsMethodArgument() && !string.IsNullOrWhiteSpace(p.Name) && !p.SerializedName.IsApiVersion()) - .OrderBy(item => !item.IsRequired); + p => p != null && p.IsMethodArgument() && !string.IsNullOrWhiteSpace(p.Name)) + .OrderBy(item => !item.IsRequired); } } public string ParameterValidations diff --git a/src/generator/AutoRest.Go/TemplateModels/ModelTemplateModel.cs b/src/generator/AutoRest.Go/TemplateModels/ModelTemplateModel.cs index 4589ff5010..72acc32ab5 100644 --- a/src/generator/AutoRest.Go/TemplateModels/ModelTemplateModel.cs +++ b/src/generator/AutoRest.Go/TemplateModels/ModelTemplateModel.cs @@ -21,6 +21,8 @@ public class ModelTemplateModel : CompositeType // (null or empty if the model is not paged). public string NextLink; + public bool PreparerNeeded = false; + public ModelTemplateModel(CompositeType source) { this.LoadFrom(source); diff --git a/src/generator/AutoRest.Go/TemplateModels/ModelsTemplateModel.cs b/src/generator/AutoRest.Go/TemplateModels/ModelsTemplateModel.cs index b8585e5fb4..dbac9550c3 100644 --- a/src/generator/AutoRest.Go/TemplateModels/ModelsTemplateModel.cs +++ b/src/generator/AutoRest.Go/TemplateModels/ModelsTemplateModel.cs @@ -6,6 +6,7 @@ using AutoRest.Core.ClientModel; using AutoRest.Core.Utilities; +using AutoRest.Go; namespace AutoRest.Go.TemplateModels { @@ -15,6 +16,9 @@ public class ModelsTemplateModel : ServiceClient public List ModelTemplateModels { get; set; } public string PackageName { get; set; } public Dictionary PagedTypes { get; set; } + // NextMethodUndefined is used to keep track of those models which are returned by paged methods, + // but the next method is not defined in the service client, so these models need a preparer. + public List NextMethodUndefined { get; set; } public ModelsTemplateModel(ServiceClient serviceClient, string packageName) { @@ -92,6 +96,7 @@ public ModelsTemplateModel(ServiceClient serviceClient, string packageName) // Find all methods that returned paged results PagedTypes = new Dictionary(); + NextMethodUndefined = new List(); serviceClient.Methods .Where(m => m.IsPageable()) .ForEach(m => @@ -100,6 +105,9 @@ public ModelsTemplateModel(ServiceClient serviceClient, string packageName) { PagedTypes.Add(m.ReturnValue().Body, m.NextLink()); } + if (!m.NextMethodExists(serviceClient.Methods)) { + NextMethodUndefined.Add(m.ReturnValue().Body); + } }); // Mark all models returned by one or more methods and note any "next link" fields used with paged data @@ -113,7 +121,12 @@ public ModelsTemplateModel(ServiceClient serviceClient, string packageName) mtm.IsResponseType = true; if (PagedTypes.ContainsKey(mtm)) { - mtm.NextLink = PagedTypes[mtm]; + mtm.NextLink = GoCodeNamer.PascalCaseWithoutChar(PagedTypes[mtm], '.'); + if (NextMethodUndefined.Contains(mtm)) { + mtm.PreparerNeeded = true; + } else { + mtm.PreparerNeeded = false; + } } }); @@ -134,7 +147,7 @@ public virtual IEnumerable Imports .ForEach(mt => { (mt as CompositeType).AddImports(imports); - if (PagedTypes.ContainsKey(mt)) + if (NextMethodUndefined.Count > 0) { imports.UnionWith(GoCodeNamer.PageableImports); } diff --git a/src/generator/AutoRest.Go/TemplateModels/ServiceClientTemplateModel.cs b/src/generator/AutoRest.Go/TemplateModels/ServiceClientTemplateModel.cs index 3e2224d2f2..50a2c5de43 100644 --- a/src/generator/AutoRest.Go/TemplateModels/ServiceClientTemplateModel.cs +++ b/src/generator/AutoRest.Go/TemplateModels/ServiceClientTemplateModel.cs @@ -39,10 +39,9 @@ public ServiceClientTemplateModel(ServiceClient serviceClient, string packageNam : (MethodGroupName + "Client").TrimPackageName(PackageName); MethodScope = new MethodScopeProvider(); MethodTemplateModels = new List(); - Methods.Where(m => m.BelongsToGroup(MethodGroupName, PackageName)) - .OrderBy(m => m.Name) - .ForEach(m => MethodTemplateModels.Add(new MethodTemplateModel(m, ClientName, PackageName, new MethodScopeProvider()))); + .OrderBy(m => m.Name) + .ForEach(m => MethodTemplateModels.Add(new MethodTemplateModel(m, ClientName, PackageName, new MethodScopeProvider(), m.NextMethodExists(Methods)))); Documentation = string.Format("Package {0} implements the Azure ARM {1} service API version {2}.\n\n{3}", PackageName, ServiceName, ApiVersion, !string.IsNullOrEmpty(Documentation) ? Documentation.UnwrapAnchorTags() : ""); diff --git a/src/generator/AutoRest.Go/Templates/MethodTemplate.cshtml b/src/generator/AutoRest.Go/Templates/MethodTemplate.cshtml index c276c7b258..fc80f22084 100644 --- a/src/generator/AutoRest.Go/Templates/MethodTemplate.cshtml +++ b/src/generator/AutoRest.Go/Templates/MethodTemplate.cshtml @@ -151,7 +151,7 @@ func (client @(Model.Owner)) @(Model.ResponderMethodName)(resp *http.Response) ( return } -@if (Model.IsPageable()) +@if (Model.IsPageable() && !Model.NextAlreadyDefined) { @:@EmptyLine @:// @(Model.NextMethodName) retrieves the next set of results, if any. diff --git a/src/generator/AutoRest.Go/Templates/ModelTemplate.cshtml b/src/generator/AutoRest.Go/Templates/ModelTemplate.cshtml index d90f9d3a57..f6ad6afb59 100644 --- a/src/generator/AutoRest.Go/Templates/ModelTemplate.cshtml +++ b/src/generator/AutoRest.Go/Templates/ModelTemplate.cshtml @@ -14,7 +14,7 @@ type @Model.Name struct { @(Model.Fields()) } -@if (!string.IsNullOrEmpty(Model.NextLink)) +@if (!string.IsNullOrEmpty(Model.NextLink) && Model.PreparerNeeded) { @:@EmptyLine @:// @(Model.PreparerMethodName()) prepares a request to retrieve the next set of results. It returns diff --git a/src/generator/AutoRest.Go/VariableScopeProvider.cs b/src/generator/AutoRest.Go/VariableScopeProvider.cs index 16882b70db..dd84ac1c53 100644 --- a/src/generator/AutoRest.Go/VariableScopeProvider.cs +++ b/src/generator/AutoRest.Go/VariableScopeProvider.cs @@ -16,7 +16,7 @@ public class VariableScopeProvider : IScopeProvider /// Get a variable name that is unique in this method's scope /// /// The variable prefix - /// The suffux added to the variable - a simple counter is used to generate new variable names + /// The suffix added to the variable - a simple counter is used to generate new variable names /// A variable name unique in this method public string GetVariableName(string prefix, int suffix = 0) { diff --git a/src/generator/AutoRest.Go/rakefile.rb b/src/generator/AutoRest.Go/rakefile.rb index beca978706..c23f14b894 100644 --- a/src/generator/AutoRest.Go/rakefile.rb +++ b/src/generator/AutoRest.Go/rakefile.rb @@ -9,17 +9,18 @@ AUTOREST = "../../core/AutoRest/bin/Debug/net451/win7-x64/AutoRest.exe" SWAGGER_VERSIONS = { + # asazure: {version: "2016-05-06"}, authorization: {version: "2015-07-01"}, batch: {version: "2015-12-01", swagger: "BatchManagement"}, cdn: {version: "2016-04-02"}, cognitiveservices: {version: "2016-02-01-preview"}, - compute: {version: "2016-03-30"}, + compute: {version: "2016-03-30"}, #composite swagger (includes container service) # containerservice: {version: "2016-03-30", swagger: "containerservice"}, # commerce: {version: "2015-06-01-preview"}, datalake_analytics: { account: {version: "2015-10-01-preview"}, # catalog: {version: "2016-06-01-preview"}, - job: {version: "2016-03-20-preview"} + # job: {version: "2016-03-20-preview"} }, datalake_store: { account: {version: "2015-10-01-preview"}, @@ -28,33 +29,44 @@ devtestlabs: {version: "2016-05-15", swagger: "DTL"}, dns: {version: "2016-04-01"}, eventhub: {version: "2015-08-01", swagger: "EventHub"}, - # graphrbac: {version: "1.6"}, + graphrbac: {version: "1.6"}, # composite swagger + # insights (composite swagger) intune: {version: "2015-01-14-preview"}, iothub: {version: "2016-02-03"}, keyvault: {version: "2015-06-01"}, - logic: {version: "2016-06-01"}, - machinelearning: {version: "2016-05-01-preview", swagger: "webservices"}, + logic: {version: "2016-06-01"}, #composite swagger + # machine learning has two swaggers, but not a composite swagger + # this service should follow the same structure as the resources service and clients + # machinelearning: {version: "2016-05-01-preview", swagger: "webservices"}, + machinelearning: { + webservices: {version: "2016-05-01-preview", swagger: "webservices"}, + commitmentplans: {version: "2016-05-01-preview", swagger: "commitmentPlans"} + }, mediaservices: {version: "2015-10-01", swagger: "media"}, mobileengagement: {version: "2014-12-01", swagger: "mobile-engagement"}, network: {version: "2016-09-01"}, notificationhubs: {version: "2016-03-01"}, powerbiembedded: {version: "2016-01-29"}, + # recoveryservices: {version: "2016-06-01"}, + # recoveryservicesbackup: {version: "2016-06-01"}, redis: {version: "2016-04-01"}, resources: { features: {version: "2015-12-01"}, - locks: {version: "2015-01-01"}, - resources: {version: "2016-07-01"}, + locks: {version: "2016-09-01"}, policy: {version: "2016-04-01"}, + resources: {version: "2016-09-01"}, + # generator has a bug and generates an ugly SDK for subscription newest API version + # subscriptions: {version: "2016-06-01"} subscriptions: {version: "2015-11-01"} }, scheduler: {version: "2016-03-01"}, search: {version: "2015-02-28"}, - servermanagement: {version: "2015-07-01-preview"}, + servermanagement: {version: "2016-07-01-preview"}, servicebus: {version: "2015-08-01"}, sql: {version: "2015-05-01"}, storage: {version: "2016-01-01"}, trafficmanager: {version: "2015-11-01"}, - web: {version: "2015-08-01", swagger: "service"} + web: {version: "2015-08-01", swagger: "service"} # composite swagger } class Service