Skip to content

Instantly share code, notes, and snippets.

@matteogastaldello
Created May 8, 2024 10:29
Show Gist options
  • Save matteogastaldello/823cdaf0127c2f2eaa92ddb574539825 to your computer and use it in GitHub Desktop.
Save matteogastaldello/823cdaf0127c2f2eaa92ddb574539825 to your computer and use it in GitHub Desktop.
openapi: 3.0.1
info:
title: Feed
description: ""
termsOfService: https://go.microsoft.com/fwlink/?LinkId=329770
contact:
name: nugetvss
email: nugetvss@microsoft.com
license:
name: MICROSOFT SOFTWARE LICENSE TERMS
url: https://go.microsoft.com/fwlink/?LinkId=329770
version: "7.0"
externalDocs:
description: Azure DevOps REST APIs
url: https://aka.ms/azure-devops-rest-apis
servers:
- url: https://feeds.dev.azure.com/
security:
- accessToken: []
paths:
/{organization}/{project}/_apis/packaging/feeds:
post:
tags:
- Feed Management
description: |-
Create a feed, a container for various package types.
Feeds can be created in a project if the project parameter is included in the request url.
If the project parameter is omitted, the feed will not be associated with a project and will be created at the organization level.
operationId: Feed Management_Create Feed
parameters:
- name: organization
in: path
description: The name of the Azure DevOps organization.
required: true
schema:
type: string
- name: project
in: path
description: Project ID or project name
required: true
schema:
type: string
x-ms-required: false
x-ms-required: false
- name: api-version
in: query
description: Version of the API to use. This should be set to '7.0' to use
this version of the api.
required: true
schema:
type: string
requestBody:
description: A JSON object containing both required and optional attributes
for the feed. Name is the only required value.
content:
application/json:
schema:
$ref: '#/components/schemas/FeedCore'
required: true
responses:
"200":
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Feed'
security:
- oauth2:
- vso.packaging_write
x-ms-docs-override-version: "7.0"
x-ms-vss-resource: feeds
x-ms-vss-method: CreateFeed
x-codegen-request-body-name: body
components:
schemas:
FeedCore:
type: object
properties:
capabilities:
type: string
description: Supported capabilities of a feed.
enum:
- none
- upstreamV2
- underMaintenance
- defaultCapabilities
x-ms-enum:
name: FeedCapabilities
values:
- value: none
description: No flags exist for this feed
- value: upstreamV2
description: This feed can serve packages from upstream sources Upstream
packages must be manually promoted to views
- value: underMaintenance
description: This feed is currently under maintenance and may have reduced
functionality
- value: defaultCapabilities
description: The capabilities given to a newly created feed
fullyQualifiedId:
type: string
description: This will either be the feed GUID or the feed GUID and view
GUID depending on how the feed was accessed.
fullyQualifiedName:
type: string
description: "Full name of the view, in feed@view format."
id:
type: string
description: A GUID that uniquely identifies this feed.
format: uuid
isReadOnly:
type: boolean
description: "If set, all packages in the feed are immutable. It is important\
\ to note that feed views are immutable; therefore, this flag will always\
\ be set for views."
name:
type: string
description: "A name for the feed. feed names must follow these rules: <list\
\ type=\"bullet\"><item><description> Must not exceed 64 characters </description></item><item><description>\
\ Must not contain whitespaces </description></item><item><description>\
\ Must not start with an underscore or a period </description></item><item><description>\
\ Must not end with a period </description></item><item><description>\
\ Must not contain any of the following illegal characters: <![CDATA[\
\ @, ~, ;, {, }, \\, +, =, <, >, |, /, \\\\, ?, :, &, $, *, \\\", #, [,\
\ ] ]]></description></item></list>"
project:
type: string
description: Project ID or project name
upstreamEnabled:
type: boolean
description: "OBSOLETE: This should always be true. Setting to false will\
\ override all sources in UpstreamSources."
upstreamSources:
type: array
description: A list of sources that this feed will fetch packages from. An
empty list indicates that this feed will not search any additional sources
for packages.
items:
type: string
view:
type: string
viewId:
type: string
description: View Id.
format: uuid
viewName:
type: string
description: View name.
description: An object that contains all of the settings for a specific feed.
# required:
# - name
Feed:
properties:
_links:
type: string
module example.com/m
go 1.22.2
require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pb33f/libopenapi v0.16.5 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect
golang.org/x/sync v0.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
package main
import (
"errors"
"fmt"
"os"
"github.com/pb33f/libopenapi"
"github.com/pb33f/libopenapi/datamodel/high/base"
v3 "github.com/pb33f/libopenapi/datamodel/high/v3"
"github.com/pb33f/libopenapi/orderedmap"
)
func initOAS() (*libopenapi.DocumentModel[v3.Document], error) {
contents, err := os.ReadFile("feeds-simple.yaml")
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
d, err := libopenapi.NewDocument(contents)
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
doc, modelErrors := d.BuildV3Model()
if len(modelErrors) > 0 {
return nil, fmt.Errorf("failed to build model: %w", errors.Join(modelErrors...))
}
if doc == nil {
return nil, fmt.Errorf("failed to build model")
}
// Resolve model references
resolvingErrors := doc.Index.GetResolver().Resolve()
errs := []error{}
for i := range resolvingErrors {
fmt.Println("Resolving error", resolvingErrors[i].Error())
errs = append(errs, resolvingErrors[i].ErrorRef)
}
if len(resolvingErrors) > 0 {
return nil, fmt.Errorf("failed to resolve model references: %w", errors.Join(errs...))
}
return doc, nil
}
func Reproduce(doc *libopenapi.DocumentModel[v3.Document]) (errors []error, fatalError error) {
verbPath := "/{organization}/{project}/_apis/packaging/feeds"
path := doc.Model.Paths.PathItems.Value(verbPath)
if path == nil {
return errors, fmt.Errorf("path %v not found", path)
}
bodySchema := base.CreateSchemaProxy(&base.Schema{Properties: orderedmap.New[string, *base.SchemaProxy]()})
if path.Post.RequestBody != nil {
bodySchema = path.Post.RequestBody.Content.Value("application/json").Schema
}
if bodySchema == nil {
return errors, fmt.Errorf("body schema not found for %s", verbPath)
}
schema, err := bodySchema.BuildSchema()
if err != nil {
return errors, fmt.Errorf("building schema for %s: %w", verbPath, err)
}
schema.Properties.Set("authenticationRefs", base.CreateSchemaProxy(&base.Schema{
Type: []string{"object"},
Description: "AuthenticationRefs represent the reference to a CR containing the authentication information. One authentication method must be set."}))
schema.Required = append(schema.Required, []string{"authenticationRefs"}...)
rend, err := schema.Render()
if err != nil {
return errors, fmt.Errorf("rendering schema for %s: %w", verbPath, err)
}
fmt.Println(string(rend))
return errors, nil
}
func main() {
doc, err := initOAS()
if err != nil {
fmt.Println("Error:", err)
return
}
errors, fatalError := Reproduce(doc)
if fatalError != nil {
fmt.Println("Fatal error:", fatalError)
}
for i := range errors {
fmt.Println("Error:", errors[i])
}
}
@matteogastaldello
Copy link
Author

go run issue.go should reproduce the error described in pb33f/libopenapi#285

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment