diff --git a/hydra/api/api.gen.go b/hydra/api/api.gen.go index c64bc961..be12cc19 100644 --- a/hydra/api/api.gen.go +++ b/hydra/api/api.gen.go @@ -252,13 +252,25 @@ type Jobset_Inputs struct { // JobsetEval defines model for JobsetEval. type JobsetEval struct { - // List of builds generated for this jobset evaluation + // List of builds generated for this jobset evaluation. Builds *[]int `json:"builds,omitempty"` - // is true if the number of JobsetEval members is different from the prior evaluation. (will always be true on the first evaluation) + // How long it took (in seconds) to fetch the jobset inputs. + Checkouttime *int `json:"checkouttime,omitempty"` + + // How long it took (in seconds) to evaluate the jobset. + Evaltime *int `json:"evaltime,omitempty"` + + // For flake jobsets, the immutable flake reference allowing you to reproduce this evaluation. Null otherwise. + Flake *string `json:"flake"` + + // Whether the number of JobsetEval members is different from the prior evaluation. This is always true on the first evaluation. Hasnewbuilds *bool `json:"hasnewbuilds,omitempty"` Id *int `json:"id,omitempty"` Jobsetevalinputs *JobsetEval_Jobsetevalinputs `json:"jobsetevalinputs,omitempty"` + + // Time in seconds since the Unix epoch when this evaluation was created. + Timestamp *int `json:"timestamp,omitempty"` } // JobsetEval_Jobsetevalinputs defines model for JobsetEval.Jobsetevalinputs. @@ -368,6 +380,9 @@ type Project struct { // username of the project owner Owner *string `json:"owner,omitempty"` + + // when set to true the project and all related objects are only accessible to authenticated users + Private *bool `json:"private,omitempty"` } // SearchResult defines model for SearchResult. @@ -435,6 +450,9 @@ type PutProjectIdJSONBody struct { // owner of the project Owner *string `json:"owner,omitempty"` + // when set to true the project and all related objects are only accessible to authenticated users + Private *bool `json:"private,omitempty"` + // when set to true the project is displayed in the web interface Visible *bool `json:"visible,omitempty"` } @@ -752,6 +770,9 @@ type ClientInterface interface { // GetBuildBuildId request GetBuildBuildId(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetBuildBuildIdConstituents request + GetBuildBuildIdConstituents(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetEvalBuildId request GetEvalBuildId(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -840,6 +861,18 @@ func (c *Client) GetBuildBuildId(ctx context.Context, buildId int, reqEditors .. return c.Client.Do(req) } +func (c *Client) GetBuildBuildIdConstituents(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetBuildBuildIdConstituentsRequest(c.Server, buildId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) GetEvalBuildId(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewGetEvalBuildIdRequest(c.Server, buildId) if err != nil { @@ -1163,6 +1196,40 @@ func NewGetBuildBuildIdRequest(server string, buildId int) (*http.Request, error return req, nil } +// NewGetBuildBuildIdConstituentsRequest generates requests for GetBuildBuildIdConstituents +func NewGetBuildBuildIdConstituentsRequest(server string, buildId int) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "build-id", runtime.ParamLocationPath, buildId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/build/%s/constituents", pathParam0) + if operationPath[0] == '/' { + operationPath = operationPath[1:] + } + operationURL := url.URL{ + Path: operationPath, + } + + queryURL := serverURL.ResolveReference(&operationURL) + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewGetEvalBuildIdRequest generates requests for GetEvalBuildId func NewGetEvalBuildIdRequest(server string, buildId int) (*http.Request, error) { var err error @@ -1679,6 +1746,9 @@ type ClientWithResponsesInterface interface { // GetBuildBuildId request GetBuildBuildIdWithResponse(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*GetBuildBuildIdResponse, error) + // GetBuildBuildIdConstituents request + GetBuildBuildIdConstituentsWithResponse(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*GetBuildBuildIdConstituentsResponse, error) + // GetEvalBuildId request GetEvalBuildIdWithResponse(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*GetEvalBuildIdResponse, error) @@ -1811,6 +1881,29 @@ func (r GetBuildBuildIdResponse) StatusCode() int { return 0 } +type GetBuildBuildIdConstituentsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]Build + JSON404 *Error +} + +// Status returns HTTPResponse.Status +func (r GetBuildBuildIdConstituentsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetBuildBuildIdConstituentsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetEvalBuildIdResponse struct { Body []byte HTTPResponse *http.Response @@ -2166,6 +2259,15 @@ func (c *ClientWithResponses) GetBuildBuildIdWithResponse(ctx context.Context, b return ParseGetBuildBuildIdResponse(rsp) } +// GetBuildBuildIdConstituentsWithResponse request returning *GetBuildBuildIdConstituentsResponse +func (c *ClientWithResponses) GetBuildBuildIdConstituentsWithResponse(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*GetBuildBuildIdConstituentsResponse, error) { + rsp, err := c.GetBuildBuildIdConstituents(ctx, buildId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetBuildBuildIdConstituentsResponse(rsp) +} + // GetEvalBuildIdWithResponse request returning *GetEvalBuildIdResponse func (c *ClientWithResponses) GetEvalBuildIdWithResponse(ctx context.Context, buildId int, reqEditors ...RequestEditorFn) (*GetEvalBuildIdResponse, error) { rsp, err := c.GetEvalBuildId(ctx, buildId, reqEditors...) @@ -2409,6 +2511,39 @@ func ParseGetBuildBuildIdResponse(rsp *http.Response) (*GetBuildBuildIdResponse, return response, nil } +// ParseGetBuildBuildIdConstituentsResponse parses an HTTP response from a GetBuildBuildIdConstituentsWithResponse call +func ParseGetBuildBuildIdConstituentsResponse(rsp *http.Response) (*GetBuildBuildIdConstituentsResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &GetBuildBuildIdConstituentsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []Build + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + // ParseGetEvalBuildIdResponse parses an HTTP response from a GetEvalBuildIdWithResponse call func ParseGetEvalBuildIdResponse(rsp *http.Response) (*GetEvalBuildIdResponse, error) { bodyBytes, err := ioutil.ReadAll(rsp.Body) @@ -2831,3 +2966,4 @@ func ParseGetSearchResponse(rsp *http.Response) (*GetSearchResponse, error) { return response, nil } + diff --git a/hydra/api/hydra-api.yaml b/hydra/api/hydra-api.yaml index 2a454942..06298c32 100644 --- a/hydra/api/hydra-api.yaml +++ b/hydra/api/hydra-api.yaml @@ -181,6 +181,9 @@ paths: visible: description: when set to true the project is displayed in the web interface type: boolean + private: + description: when set to true the project and all related objects are only accessible to authenticated users + type: boolean declarative: description: declarative input configured for this project type: object @@ -504,6 +507,32 @@ paths: schema: $ref: '#/components/schemas/Error' + /build/{build-id}/constituents: + get: + summary: Retrieves a build's constituent jobs + parameters: + - name: build-id + in: path + description: build identifier + required: true + schema: + type: integer + responses: + '200': + description: build + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Build' + '404': + description: build couldn't be found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /eval/{build-id}: get: summary: Retrieves evaluations identified by build id @@ -578,6 +607,9 @@ components: hidden: description: when set to true the project is not displayed in the web interface type: boolean + private: + description: when set to true the project and all related objects are only accessible to authenticated users + type: boolean enabled: description: when set to true the project gets scheduled for evaluation type: boolean @@ -735,11 +767,24 @@ components: properties: id: type: integer + timestamp: + description: Time in seconds since the Unix epoch when this evaluation was created. + type: integer + checkouttime: + description: How long it took (in seconds) to fetch the jobset inputs. + type: integer + evaltime: + description: How long it took (in seconds) to evaluate the jobset. + type: integer hasnewbuilds: - description: is true if the number of JobsetEval members is different from the prior evaluation. (will always be true on the first evaluation) + description: Whether the number of JobsetEval members is different from the prior evaluation. This is always true on the first evaluation. type: boolean + flake: + description: For flake jobsets, the immutable flake reference allowing you to reproduce this evaluation. Null otherwise. + nullable: true + type: string builds: - description: List of builds generated for this jobset evaluation + description: List of builds generated for this jobset evaluation. type: array items: type: integer diff --git a/hydra/resource_hydra_project.go b/hydra/resource_hydra_project.go index a2fcd06f..d12c93a1 100644 --- a/hydra/resource_hydra_project.go +++ b/hydra/resource_hydra_project.go @@ -92,6 +92,12 @@ func resourceHydraProject() *schema.Resource { MaxItems: 1, Elem: declInputSchema(), }, + "private": { + Description: "Whether or not the project is private.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, }, } } @@ -122,6 +128,11 @@ func createProjectPutBody(project string, d *schema.ResourceData) *api.PutProjec body.Visible = &visible } + private := d.Get("private").(bool) + if private { + body.Private = &private + } + declarative := d.Get("declarative").(*schema.Set) if len(declarative.List()) > 0 { // There will only ever be one declarative block, so it's fine to access the @@ -218,6 +229,7 @@ func resourceHydraProjectRead(ctx context.Context, d *schema.ResourceData, m int d.Set("owner", *projectResponse.Owner) d.Set("enabled", *projectResponse.Enabled) d.Set("visible", !(*projectResponse.Hidden)) + d.Set("private", *projectResponse.Private) // If Declarative can be dereferenced and every field is not empty, we update // the internal representation with it. If the project was never declarative, diff --git a/tools/generator.sh b/tools/generator.sh index 449189d6..1768956b 100755 --- a/tools/generator.sh +++ b/tools/generator.sh @@ -120,6 +120,7 @@ renderProject() { enabled=$(boolFrom "$project" ".enabled") visible=$(boolFrom "$project" ".hidden == false") declarative=$(declarativeConfig "$project") + private=$(boolFrom "$project" ".private") cat <<-TPL resource "hydra_project" "$name" { @@ -130,6 +131,7 @@ resource "hydra_project" "$name" { owner = "$owner" enabled = $enabled visible = $visible + private = $private TPL if [ -n "$declarative" ]; then @@ -266,7 +268,7 @@ generate() { echo "Processing jobset '$projectname/$jobsetname'..." >&2 echo - jobset="$(curl --silent --header "Accept: application/json" "$serverRoot/jobset/$projectname/$jobsetname" | jq .)" + jobset="$(curl --silent --header "Accept: application/json" "$serverRoot/jobset/$projectname/$jobsetname" -b "$cookieJar" | jq .)" renderJobset "$projectname" "$jobsetname" "$jobset" done < <(echo "$project" | jq -r ".jobsets | sort | .[]") fi @@ -283,7 +285,7 @@ generate() { } help() { - echo "Usage: $(basename "$0") " + echo "Usage: $(basename "$0") [--include-private]" echo echo " Arguments:" echo " The root of the Hydra server to import projects and jobsets from." @@ -297,6 +299,12 @@ main() { serverRoot="$1" generatedDir="$2" importFile="$3" + if [ "${4:-}" = "--include-private" ]; then + includePrivate="1" + else + includePrivate="0" + fi + cookieJar="$(mktemp)" if [ -z "$serverRoot" ] || [ -z "$generatedDir" ] || [ -z "$importFile" ]; then help @@ -315,11 +323,26 @@ main() { inputFile=$(mktemp -t projects.json.XXXXXXXXXX) finish() { rm -f "$inputFile" + rm -f "$cookieJar" } trap finish EXIT + if [ "$includePrivate" = 1 ]; then + echo -n "Username: " + read -r username + echo -n "Password: " + read -rs pw + curl -X POST -c "$cookieJar" \ + "$serverRoot"/login \ + --fail --silent --show-error -o /dev/null \ + -d '{"username":"'"$username"'","password":"'"$pw"'"}' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + --referer "$serverRoot" + fi + echo "Fetching projects.json..." - curl --silent --show-error --header "Accept: application/json" "$serverRoot" > "$inputFile" + curl --silent --show-error --header "Accept: application/json" "$serverRoot" -b "$cookieJar" > "$inputFile" echo "Starting generation..." generate