.
This commit is contained in:
parent
18bfc87a1c
commit
e47feaf5e8
@ -7,7 +7,7 @@ gitea-generated/client/gitea_api_client.go:: api.json
|
|||||||
[ -d gitea-generated ] || mkdir gitea-generated
|
[ -d gitea-generated ] || mkdir gitea-generated
|
||||||
podman run --rm -v $$(pwd):/api ghcr.io/go-swagger/go-swagger generate client -f /api/api.json -t /api/gitea-generated
|
podman run --rm -v $$(pwd):/api ghcr.io/go-swagger/go-swagger generate client -f /api/api.json -t /api/gitea-generated
|
||||||
|
|
||||||
api: gitea-generated/client/gitea_api_client.go client.gen.go
|
api: gitea-generated/client/gitea_api_client.go
|
||||||
|
|
||||||
build: api
|
build: api
|
||||||
go build
|
go build
|
||||||
|
@ -10549,6 +10549,9 @@
|
|||||||
},
|
},
|
||||||
"/repos/{owner}/{repo}/media/{filepath}": {
|
"/repos/{owner}/{repo}/media/{filepath}": {
|
||||||
"get": {
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/octet-stream"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"repository"
|
"repository"
|
||||||
],
|
],
|
||||||
@ -10585,7 +10588,10 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Returns raw file content."
|
"description": "Returns raw file content.",
|
||||||
|
"schema": {
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
@ -12621,14 +12627,13 @@
|
|||||||
},
|
},
|
||||||
"/repos/{owner}/{repo}/raw/{filepath}": {
|
"/repos/{owner}/{repo}/raw/{filepath}": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
"tags": [
|
||||||
"repository"
|
"repository"
|
||||||
],
|
],
|
||||||
"summary": "Get a file from a repository",
|
"summary": "Get a file from a repository",
|
||||||
"operationId": "repoGetRawFile",
|
"operationId": "repoGetRawFile",
|
||||||
|
"produces" : ["application/octet-stream"],
|
||||||
|
"consumes" : ["application/octet-stream"],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -12660,7 +12665,10 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Returns raw file content."
|
"description": "Returns raw file content.",
|
||||||
|
"schema": {
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
|
@ -3,7 +3,7 @@ package common
|
|||||||
const (
|
const (
|
||||||
GiteaTokenEnv = "GITEA_TOKEN"
|
GiteaTokenEnv = "GITEA_TOKEN"
|
||||||
ObsUserEnv = "OBS_USER"
|
ObsUserEnv = "OBS_USER"
|
||||||
ObsPasswordEnv = "OBS_PW"
|
ObsPasswordEnv = "OBS_PASSWORD"
|
||||||
|
|
||||||
DefaultGitPrj = "_ObsPrj"
|
DefaultGitPrj = "_ObsPrj"
|
||||||
GiteaRequestHeader = "X-Gitea-Event-Type"
|
GiteaRequestHeader = "X-Gitea-Event-Type"
|
||||||
|
@ -174,6 +174,17 @@ func (f writeFunc) Write(data []byte) (int, error) {
|
|||||||
return f(data)
|
return f(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h writeFunc) UnmarshalText(text []byte) error {
|
||||||
|
_, err := h.Write(text)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h writeFunc) Close() error {
|
||||||
|
_, err := h.Write(nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (e *RequestHandler) GitExec(cwd string, params ...string) ExecStream {
|
func (e *RequestHandler) GitExec(cwd string, params ...string) ExecStream {
|
||||||
if e.Error != nil {
|
if e.Error != nil {
|
||||||
return e
|
return e
|
||||||
@ -436,6 +447,61 @@ func parseGitTree(data <-chan byte) (tree, error) {
|
|||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *RequestHandler) GitSubmoduleList(cwd, commitId string) map[string]string {
|
||||||
|
var done sync.Mutex
|
||||||
|
submoduleList := make(map[string]string)
|
||||||
|
|
||||||
|
done.Lock()
|
||||||
|
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer done.Unlock()
|
||||||
|
defer close(data_out.ch)
|
||||||
|
|
||||||
|
data_out.Write([]byte(commitId))
|
||||||
|
data_out.ch <- '\x00'
|
||||||
|
c, err := parseGitCommit(data_in.ch)
|
||||||
|
if err != nil {
|
||||||
|
e.Error = err
|
||||||
|
e.LogError("Error parsing git commit: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data_out.Write([]byte(c.Tree))
|
||||||
|
data_out.ch <- '\x00'
|
||||||
|
tree, err := parseGitTree(data_in.ch)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Error = err
|
||||||
|
e.LogError("Error parsing git tree: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, te := range tree.items {
|
||||||
|
if te.isSubmodule() {
|
||||||
|
submoduleList[te.name] = te.hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
|
||||||
|
cmd.Env = []string{
|
||||||
|
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
|
||||||
|
"GIT_CONFIG_GLOBAL=/dev/null",
|
||||||
|
}
|
||||||
|
cmd.Dir = filepath.Join(e.GitPath, cwd)
|
||||||
|
cmd.Stdout = &data_in
|
||||||
|
cmd.Stdin = &data_out
|
||||||
|
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
|
||||||
|
e.Logger.LogError("%s", data)
|
||||||
|
return len(data), nil
|
||||||
|
})
|
||||||
|
e.Log("command run: %v", cmd.Args)
|
||||||
|
e.Error = cmd.Run()
|
||||||
|
|
||||||
|
done.Lock()
|
||||||
|
return submoduleList
|
||||||
|
}
|
||||||
|
|
||||||
func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, commitId string) (string, bool) {
|
func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, commitId string) (string, bool) {
|
||||||
if e.Error != nil {
|
if e.Error != nil {
|
||||||
return "", false
|
return "", false
|
||||||
|
@ -7,6 +7,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime"
|
"github.com/go-openapi/runtime"
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
@ -15,13 +16,14 @@ import (
|
|||||||
// RepoGetRawFileOrLFSReader is a Reader for the RepoGetRawFileOrLFS structure.
|
// RepoGetRawFileOrLFSReader is a Reader for the RepoGetRawFileOrLFS structure.
|
||||||
type RepoGetRawFileOrLFSReader struct {
|
type RepoGetRawFileOrLFSReader struct {
|
||||||
formats strfmt.Registry
|
formats strfmt.Registry
|
||||||
|
writer io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadResponse reads a server response into the received o.
|
// ReadResponse reads a server response into the received o.
|
||||||
func (o *RepoGetRawFileOrLFSReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
func (o *RepoGetRawFileOrLFSReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||||
switch response.Code() {
|
switch response.Code() {
|
||||||
case 200:
|
case 200:
|
||||||
result := NewRepoGetRawFileOrLFSOK()
|
result := NewRepoGetRawFileOrLFSOK(o.writer)
|
||||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -38,8 +40,11 @@ func (o *RepoGetRawFileOrLFSReader) ReadResponse(response runtime.ClientResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewRepoGetRawFileOrLFSOK creates a RepoGetRawFileOrLFSOK with default headers values
|
// NewRepoGetRawFileOrLFSOK creates a RepoGetRawFileOrLFSOK with default headers values
|
||||||
func NewRepoGetRawFileOrLFSOK() *RepoGetRawFileOrLFSOK {
|
func NewRepoGetRawFileOrLFSOK(writer io.Writer) *RepoGetRawFileOrLFSOK {
|
||||||
return &RepoGetRawFileOrLFSOK{}
|
return &RepoGetRawFileOrLFSOK{
|
||||||
|
|
||||||
|
Payload: writer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -48,6 +53,7 @@ RepoGetRawFileOrLFSOK describes a response with status code 200, with default he
|
|||||||
Returns raw file content.
|
Returns raw file content.
|
||||||
*/
|
*/
|
||||||
type RepoGetRawFileOrLFSOK struct {
|
type RepoGetRawFileOrLFSOK struct {
|
||||||
|
Payload io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSuccess returns true when this repo get raw file or l f s o k response has a 2xx status code
|
// IsSuccess returns true when this repo get raw file or l f s o k response has a 2xx status code
|
||||||
@ -88,8 +94,17 @@ func (o *RepoGetRawFileOrLFSOK) String() string {
|
|||||||
return fmt.Sprintf("[GET /repos/{owner}/{repo}/media/{filepath}][%d] repoGetRawFileOrLFSOK", 200)
|
return fmt.Sprintf("[GET /repos/{owner}/{repo}/media/{filepath}][%d] repoGetRawFileOrLFSOK", 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *RepoGetRawFileOrLFSOK) GetPayload() io.Writer {
|
||||||
|
return o.Payload
|
||||||
|
}
|
||||||
|
|
||||||
func (o *RepoGetRawFileOrLFSOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
func (o *RepoGetRawFileOrLFSOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
// response payload
|
||||||
|
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime"
|
"github.com/go-openapi/runtime"
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
@ -15,13 +16,14 @@ import (
|
|||||||
// RepoGetRawFileReader is a Reader for the RepoGetRawFile structure.
|
// RepoGetRawFileReader is a Reader for the RepoGetRawFile structure.
|
||||||
type RepoGetRawFileReader struct {
|
type RepoGetRawFileReader struct {
|
||||||
formats strfmt.Registry
|
formats strfmt.Registry
|
||||||
|
writer io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadResponse reads a server response into the received o.
|
// ReadResponse reads a server response into the received o.
|
||||||
func (o *RepoGetRawFileReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
func (o *RepoGetRawFileReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||||
switch response.Code() {
|
switch response.Code() {
|
||||||
case 200:
|
case 200:
|
||||||
result := NewRepoGetRawFileOK()
|
result := NewRepoGetRawFileOK(o.writer)
|
||||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -38,8 +40,11 @@ func (o *RepoGetRawFileReader) ReadResponse(response runtime.ClientResponse, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewRepoGetRawFileOK creates a RepoGetRawFileOK with default headers values
|
// NewRepoGetRawFileOK creates a RepoGetRawFileOK with default headers values
|
||||||
func NewRepoGetRawFileOK() *RepoGetRawFileOK {
|
func NewRepoGetRawFileOK(writer io.Writer) *RepoGetRawFileOK {
|
||||||
return &RepoGetRawFileOK{}
|
return &RepoGetRawFileOK{
|
||||||
|
|
||||||
|
Payload: writer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -48,6 +53,7 @@ RepoGetRawFileOK describes a response with status code 200, with default header
|
|||||||
Returns raw file content.
|
Returns raw file content.
|
||||||
*/
|
*/
|
||||||
type RepoGetRawFileOK struct {
|
type RepoGetRawFileOK struct {
|
||||||
|
Payload io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSuccess returns true when this repo get raw file o k response has a 2xx status code
|
// IsSuccess returns true when this repo get raw file o k response has a 2xx status code
|
||||||
@ -88,8 +94,17 @@ func (o *RepoGetRawFileOK) String() string {
|
|||||||
return fmt.Sprintf("[GET /repos/{owner}/{repo}/raw/{filepath}][%d] repoGetRawFileOK", 200)
|
return fmt.Sprintf("[GET /repos/{owner}/{repo}/raw/{filepath}][%d] repoGetRawFileOK", 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *RepoGetRawFileOK) GetPayload() io.Writer {
|
||||||
|
return o.Payload
|
||||||
|
}
|
||||||
|
|
||||||
func (o *RepoGetRawFileOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
func (o *RepoGetRawFileOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
// response payload
|
||||||
|
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime"
|
"github.com/go-openapi/runtime"
|
||||||
httptransport "github.com/go-openapi/runtime/client"
|
httptransport "github.com/go-openapi/runtime/client"
|
||||||
@ -103,6 +104,11 @@ func WithAcceptApplicationJSON(r *runtime.ClientOperation) {
|
|||||||
r.ProducesMediaTypes = []string{"application/json"}
|
r.ProducesMediaTypes = []string{"application/json"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAcceptApplicationOctetStream sets the Accept header to "application/octet-stream".
|
||||||
|
func WithAcceptApplicationOctetStream(r *runtime.ClientOperation) {
|
||||||
|
r.ProducesMediaTypes = []string{"application/octet-stream"}
|
||||||
|
}
|
||||||
|
|
||||||
// WithAcceptTextHTML sets the Accept header to "text/html".
|
// WithAcceptTextHTML sets the Accept header to "text/html".
|
||||||
func WithAcceptTextHTML(r *runtime.ClientOperation) {
|
func WithAcceptTextHTML(r *runtime.ClientOperation) {
|
||||||
r.ProducesMediaTypes = []string{"text/html"}
|
r.ProducesMediaTypes = []string{"text/html"}
|
||||||
@ -303,9 +309,9 @@ type ClientService interface {
|
|||||||
|
|
||||||
RepoGetPushMirrorByRemoteName(params *RepoGetPushMirrorByRemoteNameParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetPushMirrorByRemoteNameOK, error)
|
RepoGetPushMirrorByRemoteName(params *RepoGetPushMirrorByRemoteNameParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetPushMirrorByRemoteNameOK, error)
|
||||||
|
|
||||||
RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetRawFileOK, error)
|
RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.ClientAuthInfoWriter, writer io.Writer, opts ...ClientOption) (*RepoGetRawFileOK, error)
|
||||||
|
|
||||||
RepoGetRawFileOrLFS(params *RepoGetRawFileOrLFSParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetRawFileOrLFSOK, error)
|
RepoGetRawFileOrLFS(params *RepoGetRawFileOrLFSParams, authInfo runtime.ClientAuthInfoWriter, writer io.Writer, opts ...ClientOption) (*RepoGetRawFileOrLFSOK, error)
|
||||||
|
|
||||||
RepoGetRelease(params *RepoGetReleaseParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetReleaseOK, error)
|
RepoGetRelease(params *RepoGetReleaseParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetReleaseOK, error)
|
||||||
|
|
||||||
@ -4103,7 +4109,7 @@ func (a *Client) RepoGetPushMirrorByRemoteName(params *RepoGetPushMirrorByRemote
|
|||||||
/*
|
/*
|
||||||
RepoGetRawFile gets a file from a repository
|
RepoGetRawFile gets a file from a repository
|
||||||
*/
|
*/
|
||||||
func (a *Client) RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetRawFileOK, error) {
|
func (a *Client) RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.ClientAuthInfoWriter, writer io.Writer, opts ...ClientOption) (*RepoGetRawFileOK, error) {
|
||||||
// TODO: Validate the params before sending
|
// TODO: Validate the params before sending
|
||||||
if params == nil {
|
if params == nil {
|
||||||
params = NewRepoGetRawFileParams()
|
params = NewRepoGetRawFileParams()
|
||||||
@ -4112,11 +4118,11 @@ func (a *Client) RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.C
|
|||||||
ID: "repoGetRawFile",
|
ID: "repoGetRawFile",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
PathPattern: "/repos/{owner}/{repo}/raw/{filepath}",
|
PathPattern: "/repos/{owner}/{repo}/raw/{filepath}",
|
||||||
ProducesMediaTypes: []string{"application/json"},
|
ProducesMediaTypes: []string{"application/octet-stream"},
|
||||||
ConsumesMediaTypes: []string{"application/json", "text/plain"},
|
ConsumesMediaTypes: []string{"application/octet-stream"},
|
||||||
Schemes: []string{"http", "https"},
|
Schemes: []string{"http", "https"},
|
||||||
Params: params,
|
Params: params,
|
||||||
Reader: &RepoGetRawFileReader{formats: a.formats},
|
Reader: &RepoGetRawFileReader{formats: a.formats, writer: writer},
|
||||||
AuthInfo: authInfo,
|
AuthInfo: authInfo,
|
||||||
Context: params.Context,
|
Context: params.Context,
|
||||||
Client: params.HTTPClient,
|
Client: params.HTTPClient,
|
||||||
@ -4142,7 +4148,7 @@ func (a *Client) RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.C
|
|||||||
/*
|
/*
|
||||||
RepoGetRawFileOrLFS gets a file or it s l f s object from a repository
|
RepoGetRawFileOrLFS gets a file or it s l f s object from a repository
|
||||||
*/
|
*/
|
||||||
func (a *Client) RepoGetRawFileOrLFS(params *RepoGetRawFileOrLFSParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetRawFileOrLFSOK, error) {
|
func (a *Client) RepoGetRawFileOrLFS(params *RepoGetRawFileOrLFSParams, authInfo runtime.ClientAuthInfoWriter, writer io.Writer, opts ...ClientOption) (*RepoGetRawFileOrLFSOK, error) {
|
||||||
// TODO: Validate the params before sending
|
// TODO: Validate the params before sending
|
||||||
if params == nil {
|
if params == nil {
|
||||||
params = NewRepoGetRawFileOrLFSParams()
|
params = NewRepoGetRawFileOrLFSParams()
|
||||||
@ -4151,11 +4157,11 @@ func (a *Client) RepoGetRawFileOrLFS(params *RepoGetRawFileOrLFSParams, authInfo
|
|||||||
ID: "repoGetRawFileOrLFS",
|
ID: "repoGetRawFileOrLFS",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
PathPattern: "/repos/{owner}/{repo}/media/{filepath}",
|
PathPattern: "/repos/{owner}/{repo}/media/{filepath}",
|
||||||
ProducesMediaTypes: []string{"application/json", "text/html"},
|
ProducesMediaTypes: []string{"application/octet-stream"},
|
||||||
ConsumesMediaTypes: []string{"application/json", "text/plain"},
|
ConsumesMediaTypes: []string{"application/json", "text/plain"},
|
||||||
Schemes: []string{"http", "https"},
|
Schemes: []string{"http", "https"},
|
||||||
Params: params,
|
Params: params,
|
||||||
Reader: &RepoGetRawFileOrLFSReader{formats: a.formats},
|
Reader: &RepoGetRawFileOrLFSReader{formats: a.formats, writer: writer},
|
||||||
AuthInfo: authInfo,
|
AuthInfo: authInfo,
|
||||||
Context: params.Context,
|
Context: params.Context,
|
||||||
Client: params.HTTPClient,
|
Client: params.HTTPClient,
|
||||||
|
@ -23,7 +23,7 @@ const PrPattern = "PR: %s/%s#%d"
|
|||||||
func (h *RequestHandler) allocateGiteaTransport() (*transport.Runtime, *apiclient.GiteaAPI) {
|
func (h *RequestHandler) allocateGiteaTransport() (*transport.Runtime, *apiclient.GiteaAPI) {
|
||||||
r := transport.New("src.opensuse.org", apiclient.DefaultBasePath, [](string){"https"})
|
r := transport.New("src.opensuse.org", apiclient.DefaultBasePath, [](string){"https"})
|
||||||
r.DefaultAuthentication = transport.BearerToken(giteaToken)
|
r.DefaultAuthentication = transport.BearerToken(giteaToken)
|
||||||
r.SetDebug(true)
|
// r.SetDebug(true)
|
||||||
|
|
||||||
return r, apiclient.New(r, nil)
|
return r, apiclient.New(r, nil)
|
||||||
}
|
}
|
||||||
@ -287,6 +287,56 @@ func (h *RequestHandler) RequestReviews(pr *models.PullRequest, reviewer string)
|
|||||||
return review.GetPayload()
|
return review.GetPayload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *RequestHandler) AddReviewComment(pr *models.PullRequest, state models.ReviewStateType, comment string) (*models.PullReview, error) {
|
||||||
|
transport, client := h.allocateGiteaTransport()
|
||||||
|
|
||||||
|
h.Log("%#v", *pr)
|
||||||
|
c, err := client.Repository.RepoCreatePullReview(
|
||||||
|
repository.NewRepoCreatePullReviewParams().
|
||||||
|
WithDefaults().
|
||||||
|
WithOwner(pr.Base.Repo.Owner.UserName).
|
||||||
|
WithRepo(pr.Base.Repo.Name).
|
||||||
|
WithIndex(pr.Index).
|
||||||
|
WithBody(&models.CreatePullReviewOptions{
|
||||||
|
Event: state,
|
||||||
|
Body: comment,
|
||||||
|
}),
|
||||||
|
transport.DefaultAuthentication,
|
||||||
|
)
|
||||||
|
/*
|
||||||
|
c, err := client.Repository.RepoSubmitPullReview(
|
||||||
|
repository.NewRepoSubmitPullReviewParams().
|
||||||
|
WithDefaults().
|
||||||
|
WithOwner(pr.Base.Repo.Owner.UserName).
|
||||||
|
WithRepo(pr.Base.Repo.Name).
|
||||||
|
WithIndex(pr.Index).
|
||||||
|
WithID(review.ID).
|
||||||
|
WithBody(&models.SubmitPullReviewOptions{
|
||||||
|
Event: state,
|
||||||
|
Body: comment,
|
||||||
|
}),
|
||||||
|
transport.DefaultAuthentication,
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* c, err := client.Issue.IssueCreateComment(
|
||||||
|
issue.NewIssueCreateCommentParams().
|
||||||
|
WithDefaults().
|
||||||
|
WithOwner(pr.Base.Repo.Owner.UserName).
|
||||||
|
WithRepo(pr.Base.Repo.Name).
|
||||||
|
WithIndex(pr.Index).
|
||||||
|
WithBody(&models.CreateIssueCommentOption{
|
||||||
|
Body: &comment,
|
||||||
|
}),
|
||||||
|
transport.DefaultAuthentication)
|
||||||
|
*/
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (h *RequestHandler) GetAssociatedPrjGitPR(pr *PullRequestAction) *models.PullRequest {
|
func (h *RequestHandler) GetAssociatedPrjGitPR(pr *PullRequestAction) *models.PullRequest {
|
||||||
if h.HasError() {
|
if h.HasError() {
|
||||||
return nil
|
return nil
|
||||||
@ -335,20 +385,30 @@ func (h *RequestHandler) GetAssociatedPrjGitPR(pr *PullRequestAction) *models.Pu
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RequestHandler) GetRepositoryFileContent(pr *models.PullRequest, path string) ([]byte, error) {
|
func (h *RequestHandler) GetRepositoryFileContent(repo *models.Repository, hash, path string) ([]byte, error) {
|
||||||
if h.HasError() {
|
if h.HasError() {
|
||||||
return nil, h.Error
|
return nil, h.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
transport, client := h.allocateGiteaTransport()
|
transport, client := h.allocateGiteaTransport()
|
||||||
repo := pr.Head.Repo
|
var retData []byte
|
||||||
|
|
||||||
|
dataOut := writeFunc(func(data []byte) (int, error) {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
retData = data
|
||||||
|
return len(data), nil
|
||||||
|
})
|
||||||
file, err := client.Repository.RepoGetRawFile(
|
file, err := client.Repository.RepoGetRawFile(
|
||||||
repository.NewRepoGetRawFileParams().
|
repository.NewRepoGetRawFileParams().
|
||||||
WithOwner(repo.Owner.UserName).
|
WithOwner(repo.Owner.UserName).
|
||||||
WithRepo(repo.Name).
|
WithRepo(repo.Name).
|
||||||
WithFilepath(path).
|
WithFilepath(path).
|
||||||
WithRef(&pr.Head.Ref),
|
WithRef(&hash),
|
||||||
transport.DefaultAuthentication,
|
transport.DefaultAuthentication,
|
||||||
|
dataOut,
|
||||||
|
repository.WithContentTypeApplicationOctetStream,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -359,6 +419,9 @@ func (h *RequestHandler) GetRepositoryFileContent(pr *models.PullRequest, path s
|
|||||||
return nil, fmt.Errorf("Invalid response from server (%d): %s", file.Code(), file.Error())
|
return nil, fmt.Errorf("Invalid response from server (%d): %s", file.Code(), file.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return file.Body(), nil
|
return retData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *RequestHandler) GetPullRequestFileContent(pr *models.PullRequest, path string) ([]byte, error) {
|
||||||
|
return h.GetRepositoryFileContent(pr.Head.Repo, pr.Head.Sha, path)
|
||||||
|
}
|
||||||
|
@ -44,7 +44,7 @@ func prepareMsg(time time.Duration, id uint, str string, params ...any) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StdoutLogging) LogPlainError(err error) (int, error) {
|
func (s *StdoutLogging) LogPlainError(err error) (int, error) {
|
||||||
return s.Stderr.WriteString(prepareMsg(time.Since(s.Date), s.Id, "%#v\n", err))
|
return s.Stderr.WriteString(prepareMsg(time.Since(s.Date), s.Id, "%s\n", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StdoutLogging) LogError(str string, params ...any) (int, error) {
|
func (s *StdoutLogging) LogError(str string, params ...any) (int, error) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -34,14 +35,15 @@ func NewObsClient(host string) (*ObsClient, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type RepositoryMeta struct {
|
type RepositoryPathMeta struct {
|
||||||
Name string `xml:"name,attr"`
|
|
||||||
Arch []string `xml:"arch"`
|
|
||||||
Path []struct {
|
|
||||||
XMLName xml.Name `xml:"path"`
|
|
||||||
Project string `xml:"project,attr"`
|
Project string `xml:"project,attr"`
|
||||||
Repository string `xml:"repository,attr"`
|
Repository string `xml:"repository,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RepositoryMeta struct {
|
||||||
|
Name string `xml:"name,attr"`
|
||||||
|
Archs []string `xml:"arch"`
|
||||||
|
Paths []RepositoryPathMeta `xml:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Flags struct {
|
type Flags struct {
|
||||||
@ -53,11 +55,13 @@ type ProjectMeta struct {
|
|||||||
Name string `xml:"name,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Title string `xml:"title"`
|
Title string `xml:"title"`
|
||||||
Description string `xml:"description"`
|
Description string `xml:"description"`
|
||||||
ScmSync string `xml:"xmlsync"`
|
ScmSync string `xml:"scmsync"`
|
||||||
Repositories []Repository `xml:"repository"`
|
Repositories []RepositoryMeta `xml:"repository"`
|
||||||
|
|
||||||
BuildFlags Flags `xml:"build"`
|
BuildFlags Flags `xml:"build"`
|
||||||
PublicFlags Flags `xml:"publish"`
|
PublicFlags Flags `xml:"publish"`
|
||||||
|
DebugFlags Flags `xml:"debuginfo"`
|
||||||
|
UseForBuild Flags `xml:"useforbuild"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseProjectMeta(data []byte) (*ProjectMeta, error) {
|
func parseProjectMeta(data []byte) (*ProjectMeta, error) {
|
||||||
@ -77,6 +81,8 @@ func (c *ObsClient) GetProjectMeta(project string) (*ProjectMeta, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.SetBasicAuth(c.user, c.password)
|
req.SetBasicAuth(c.user, c.password)
|
||||||
|
log.Printf("request: %#v", *req.URL)
|
||||||
|
log.Printf("headers: %#v", req.Header)
|
||||||
res, err := c.client.Do(req)
|
res, err := c.client.Do(req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -100,6 +106,57 @@ func (c *ObsClient) GetProjectMeta(project string) (*ProjectMeta, error) {
|
|||||||
return parseProjectMeta(data)
|
return parseProjectMeta(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ObsSafeProjectName(prjname string) string {
|
||||||
|
if len(prjname) < 1 {
|
||||||
|
return prjname
|
||||||
|
} else if len(prjname) > 200 {
|
||||||
|
prjname = prjname[:199]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch prjname[0] {
|
||||||
|
case '_', '.', ':':
|
||||||
|
prjname = "X" + prjname[1:]
|
||||||
|
// no UTF-8 in OBS :(
|
||||||
|
// prjname = "_" + prjname[1:]
|
||||||
|
// case ':':
|
||||||
|
// prjname = ":" + prjname[1:]
|
||||||
|
// case '.':
|
||||||
|
// prjname = "․" + prjname[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return prjname
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ObsClient) SetProjectMeta(meta *ProjectMeta) (error) {
|
||||||
|
|
||||||
|
req, err := http.NewRequest("PUT", c.baseUrl.JoinPath("source", meta.Name, "_meta").String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.SetBasicAuth(c.user, c.password)
|
||||||
|
xml, err := xml.Marshal(meta)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Body = io.NopCloser(bytes.NewReader(xml))
|
||||||
|
log.Printf("headers: %#v", req.Header)
|
||||||
|
log.Printf("xml: %s", xml)
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch res.StatusCode {
|
||||||
|
case 200:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Unexpected return code: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ObsClient) DeleteProject(project string) error {
|
func (c *ObsClient) DeleteProject(project string) error {
|
||||||
req, err := http.NewRequest("DELETE", c.baseUrl.JoinPath("source", project).String(), nil)
|
req, err := http.NewRequest("DELETE", c.baseUrl.JoinPath("source", project).String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,8 +24,8 @@ func RequireGiteaSecretToken() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RequireObsSecretToken() error {
|
func RequireObsSecretToken() error {
|
||||||
obsPassword = os.Getenv(ObsUserEnv)
|
obsUser = os.Getenv(ObsUserEnv)
|
||||||
obsUser = os.Getenv(ObsPasswordEnv)
|
obsPassword = os.Getenv(ObsPasswordEnv)
|
||||||
|
|
||||||
if len(obsPassword) < 10 || len(obsUser) < 2 {
|
if len(obsPassword) < 10 || len(obsUser) < 2 {
|
||||||
return fmt.Errorf("Missing OBS authentication: %s %s", ObsUserEnv, ObsPasswordEnv)
|
return fmt.Errorf("Missing OBS authentication: %s %s", ObsUserEnv, ObsPasswordEnv)
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"src.opensuse.org/autogits/common"
|
"src.opensuse.org/autogits/common"
|
||||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||||
@ -12,6 +15,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
GitAuthor = "GiteaBot - Obs Staging"
|
GitAuthor = "GiteaBot - Obs Staging"
|
||||||
|
BotName = "ObsStaging"
|
||||||
ObsBuildBot = "/obsbuild"
|
ObsBuildBot = "/obsbuild"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,14 +28,20 @@ func failOnError(err error, msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func allocateRequestHandler() *common.RequestHandler {
|
func fetchPrGit(h *common.RequestHandler, pr *models.PullRequest) error {
|
||||||
return &common.RequestHandler{
|
// clone PR head and base and return path
|
||||||
Logger: common.CreateStdoutLogger(os.Stdout, os.Stdout),
|
if _, err := os.Stat(path.Join(h.GitPath, pr.Head.Sha)); os.IsNotExist(err) {
|
||||||
|
h.GitExec("", "clone", "--depth", "1", pr.Head.Repo.CloneURL, pr.Head.Sha)
|
||||||
|
h.GitExec(pr.Head.Sha, "fetch", "--depth", "1", "origin", pr.Head.Sha, pr.Base.Sha)
|
||||||
|
} else if err != nil {
|
||||||
|
h.Error = err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return h.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func processPullNotification(h *common.RequestHandler, notification *models.NotificationSubject) {
|
func processPullNotification(h *common.RequestHandler, notification *models.NotificationSubject) {
|
||||||
rx := regexp.MustCompile(`^https://src\.(?:open)?suse\.org/api/v\d+/repos/(?<org>[a-zA-Z0-9]+)/(?<project>[_a-zA-Z0-9]+)/issues/(?<num>[0-9]+)$`)
|
rx := regexp.MustCompile(`^https://src\.(?:open)?suse\.(?:org|de)/api/v\d+/repos/(?<org>[a-zA-Z0-9]+)/(?<project>[_a-zA-Z0-9]+)/issues/(?<num>[0-9]+)$`)
|
||||||
match := rx.FindStringSubmatch(notification.URL)
|
match := rx.FindStringSubmatch(notification.URL)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
log.Panicf("Unexpected format of notification: %s", notification.URL)
|
log.Panicf("Unexpected format of notification: %s", notification.URL)
|
||||||
@ -64,26 +74,89 @@ func processPullNotification(h *common.RequestHandler, notification *models.Noti
|
|||||||
for _, review := range reviews {
|
for _, review := range reviews {
|
||||||
h.Log("state: %s, body: %s, id:%d\n", string(review.State), review.Body, review.ID)
|
h.Log("state: %s, body: %s, id:%d\n", string(review.State), review.Body, review.ID)
|
||||||
|
|
||||||
if *review.User.LoginName != "autogits_obs_staging_bot" {
|
if review.User.UserName != "autogits_obs_staging_bot" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch review.State {
|
err := fetchPrGit(h, pr)
|
||||||
case common.ReviewStateUnknown, common.ReviewStateRequestReview:
|
if err != nil {
|
||||||
|
h.LogError("Cannot fetch PR git: %s", pr.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dir := pr.Head.Sha
|
||||||
|
headSubmodules := h.GitSubmoduleList(dir, pr.Head.Sha)
|
||||||
|
baseSubmodules := h.GitSubmoduleList(dir, pr.Base.Sha)
|
||||||
|
|
||||||
|
// find modified submodules and new submodules -- build them
|
||||||
|
|
||||||
|
h.Log("processing state...")
|
||||||
|
|
||||||
|
switch review.State {
|
||||||
// create build project, if doesn't exist, and add it to pending requests
|
// create build project, if doesn't exist, and add it to pending requests
|
||||||
|
case common.ReviewStateUnknown, common.ReviewStateRequestReview:
|
||||||
|
h.Log("repo content fetching ...")
|
||||||
|
buildPrjBytes, err := h.GetPullRequestFileContent(pr, "project.build")
|
||||||
|
if err != nil {
|
||||||
|
h.LogPlainError(err)
|
||||||
|
_, err := h.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find reference project")
|
||||||
|
if err != nil {
|
||||||
|
h.LogPlainError(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buildPrj := strings.TrimSpace(string(buildPrjBytes))
|
||||||
|
meta, err := obsClient.GetProjectMeta(string(buildPrj))
|
||||||
|
if err != nil {
|
||||||
|
h.Log("error fetching project meta for %s: %v", buildPrj, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate new project with paths pointinig back to original repos
|
||||||
|
// disable publishing
|
||||||
|
|
||||||
|
// TODO: escape things here
|
||||||
|
meta.Name = fmt.Sprintf("%s:%s:%s:PR:%d",
|
||||||
|
obsClient.HomeProject,
|
||||||
|
common.ObsSafeProjectName(pr.Base.Repo.Owner.UserName),
|
||||||
|
common.ObsSafeProjectName(pr.Base.Repo.Name),
|
||||||
|
pr.Index,
|
||||||
|
)
|
||||||
|
meta.Description = fmt.Sprintf(`Pull request build job: %s%s PR#%d`,
|
||||||
|
"https://src.opensuse.org", pr.Base.Repo.Name, pr.Index)
|
||||||
|
// meta.ScmSync = pr.Head.Repo.CloneURL + "?" +
|
||||||
|
meta.Title = fmt.Sprintf("PR#%d to %s", pr.Index, pr.Base.Name)
|
||||||
|
meta.PublicFlags = common.Flags{Contents: "<disable/>"}
|
||||||
|
|
||||||
|
// set paths to parent project
|
||||||
|
for idx, r := range meta.Repositories {
|
||||||
|
meta.Repositories[idx].Paths = []common.RepositoryPathMeta{{
|
||||||
|
Project: buildPrj,
|
||||||
|
Repository: r.Name,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Log("%#v", meta)
|
||||||
|
return
|
||||||
|
|
||||||
|
err = obsClient.SetProjectMeta(meta)
|
||||||
|
if err != nil {
|
||||||
|
h.LogError("cannot create meta project: %#v", err)
|
||||||
|
}
|
||||||
case common.ReviewStatePending:
|
case common.ReviewStatePending:
|
||||||
// waiting for build results
|
// waiting for build results
|
||||||
case common.ReviewStateApproved:
|
case common.ReviewStateApproved:
|
||||||
// done, mark notification as read
|
// done, mark notification as read
|
||||||
case common.ReviewStateRequestChanges:
|
case common.ReviewStateRequestChanges:
|
||||||
// build failures, mark notification as read
|
h.Log("processing request for failed request changes...")
|
||||||
|
// build failures, nothing to do here, mark notification as read
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pollWorkNotifications() {
|
func pollWorkNotifications() {
|
||||||
h := allocateRequestHandler()
|
h := common.CreateRequestHandler(GitAuthor, BotName)
|
||||||
data, err := h.GetNotifications(nil)
|
data, err := h.GetNotifications(nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,7 +190,25 @@ func main() {
|
|||||||
|
|
||||||
pollWorkNotifications()
|
pollWorkNotifications()
|
||||||
|
|
||||||
|
/*
|
||||||
|
h := allocateRequestHandler()
|
||||||
|
//" autogits/_ObsPrj/raw/project.build?ref=9680b770855e4fc2e9d9cebbd87e6a0d119693c3e03db187494e3aeff727312f"
|
||||||
|
// https://src.opensuse.org/adamm/autogits/commit/8db4d8c3021fc21baa606b87eaad0e476bb7f624f76cb37b6a1819bdb5f04b43#diff-6e698c75c21cd4458440e8a71408c6301ba3a562
|
||||||
|
f, err := h.GetRepositoryFileContent(
|
||||||
|
&models.Repository{
|
||||||
|
Owner: &models.User{
|
||||||
|
UserName: "adamm",
|
||||||
|
},
|
||||||
|
Name: "autogits",
|
||||||
|
},
|
||||||
|
"54e418acaf960c5ed8be7f4a29616ae7b5eb75f797f7ed4d487f79485d056108",
|
||||||
|
"bots-common/obs/client.go")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.LogPlainError(err)
|
||||||
|
}
|
||||||
|
h.Log("len: %d", len(f))
|
||||||
|
*/
|
||||||
stuck := make(chan int)
|
stuck := make(chan int)
|
||||||
<-stuck
|
<-stuck
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user