├── vendor ├── github.com │ ├── wk8 │ │ └── go-ordered-map │ │ │ └── v2 │ │ │ ├── .gitignore │ │ │ ├── Makefile │ │ │ ├── CHANGELOG.md │ │ │ ├── .golangci.yml │ │ │ └── yaml.go │ ├── invopop │ │ └── jsonschema │ │ │ ├── .gitignore │ │ │ ├── utils.go │ │ │ ├── COPYING │ │ │ ├── .golangci.yml │ │ │ └── id.go │ ├── BurntSushi │ │ └── toml │ │ │ ├── .gitignore │ │ │ ├── doc.go │ │ │ ├── deprecated.go │ │ │ ├── COPYING │ │ │ ├── internal │ │ │ └── tz.go │ │ │ └── type_toml.go │ ├── buger │ │ └── jsonparser │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── Dockerfile │ │ │ ├── bytes_safe.go │ │ │ ├── bytes.go │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── bytes_unsafe.go │ │ │ └── oss-fuzz-build.sh │ ├── google │ │ └── uuid │ │ │ ├── CONTRIBUTORS │ │ │ ├── doc.go │ │ │ ├── node_js.go │ │ │ ├── README.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── marshal.go │ │ │ ├── node_net.go │ │ │ ├── version1.go │ │ │ ├── LICENSE │ │ │ ├── sql.go │ │ │ ├── CHANGELOG.md │ │ │ ├── util.go │ │ │ └── hash.go │ ├── mark3labs │ │ └── mcp-go │ │ │ ├── server │ │ │ ├── ctx.go │ │ │ ├── constants.go │ │ │ ├── http_transport_options.go │ │ │ ├── roots.go │ │ │ ├── elicitation.go │ │ │ └── errors.go │ │ │ ├── mcp │ │ │ ├── consts.go │ │ │ └── typed_tools.go │ │ │ ├── util │ │ │ └── logger.go │ │ │ └── LICENSE │ ├── stretchr │ │ └── testify │ │ │ ├── assert │ │ │ ├── assertion_format.go.tmpl │ │ │ ├── assertion_forward.go.tmpl │ │ │ ├── errors.go │ │ │ ├── forward_assertions.go │ │ │ ├── yaml │ │ │ │ ├── yaml_fail.go │ │ │ │ ├── yaml_custom.go │ │ │ │ └── yaml_default.go │ │ │ └── doc.go │ │ │ └── LICENSE │ ├── spf13 │ │ └── cast │ │ │ ├── .editorconfig │ │ │ ├── .gitignore │ │ │ ├── .golangci.yaml │ │ │ ├── indirect.go │ │ │ ├── internal │ │ │ └── timeformattype_string.go │ │ │ ├── LICENSE │ │ │ └── Makefile │ ├── bahlo │ │ └── generic-list-go │ │ │ ├── README.md │ │ │ └── LICENSE │ ├── jinzhu │ │ └── configor │ │ │ ├── admin.yml │ │ │ └── LICENSE │ ├── yosida95 │ │ └── uritemplate │ │ │ └── v3 │ │ │ ├── error.go │ │ │ ├── machine.go │ │ │ ├── README.rst │ │ │ ├── equals.go │ │ │ └── LICENSE │ ├── davecgh │ │ └── go-spew │ │ │ ├── LICENSE │ │ │ └── spew │ │ │ └── bypasssafe.go │ ├── mailru │ │ └── easyjson │ │ │ └── LICENSE │ └── pmezard │ │ └── go-difflib │ │ └── LICENSE ├── go.uber.org │ ├── multierr │ │ ├── .gitignore │ │ ├── .codecov.yml │ │ ├── Makefile │ │ ├── LICENSE.txt │ │ ├── README.md │ │ └── error_post_go120.go │ └── zap │ │ ├── checklicense.sh │ │ ├── .gitignore │ │ ├── .codecov.yml │ │ ├── glide.yaml │ │ ├── LICENSE │ │ ├── time.go │ │ ├── zapcore │ │ ├── doc.go │ │ ├── reflected_encoder.go │ │ ├── level_strings.go │ │ ├── lazy_with.go │ │ └── clock.go │ │ ├── internal │ │ ├── bufferpool │ │ │ └── bufferpool.go │ │ ├── color │ │ │ └── color.go │ │ ├── level_enabler.go │ │ └── pool │ │ │ └── pool.go │ │ ├── flag.go │ │ ├── buffer │ │ └── pool.go │ │ └── Makefile ├── gopkg.in │ └── yaml.v3 │ │ ├── NOTICE │ │ ├── writerc.go │ │ └── LICENSE └── modules.txt ├── .golangci.yml ├── internal ├── bitrise │ ├── tool.go │ ├── context.go │ └── call_api.go └── tool │ ├── user │ └── me.go │ ├── workspaces │ ├── list.go │ ├── get.go │ ├── get_workspace_groups.go │ ├── get_workspace_members.go │ ├── add_member_to_group.go │ ├── create_workspace_group.go │ └── invite_member_to_workspace.go │ ├── apps │ ├── get.go │ ├── list_branches.go │ ├── register_webhook.go │ ├── delete.go │ ├── get_bitrise_yml.go │ ├── list.go │ ├── update_bitrise_yml.go │ ├── update.go │ └── register_ssh_key.go │ ├── pipelines │ ├── list.go │ ├── get.go │ ├── rebuild.go │ └── abort.go │ ├── builds │ ├── list_build_workflows.go │ ├── get.go │ ├── get_steps.go │ ├── get_build_bitrise_yml.go │ ├── abort.go │ └── get_build_log_test.go │ ├── cache │ ├── list_items.go │ ├── delete_all_items.go │ ├── delete_item.go │ └── get_item_download_url.go │ ├── webhooks │ ├── list_outgoing.go │ ├── delete_outgoing.go │ ├── create_outgoing.go │ └── update_outgoing.go │ ├── releasemanagement │ ├── get_connected_app.go │ ├── get_tester_group.go │ ├── get_installable_artifact_upload_and_proc_status.go │ ├── notify_tester_group.go │ ├── add_testers_to_tester_group.go │ ├── list_tester_groups.go │ ├── update_tester_group.go │ └── set_installable_artifact_public_install_page.go │ ├── grouproles │ ├── list.go │ └── replace.go │ └── artifacts │ ├── delete.go │ ├── get.go │ ├── list.go │ └── update.go ├── gemini-extension.json ├── Dockerfile ├── Makefile ├── go.mod ├── LICENSE ├── README.md ├── .devcontainer └── devcontainer.json └── docs └── install-vscode.md /vendor/github.com/wk8/go-ordered-map/v2/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /vendor/github.com/invopop/jsonschema/.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/.gitignore: -------------------------------------------------------------------------------- 1 | /toml.test 2 | /toml-test 3 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | cover.html 3 | cover.out 4 | /bin 5 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.test 3 | 4 | *.out 5 | 6 | *.mprof 7 | 8 | .idea 9 | 10 | vendor/github.com/buger/goterm/ 11 | prof.cpu 12 | prof.mem 13 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Paul Borman 2 | bmatsuo 3 | shawnps 4 | theory 5 | jboverfelt 6 | dsymonds 7 | cd1 8 | wallclockbuilder 9 | dansouza 10 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | linters: 4 | default: "standard" 5 | exclusions: 6 | rules: 7 | - source: "defer .*" 8 | linters: 9 | - errcheck 10 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/server/ctx.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | type contextKey int 4 | 5 | const ( 6 | // This const is used as key for context value lookup 7 | requestHeader contextKey = iota 8 | ) 9 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | arch: 3 | - amd64 4 | - ppc64le 5 | go: 6 | - 1.7.x 7 | - 1.8.x 8 | - 1.9.x 9 | - 1.10.x 10 | - 1.11.x 11 | script: go test -v ./. 12 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/server/constants.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | // Common HTTP header constants used across server transports 4 | const ( 5 | HeaderKeySessionID = "Mcp-Session-Id" 6 | HeaderKeyProtocolVersion = "Mcp-Protocol-Version" 7 | ) 8 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/mcp/consts.go: -------------------------------------------------------------------------------- 1 | package mcp 2 | 3 | const ( 4 | ContentTypeText = "text" 5 | ContentTypeImage = "image" 6 | ContentTypeAudio = "audio" 7 | ContentTypeLink = "resource_link" 8 | ContentTypeResource = "resource" 9 | ) 10 | -------------------------------------------------------------------------------- /internal/bitrise/tool.go: -------------------------------------------------------------------------------- 1 | package bitrise 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/mark3labs/mcp-go/mcp" 7 | ) 8 | 9 | type Tool struct { 10 | APIGroups []string 11 | Definition mcp.Tool 12 | Handler func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.go] 12 | indent_style = tab 13 | 14 | [{*.yml,*.yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /vendor/github.com/bahlo/generic-list-go/README.md: -------------------------------------------------------------------------------- 1 | # generic-list-go [![CI](https://github.com/bahlo/generic-list-go/actions/workflows/ci.yml/badge.svg)](https://github.com/bahlo/generic-list-go/actions/workflows/ci.yml) 2 | 3 | Go [container/list](https://pkg.go.dev/container/list) but with generics. 4 | 5 | The code is based on `container/list` in `go1.18beta2`. 6 | -------------------------------------------------------------------------------- /gemini-extension.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitrise", 3 | "version": "1.0.0", 4 | "mcpServers": { 5 | "bitrise": { 6 | "description": "Connect AI assistants to Bitrise - manage apps, builds, artifacts, and more through natural language", 7 | "httpUrl": "https://mcp.bitrise.io", 8 | "headers": { 9 | "Authorization": "Bearer $BITRISE_PAT" 10 | } 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/doc.go: -------------------------------------------------------------------------------- 1 | // Package toml implements decoding and encoding of TOML files. 2 | // 3 | // This package supports TOML v1.0.0, as specified at https://toml.io 4 | // 5 | // The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator, 6 | // and can be used to verify if TOML document is valid. It can also be used to 7 | // print the type of each key. 8 | package toml 9 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/checklicense.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | ERROR_COUNT=0 4 | while read -r file 5 | do 6 | case "$(head -1 "${file}")" in 7 | *"Copyright (c) "*" Uber Technologies, Inc.") 8 | # everything's cool 9 | ;; 10 | *) 11 | echo "$file is missing license header." 12 | (( ERROR_COUNT++ )) 13 | ;; 14 | esac 15 | done < <(git ls-files "*\.go") 16 | 17 | exit $ERROR_COUNT 18 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | 25 | *.bench 26 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/server/http_transport_options.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | ) 7 | 8 | // HTTPContextFunc is a function that takes an existing context and the current 9 | // request and returns a potentially modified context based on the request 10 | // content. This can be used to inject context values from headers, for example. 11 | type HTTPContextFunc func(ctx context.Context, r *http.Request) context.Context 12 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.6 2 | 3 | RUN go get github.com/Jeffail/gabs 4 | RUN go get github.com/bitly/go-simplejson 5 | RUN go get github.com/pquerna/ffjson 6 | RUN go get github.com/antonholmquist/jason 7 | RUN go get github.com/mreiferson/go-ujson 8 | RUN go get -tags=unsafe -u github.com/ugorji/go/codec 9 | RUN go get github.com/mailru/easyjson 10 | 11 | WORKDIR /go/src/github.com/buger/jsonparser 12 | ADD . /go/src/github.com/buger/jsonparser -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package uuid generates and inspects UUIDs. 6 | // 7 | // UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security 8 | // Services. 9 | // 10 | // A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to 11 | // maps or compared directly. 12 | package uuid 13 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | vendor 10 | 11 | # Architecture specific extensions/prefixes 12 | *.[568vq] 13 | [568vq].out 14 | 15 | *.cgo1.go 16 | *.cgo2.c 17 | _cgo_defun.c 18 | _cgo_gotypes.go 19 | _cgo_export.* 20 | 21 | _testmain.go 22 | 23 | *.exe 24 | *.test 25 | *.prof 26 | *.pprof 27 | *.out 28 | *.log 29 | 30 | /bin 31 | cover.out 32 | cover.html 33 | -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/configor/admin.yml: -------------------------------------------------------------------------------- 1 | top: 2 | - name: Permission 3 | key: author_manage 4 | icon: 5 | children: 6 | - name: My Permission 7 | key: my_author 8 | icon: 9 | children: 10 | - name: Apply 11 | key: author_apply 12 | icon: 13 | - name: My Applies 14 | key: author_apply_record 15 | icon: 16 | - name: My Permission 17 | key: my_author 18 | icon: 19 | -------------------------------------------------------------------------------- /vendor/github.com/yosida95/uritemplate/v3/error.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Kohei YOSHIDA. All rights reserved. 2 | // 3 | // This program is free software; you can redistribute it and/or 4 | // modify it under the terms of The BSD 3-Clause License 5 | // that can be found in the LICENSE file. 6 | 7 | package uritemplate 8 | 9 | import ( 10 | "fmt" 11 | ) 12 | 13 | func errorf(pos int, format string, a ...interface{}) error { 14 | msg := fmt.Sprintf(format, a...) 15 | return fmt.Errorf("uritemplate:%d:%s", pos, msg) 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/node_js.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build js 6 | 7 | package uuid 8 | 9 | // getHardwareInterface returns nil values for the JS version of the code. 10 | // This removes the "net" dependency, because it is not used in the browser. 11 | // Using the "net" library inflates the size of the transpiled JS code by 673k bytes. 12 | func getHardwareInterface(name string) (string, []byte) { return "", nil } 13 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/bytes_safe.go: -------------------------------------------------------------------------------- 1 | // +build appengine appenginevm 2 | 3 | package jsonparser 4 | 5 | import ( 6 | "strconv" 7 | ) 8 | 9 | // See fastbytes_unsafe.go for explanation on why *[]byte is used (signatures must be consistent with those in that file) 10 | 11 | func equalStr(b *[]byte, s string) bool { 12 | return string(*b) == s 13 | } 14 | 15 | func parseFloat(b *[]byte) (float64, error) { 16 | return strconv.ParseFloat(string(*b), 64) 17 | } 18 | 19 | func bytesToString(b *[]byte) string { 20 | return string(*b) 21 | } 22 | 23 | func StringToBytes(s string) []byte { 24 | return []byte(s) 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/yosida95/uritemplate/v3/machine.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Kohei YOSHIDA. All rights reserved. 2 | // 3 | // This program is free software; you can redistribute it and/or 4 | // modify it under the terms of The BSD 3-Clause License 5 | // that can be found in the LICENSE file. 6 | 7 | package uritemplate 8 | 9 | // threadList implements https://research.swtch.com/sparse. 10 | type threadList struct { 11 | dense []threadEntry 12 | sparse []uint32 13 | } 14 | 15 | type threadEntry struct { 16 | pc uint32 17 | t *thread 18 | } 19 | 20 | type thread struct { 21 | op *progOp 22 | cap map[string][]int 23 | } 24 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.25-bookworm AS builder 2 | 3 | # Optimise the generated binary for the AMD64 v3 micro‑architecture 4 | ENV GOAMD64=v3 5 | ARG VERSION=development 6 | 7 | WORKDIR /build 8 | 9 | COPY . . 10 | 11 | RUN mkdir -p /out 12 | 13 | RUN go build -v -mod=vendor -o /out/bitrise-mcp \ 14 | -ldflags="-X 'main.BuildVersion=${VERSION}'" \ 15 | . 16 | 17 | FROM debian:bookworm-slim 18 | 19 | RUN apt-get update && apt-get install -y \ 20 | ca-certificates curl git \ 21 | && rm -rf /var/lib/apt/lists/* 22 | 23 | COPY --from=builder /out/bitrise-mcp / 24 | 25 | ENV ADDR="0.0.0.0:8000" 26 | EXPOSE 8000 27 | 28 | CMD ["/bitrise-mcp"] 29 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go: -------------------------------------------------------------------------------- 1 | //go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default 2 | 3 | // Package yaml is an implementation of YAML functions that always fail. 4 | // 5 | // This implementation can be used at build time to replace the default implementation 6 | // to avoid linking with [gopkg.in/yaml.v3]: 7 | // 8 | // go test -tags testify_yaml_fail 9 | package yaml 10 | 11 | import "errors" 12 | 13 | var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)") 14 | 15 | func Unmarshal([]byte, interface{}) error { 16 | return errNotImplemented 17 | } 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PHONY: install-golangci-lint lint 2 | 3 | GOLANGCI_LINT_VERSION=v2.6.1 4 | 5 | # Install golangci-lint using the official installer script 6 | install-golangci-lint: 7 | @if ! command -v golangci-lint > /dev/null || [ "$$(golangci-lint --version 2>/dev/null | grep -oE 'version [0-9]+\.[0-9]+\.[0-9]+' | sed 's/version /v/')" != "${GOLANGCI_LINT_VERSION}" ]; then \ 8 | echo "Installing golangci-lint ${GOLANGCI_LINT_VERSION}..."; \ 9 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $$(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}; \ 10 | else \ 11 | echo "golangci-lint ${GOLANGCI_LINT_VERSION} is already installed"; \ 12 | fi 13 | 14 | lint: install-golangci-lint 15 | $$(go env GOPATH)/bin/golangci-lint run -v 16 | -------------------------------------------------------------------------------- /internal/tool/user/me.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 8 | "github.com/mark3labs/mcp-go/mcp" 9 | ) 10 | 11 | var Me = bitrise.Tool{ 12 | APIGroups: []string{"user", "read-only"}, 13 | Definition: mcp.NewTool("me", 14 | mcp.WithDescription("Get user info for the currently authenticated user account"), 15 | ), 16 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 17 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 18 | Method: http.MethodGet, 19 | BaseURL: bitrise.APIBaseURL, 20 | Path: "/me", 21 | }) 22 | if err != nil { 23 | return mcp.NewToolResultErrorFromErr("call api", err), nil 24 | } 25 | return mcp.NewToolResultText(res), nil 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/.golangci.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | run: 4 | timeout: 10m 5 | 6 | linters: 7 | enable: 8 | - errcheck 9 | - govet 10 | - ineffassign 11 | - misspell 12 | - nolintlint 13 | # - revive 14 | - unused 15 | 16 | disable: 17 | - staticcheck 18 | 19 | settings: 20 | misspell: 21 | locale: US 22 | nolintlint: 23 | allow-unused: false # report any unused nolint directives 24 | require-specific: false # don't require nolint directives to be specific about which linter is being skipped 25 | 26 | formatters: 27 | enable: 28 | - gci 29 | - gofmt 30 | # - gofumpt 31 | - goimports 32 | # - golines 33 | 34 | settings: 35 | gci: 36 | sections: 37 | - standard 38 | - default 39 | - localmodule 40 | -------------------------------------------------------------------------------- /vendor/github.com/wk8/go-ordered-map/v2/Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := all 2 | 3 | .PHONY: all 4 | all: test_with_fuzz lint 5 | 6 | # the TEST_FLAGS env var can be set to eg run only specific tests 7 | TEST_COMMAND = go test -v -count=1 -race -cover $(TEST_FLAGS) 8 | 9 | .PHONY: test 10 | test: 11 | $(TEST_COMMAND) 12 | 13 | .PHONY: bench 14 | bench: 15 | go test -bench=. 16 | 17 | FUZZ_TIME ?= 10s 18 | 19 | # see https://github.com/golang/go/issues/46312 20 | # and https://stackoverflow.com/a/72673487/4867444 21 | # if we end up having more fuzz tests 22 | .PHONY: test_with_fuzz 23 | test_with_fuzz: 24 | $(TEST_COMMAND) -fuzz=FuzzRoundTripJSON -fuzztime=$(FUZZ_TIME) 25 | $(TEST_COMMAND) -fuzz=FuzzRoundTripYAML -fuzztime=$(FUZZ_TIME) 26 | 27 | .PHONY: fuzz 28 | fuzz: test_with_fuzz 29 | 30 | .PHONY: lint 31 | lint: 32 | golangci-lint run 33 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | range: 80..100 3 | round: down 4 | precision: 2 5 | 6 | status: 7 | project: # measuring the overall project coverage 8 | default: # context, you can create multiple ones with custom titles 9 | enabled: yes # must be yes|true to enable this status 10 | target: 100 # specify the target coverage for each commit status 11 | # option: "auto" (must increase from parent commit or pull request base) 12 | # option: "X%" a static target percentage to hit 13 | if_not_found: success # if parent is not found report status as success, error, or failure 14 | if_ci_failed: error # if ci fails report status as success, error, or failure 15 | 16 | -------------------------------------------------------------------------------- /internal/tool/workspaces/list.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 8 | "github.com/mark3labs/mcp-go/mcp" 9 | ) 10 | 11 | var List = bitrise.Tool{ 12 | APIGroups: []string{"workspaces", "read-only"}, 13 | Definition: mcp.NewTool("list_workspaces", 14 | mcp.WithDescription("List the workspaces the user has access to"), 15 | ), 16 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 17 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 18 | Method: http.MethodGet, 19 | BaseURL: bitrise.APIBaseURL, 20 | Path: "/organizations", 21 | }) 22 | if err != nil { 23 | return mcp.NewToolResultErrorFromErr("call api", err), nil 24 | } 25 | return mcp.NewToolResultText(res), nil 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/util/logger.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | // Logger defines a minimal logging interface 8 | type Logger interface { 9 | Infof(format string, v ...any) 10 | Errorf(format string, v ...any) 11 | } 12 | 13 | // --- Standard Library Logger Wrapper --- 14 | 15 | // DefaultStdLogger implements Logger using the standard library's log.Logger. 16 | func DefaultLogger() Logger { 17 | return &stdLogger{ 18 | logger: log.Default(), 19 | } 20 | } 21 | 22 | // stdLogger wraps the standard library's log.Logger. 23 | type stdLogger struct { 24 | logger *log.Logger 25 | } 26 | 27 | func (l *stdLogger) Infof(format string, v ...any) { 28 | l.logger.Printf("INFO: "+format, v...) 29 | } 30 | 31 | func (l *stdLogger) Errorf(format string, v ...any) { 32 | l.logger.Printf("ERROR: "+format, v...) 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go: -------------------------------------------------------------------------------- 1 | //go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default 2 | 3 | // Package yaml is an implementation of YAML functions that calls a pluggable implementation. 4 | // 5 | // This implementation is selected with the testify_yaml_custom build tag. 6 | // 7 | // go test -tags testify_yaml_custom 8 | // 9 | // This implementation can be used at build time to replace the default implementation 10 | // to avoid linking with [gopkg.in/yaml.v3]. 11 | // 12 | // In your test package: 13 | // 14 | // import assertYaml "github.com/stretchr/testify/assert/yaml" 15 | // 16 | // func init() { 17 | // assertYaml.Unmarshal = func (in []byte, out interface{}) error { 18 | // // ... 19 | // return nil 20 | // } 21 | // } 22 | package yaml 23 | 24 | var Unmarshal func(in []byte, out interface{}) error 25 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | range: 80..100 3 | round: down 4 | precision: 2 5 | 6 | status: 7 | project: # measuring the overall project coverage 8 | default: # context, you can create multiple ones with custom titles 9 | enabled: yes # must be yes|true to enable this status 10 | target: 95% # specify the target coverage for each commit status 11 | # option: "auto" (must increase from parent commit or pull request base) 12 | # option: "X%" a static target percentage to hit 13 | if_not_found: success # if parent is not found report status as success, error, or failure 14 | if_ci_failed: error # if ci fails report status as success, error, or failure 15 | ignore: 16 | - internal/readme/readme.go 17 | 18 | -------------------------------------------------------------------------------- /vendor/github.com/invopop/jsonschema/utils.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | 7 | orderedmap "github.com/wk8/go-ordered-map/v2" 8 | ) 9 | 10 | var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") 11 | var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") 12 | 13 | // ToSnakeCase converts the provided string into snake case using dashes. 14 | // This is useful for Schema IDs and definitions to be coherent with 15 | // common JSON Schema examples. 16 | func ToSnakeCase(str string) string { 17 | snake := matchFirstCap.ReplaceAllString(str, "${1}-${2}") 18 | snake = matchAllCap.ReplaceAllString(snake, "${1}-${2}") 19 | return strings.ToLower(snake) 20 | } 21 | 22 | // NewProperties is a helper method to instantiate a new properties ordered 23 | // map. 24 | func NewProperties() *orderedmap.OrderedMap[string, *Schema] { 25 | return orderedmap.New[string, *Schema]() 26 | } 27 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bitrise-io/bitrise-mcp/v2 2 | 3 | go 1.25.0 4 | 5 | require ( 6 | github.com/jinzhu/configor v1.2.2 7 | github.com/mark3labs/mcp-go v0.43.0 8 | github.com/stretchr/testify v1.11.1 9 | go.uber.org/zap v1.27.0 10 | ) 11 | 12 | require ( 13 | github.com/BurntSushi/toml v1.5.0 // indirect 14 | github.com/bahlo/generic-list-go v0.2.0 // indirect 15 | github.com/buger/jsonparser v1.1.1 // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/google/uuid v1.6.0 // indirect 18 | github.com/invopop/jsonschema v0.13.0 // indirect 19 | github.com/mailru/easyjson v0.9.1 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | github.com/spf13/cast v1.10.0 // indirect 22 | github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect 23 | github.com/yosida95/uritemplate/v3 v3.0.2 // indirect 24 | go.uber.org/multierr v1.11.0 // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /internal/bitrise/context.go: -------------------------------------------------------------------------------- 1 | package bitrise 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | type ctxKey int 9 | 10 | const ( 11 | keyPAT ctxKey = iota 12 | keyEnabledGroups 13 | ) 14 | 15 | func patFromCtx(ctx context.Context) (string, error) { 16 | v := ctx.Value(keyPAT) 17 | u, ok := v.(string) 18 | if !ok { 19 | return "", fmt.Errorf("unexpected type %T", v) 20 | } 21 | return u, nil 22 | } 23 | 24 | func ContextWithPAT(ctx context.Context, s string) context.Context { 25 | return context.WithValue(ctx, keyPAT, s) 26 | } 27 | 28 | func EnabledGroupsFromCtx(ctx context.Context) ([]string, error) { 29 | v := ctx.Value(keyEnabledGroups) 30 | u, ok := v.([]string) 31 | if !ok { 32 | return nil, fmt.Errorf("unexpected type %T", v) 33 | } 34 | return u, nil 35 | } 36 | 37 | func ContextWithEnabledGroups(ctx context.Context, a []string) context.Context { 38 | return context.WithValue(ctx, keyEnabledGroups, a) 39 | } 40 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/glide.yaml: -------------------------------------------------------------------------------- 1 | package: go.uber.org/zap 2 | license: MIT 3 | import: 4 | - package: go.uber.org/atomic 5 | version: ^1 6 | - package: go.uber.org/multierr 7 | version: ^1 8 | testImport: 9 | - package: github.com/satori/go.uuid 10 | - package: github.com/sirupsen/logrus 11 | - package: github.com/apex/log 12 | subpackages: 13 | - handlers/json 14 | - package: github.com/go-kit/kit 15 | subpackages: 16 | - log 17 | - package: github.com/stretchr/testify 18 | subpackages: 19 | - assert 20 | - require 21 | - package: gopkg.in/inconshreveable/log15.v2 22 | - package: github.com/mattn/goveralls 23 | - package: github.com/pborman/uuid 24 | - package: github.com/pkg/errors 25 | - package: github.com/rs/zerolog 26 | - package: golang.org/x/tools 27 | subpackages: 28 | - cover 29 | - package: golang.org/x/lint 30 | subpackages: 31 | - golint 32 | - package: github.com/axw/gocov 33 | subpackages: 34 | - gocov 35 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/README.md: -------------------------------------------------------------------------------- 1 | # uuid 2 | The uuid package generates and inspects UUIDs based on 3 | [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) 4 | and DCE 1.1: Authentication and Security Services. 5 | 6 | This package is based on the github.com/pborman/uuid package (previously named 7 | code.google.com/p/go-uuid). It differs from these earlier packages in that 8 | a UUID is a 16 byte array rather than a byte slice. One loss due to this 9 | change is the ability to represent an invalid UUID (vs a NIL UUID). 10 | 11 | ###### Install 12 | ```sh 13 | go get github.com/google/uuid 14 | ``` 15 | 16 | ###### Documentation 17 | [![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) 18 | 19 | Full `go doc` style documentation for the package can be viewed online without 20 | installing this package by using the GoDoc site here: 21 | http://pkg.go.dev/github.com/google/uuid 22 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/deprecated.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "encoding" 5 | "io" 6 | ) 7 | 8 | // TextMarshaler is an alias for encoding.TextMarshaler. 9 | // 10 | // Deprecated: use encoding.TextMarshaler 11 | type TextMarshaler encoding.TextMarshaler 12 | 13 | // TextUnmarshaler is an alias for encoding.TextUnmarshaler. 14 | // 15 | // Deprecated: use encoding.TextUnmarshaler 16 | type TextUnmarshaler encoding.TextUnmarshaler 17 | 18 | // DecodeReader is an alias for NewDecoder(r).Decode(v). 19 | // 20 | // Deprecated: use NewDecoder(reader).Decode(&value). 21 | func DecodeReader(r io.Reader, v any) (MetaData, error) { return NewDecoder(r).Decode(v) } 22 | 23 | // PrimitiveDecode is an alias for MetaData.PrimitiveDecode(). 24 | // 25 | // Deprecated: use MetaData.PrimitiveDecode. 26 | func PrimitiveDecode(primValue Primitive, v any) error { 27 | md := MetaData{decoded: make(map[string]struct{})} 28 | return md.unify(primValue.undecoded, rvalue(v)) 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/indirect.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 Steve Francia . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package cast 7 | 8 | import ( 9 | "reflect" 10 | ) 11 | 12 | // From html/template/content.go 13 | // Copyright 2011 The Go Authors. All rights reserved. 14 | // indirect returns the value, after dereferencing as many times 15 | // as necessary to reach the base type (or nil). 16 | func indirect(i any) (any, bool) { 17 | if i == nil { 18 | return nil, false 19 | } 20 | 21 | if t := reflect.TypeOf(i); t.Kind() != reflect.Ptr { 22 | // Avoid creating a reflect.Value if it's not a pointer. 23 | return i, false 24 | } 25 | 26 | v := reflect.ValueOf(i) 27 | 28 | for v.Kind() == reflect.Ptr || (v.Kind() == reflect.Interface && v.Elem().Kind() == reflect.Ptr) { 29 | if v.IsNil() { 30 | return nil, true 31 | } 32 | 33 | v = v.Elem() 34 | } 35 | 36 | return v.Interface(), true 37 | } 38 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/Makefile: -------------------------------------------------------------------------------- 1 | # Directory to put `go install`ed binaries in. 2 | export GOBIN ?= $(shell pwd)/bin 3 | 4 | GO_FILES := $(shell \ 5 | find . '(' -path '*/.*' -o -path './vendor' ')' -prune \ 6 | -o -name '*.go' -print | cut -b3-) 7 | 8 | .PHONY: build 9 | build: 10 | go build ./... 11 | 12 | .PHONY: test 13 | test: 14 | go test -race ./... 15 | 16 | .PHONY: gofmt 17 | gofmt: 18 | $(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX)) 19 | @gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true 20 | @[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false) 21 | 22 | .PHONY: golint 23 | golint: 24 | @cd tools && go install golang.org/x/lint/golint 25 | @$(GOBIN)/golint ./... 26 | 27 | .PHONY: staticcheck 28 | staticcheck: 29 | @cd tools && go install honnef.co/go/tools/cmd/staticcheck 30 | @$(GOBIN)/staticcheck ./... 31 | 32 | .PHONY: lint 33 | lint: gofmt golint staticcheck 34 | 35 | .PHONY: cover 36 | cover: 37 | go test -race -coverprofile=cover.out -coverpkg=./... -v ./... 38 | go tool cover -html=cover.out -o cover.html 39 | -------------------------------------------------------------------------------- /vendor/github.com/mailru/easyjson/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Mail.Ru Group 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We definitely welcome patches and contribution to this project! 4 | 5 | ### Tips 6 | 7 | Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). 8 | 9 | Always try to include a test case! If it is not possible or not necessary, 10 | please explain why in the pull request description. 11 | 12 | ### Releasing 13 | 14 | Commits that would precipitate a SemVer change, as described in the Conventional 15 | Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) 16 | to create a release candidate pull request. Once submitted, `release-please` 17 | will create a release. 18 | 19 | For tips on how to work with `release-please`, see its documentation. 20 | 21 | ### Legal requirements 22 | 23 | In order to protect both you and ourselves, you will need to sign the 24 | [Contributor License Agreement](https://cla.developers.google.com/clas). 25 | 26 | You may have already signed it for other Google projects. 27 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/marshal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import "fmt" 8 | 9 | // MarshalText implements encoding.TextMarshaler. 10 | func (uuid UUID) MarshalText() ([]byte, error) { 11 | var js [36]byte 12 | encodeHex(js[:], uuid) 13 | return js[:], nil 14 | } 15 | 16 | // UnmarshalText implements encoding.TextUnmarshaler. 17 | func (uuid *UUID) UnmarshalText(data []byte) error { 18 | id, err := ParseBytes(data) 19 | if err != nil { 20 | return err 21 | } 22 | *uuid = id 23 | return nil 24 | } 25 | 26 | // MarshalBinary implements encoding.BinaryMarshaler. 27 | func (uuid UUID) MarshalBinary() ([]byte, error) { 28 | return uuid[:], nil 29 | } 30 | 31 | // UnmarshalBinary implements encoding.BinaryUnmarshaler. 32 | func (uuid *UUID) UnmarshalBinary(data []byte) error { 33 | if len(data) != 16 { 34 | return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) 35 | } 36 | copy(uuid[:], data) 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/internal/timeformattype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=TimeFormatType"; DO NOT EDIT. 2 | 3 | package internal 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[TimeFormatNoTimezone-0] 12 | _ = x[TimeFormatNamedTimezone-1] 13 | _ = x[TimeFormatNumericTimezone-2] 14 | _ = x[TimeFormatNumericAndNamedTimezone-3] 15 | _ = x[TimeFormatTimeOnly-4] 16 | } 17 | 18 | const _TimeFormatType_name = "TimeFormatNoTimezoneTimeFormatNamedTimezoneTimeFormatNumericTimezoneTimeFormatNumericAndNamedTimezoneTimeFormatTimeOnly" 19 | 20 | var _TimeFormatType_index = [...]uint8{0, 20, 43, 68, 101, 119} 21 | 22 | func (i TimeFormatType) String() string { 23 | if i < 0 || i >= TimeFormatType(len(_TimeFormatType_index)-1) { 24 | return "TimeFormatType(" + strconv.FormatInt(int64(i), 10) + ")" 25 | } 26 | return _TimeFormatType_name[_TimeFormatType_index[i]:_TimeFormatType_index[i+1]] 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/bytes.go: -------------------------------------------------------------------------------- 1 | package jsonparser 2 | 3 | import ( 4 | bio "bytes" 5 | ) 6 | 7 | // minInt64 '-9223372036854775808' is the smallest representable number in int64 8 | const minInt64 = `9223372036854775808` 9 | 10 | // About 2x faster then strconv.ParseInt because it only supports base 10, which is enough for JSON 11 | func parseInt(bytes []byte) (v int64, ok bool, overflow bool) { 12 | if len(bytes) == 0 { 13 | return 0, false, false 14 | } 15 | 16 | var neg bool = false 17 | if bytes[0] == '-' { 18 | neg = true 19 | bytes = bytes[1:] 20 | } 21 | 22 | var b int64 = 0 23 | for _, c := range bytes { 24 | if c >= '0' && c <= '9' { 25 | b = (10 * v) + int64(c-'0') 26 | } else { 27 | return 0, false, false 28 | } 29 | if overflow = (b < v); overflow { 30 | break 31 | } 32 | v = b 33 | } 34 | 35 | if overflow { 36 | if neg && bio.Equal(bytes, []byte(minInt64)) { 37 | return b, true, false 38 | } 39 | return 0, false, true 40 | } 41 | 42 | if neg { 43 | return -v, true, false 44 | } else { 45 | return v, true, false 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /internal/tool/apps/get.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Get = bitrise.Tool{ 13 | APIGroups: []string{"apps", "read-only"}, 14 | Definition: mcp.NewTool("get_app", 15 | mcp.WithDescription("Get the details of a specific app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/node_net.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !js 6 | 7 | package uuid 8 | 9 | import "net" 10 | 11 | var interfaces []net.Interface // cached list of interfaces 12 | 13 | // getHardwareInterface returns the name and hardware address of interface name. 14 | // If name is "" then the name and hardware address of one of the system's 15 | // interfaces is returned. If no interfaces are found (name does not exist or 16 | // there are no interfaces) then "", nil is returned. 17 | // 18 | // Only addresses of at least 6 bytes are returned. 19 | func getHardwareInterface(name string) (string, []byte) { 20 | if interfaces == nil { 21 | var err error 22 | interfaces, err = net.Interfaces() 23 | if err != nil { 24 | return "", nil 25 | } 26 | } 27 | for _, ifs := range interfaces { 28 | if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { 29 | return ifs.Name, ifs.HardwareAddr 30 | } 31 | } 32 | return "", nil 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/wk8/go-ordered-map/v2/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | [comment]: # (Changes since last release go here) 4 | 5 | ## 2.1.8 - Jun 27th 2023 6 | 7 | * Added support for YAML serialization/deserialization 8 | 9 | ## 2.1.7 - Apr 13th 2023 10 | 11 | * Renamed test_utils.go to utils_test.go 12 | 13 | ## 2.1.6 - Feb 15th 2023 14 | 15 | * Added `GetAndMoveToBack()` and `GetAndMoveToFront()` methods 16 | 17 | ## 2.1.5 - Dec 13th 2022 18 | 19 | * Added `Value()` method 20 | 21 | ## 2.1.4 - Dec 12th 2022 22 | 23 | * Fixed a bug with UTF-8 special characters in JSON keys 24 | 25 | ## 2.1.3 - Dec 11th 2022 26 | 27 | * Added support for JSON marshalling/unmarshalling of wrapper of primitive types 28 | 29 | ## 2.1.2 - Dec 10th 2022 30 | * Allowing to pass options to `New`, to give a capacity hint, or initial data 31 | * Allowing to deserialize nested ordered maps from JSON without having to explicitly instantiate them 32 | * Added the `AddPairs` method 33 | 34 | ## 2.1.1 - Dec 9th 2022 35 | * Fixing a bug with JSON marshalling 36 | 37 | ## 2.1.0 - Dec 7th 2022 38 | * Added support for JSON serialization/deserialization 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Bitrise 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /vendor/github.com/invopop/jsonschema/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2017 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /internal/tool/pipelines/list.go: -------------------------------------------------------------------------------- 1 | package pipelines 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var List = bitrise.Tool{ 13 | APIGroups: []string{"pipelines", "read-only"}, 14 | Definition: mcp.NewTool("list_pipelines", 15 | mcp.WithDescription("List all pipelines and standalone builds of an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/pipelines", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /internal/tool/workspaces/get.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Get = bitrise.Tool{ 13 | APIGroups: []string{"workspaces", "read-only"}, 14 | Definition: mcp.NewTool("get_workspace", 15 | mcp.WithDescription("Get details for one workspace"), 16 | mcp.WithString("workspace_slug", 17 | mcp.Description("Slug of the Bitrise workspace"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | workspaceSlug, err := request.RequireString("workspace_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/organizations/%s", workspaceSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2021 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /internal/tool/apps/list_branches.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var ListBranches = bitrise.Tool{ 13 | APIGroups: []string{"apps", "read-only"}, 14 | Definition: mcp.NewTool("list_branches", 15 | mcp.WithDescription("List the branches with existing builds of an app's repository."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/branches", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /internal/tool/apps/register_webhook.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var RegisterWebhook = bitrise.Tool{ 13 | APIGroups: []string{"apps"}, 14 | Definition: mcp.NewTool("register_webhook", 15 | mcp.WithDescription("Register an incoming webhook for a specific application."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodPost, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/register-webhook", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /internal/tool/builds/list_build_workflows.go: -------------------------------------------------------------------------------- 1 | package builds 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var ListBuildWorkflows = bitrise.Tool{ 13 | APIGroups: []string{"builds", "read-only"}, 14 | Definition: mcp.NewTool("list_build_workflows", 15 | mcp.WithDescription("List the workflows of an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/build-workflows", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /internal/tool/cache/list_items.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var ListItems = bitrise.Tool{ 13 | APIGroups: []string{"cache-items", "read-only"}, 14 | Definition: mcp.NewTool("list_cache_items", 15 | mcp.WithDescription("List the key-value cache items belonging to an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/cache-items", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Leonid Bugaev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/server/roots.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/mark3labs/mcp-go/mcp" 8 | ) 9 | 10 | var ( 11 | // ErrNoClientSession is returned when there is no active client session in the context 12 | ErrNoClientSession = errors.New("no active client session") 13 | // ErrRootsNotSupported is returned when the session does not support roots 14 | ErrRootsNotSupported = errors.New("session does not support roots") 15 | ) 16 | 17 | // RequestRoots sends an list roots request to the client. 18 | // The client must have declared roots capability during initialization. 19 | // The session must implement SessionWithRoots to support this operation. 20 | func (s *MCPServer) RequestRoots(ctx context.Context, request mcp.ListRootsRequest) (*mcp.ListRootsResult, error) { 21 | session := ClientSessionFromContext(ctx) 22 | if session == nil { 23 | return nil, ErrNoClientSession 24 | } 25 | 26 | // Check if the session supports roots requests 27 | if rootsSession, ok := session.(SessionWithRoots); ok { 28 | return rootsSession.ListRoots(ctx, request) 29 | } 30 | 31 | return nil, ErrRootsNotSupported 32 | } 33 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Steve Francia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /internal/tool/cache/delete_all_items.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var DeleteAllItems = bitrise.Tool{ 13 | APIGroups: []string{"cache-items"}, 14 | Definition: mcp.NewTool("delete_all_cache_items", 15 | mcp.WithDescription("Delete all key-value cache items belonging to an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodDelete, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/cache", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Anthropic, PBC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /internal/tool/webhooks/list_outgoing.go: -------------------------------------------------------------------------------- 1 | package webhooks 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var ListOutgoing = bitrise.Tool{ 13 | APIGroups: []string{"outgoing-webhooks", "read-only"}, 14 | Definition: mcp.NewTool("list_outgoing_webhooks", 15 | mcp.WithDescription("List the outgoing webhooks of an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/outgoing-webhooks", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/Makefile: -------------------------------------------------------------------------------- 1 | SOURCE = parser.go 2 | CONTAINER = jsonparser 3 | SOURCE_PATH = /go/src/github.com/buger/jsonparser 4 | BENCHMARK = JsonParser 5 | BENCHTIME = 5s 6 | TEST = . 7 | DRUN = docker run -v `pwd`:$(SOURCE_PATH) -i -t $(CONTAINER) 8 | 9 | build: 10 | docker build -t $(CONTAINER) . 11 | 12 | race: 13 | $(DRUN) --env GORACE="halt_on_error=1" go test ./. $(ARGS) -v -race -timeout 15s 14 | 15 | bench: 16 | $(DRUN) go test $(LDFLAGS) -test.benchmem -bench $(BENCHMARK) ./benchmark/ $(ARGS) -benchtime $(BENCHTIME) -v 17 | 18 | bench_local: 19 | $(DRUN) go test $(LDFLAGS) -test.benchmem -bench . $(ARGS) -benchtime $(BENCHTIME) -v 20 | 21 | profile: 22 | $(DRUN) go test $(LDFLAGS) -test.benchmem -bench $(BENCHMARK) ./benchmark/ $(ARGS) -memprofile mem.mprof -v 23 | $(DRUN) go test $(LDFLAGS) -test.benchmem -bench $(BENCHMARK) ./benchmark/ $(ARGS) -cpuprofile cpu.out -v 24 | $(DRUN) go test $(LDFLAGS) -test.benchmem -bench $(BENCHMARK) ./benchmark/ $(ARGS) -c 25 | 26 | test: 27 | $(DRUN) go test $(LDFLAGS) ./ -run $(TEST) -timeout 10s $(ARGS) -v 28 | 29 | fmt: 30 | $(DRUN) go fmt ./... 31 | 32 | vet: 33 | $(DRUN) go vet ./. 34 | 35 | bash: 36 | $(DRUN) /bin/bash -------------------------------------------------------------------------------- /vendor/github.com/jinzhu/configor/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-NOW Jinzhu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /internal/tool/workspaces/get_workspace_groups.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetWorkspaceGroups = bitrise.Tool{ 13 | APIGroups: []string{"workspaces", "read-only"}, 14 | Definition: mcp.NewTool("get_workspace_groups", 15 | mcp.WithDescription("Get the groups in a workspace"), 16 | mcp.WithString("workspace_slug", 17 | mcp.Description("Slug of the Bitrise workspace"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | workspaceSlug, err := request.RequireString("workspace_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/organizations/%s/groups", workspaceSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /internal/tool/workspaces/get_workspace_members.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetWorkspaceMembers = bitrise.Tool{ 13 | APIGroups: []string{"workspaces", "read-only"}, 14 | Definition: mcp.NewTool("get_workspace_members", 15 | mcp.WithDescription("Get the members of a workspace"), 16 | mcp.WithString("workspace_slug", 17 | mcp.Description("Slug of the Bitrise workspace"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | workspaceSlug, err := request.RequireString("workspace_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/organizations/%s/members", workspaceSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/yosida95/uritemplate/v3/README.rst: -------------------------------------------------------------------------------- 1 | uritemplate 2 | =========== 3 | 4 | `uritemplate`_ is a Go implementation of `URI Template`_ [RFC6570] with 5 | full functionality of URI Template Level 4. 6 | 7 | uritemplate can also generate a regexp that matches expansion of the 8 | URI Template from a URI Template. 9 | 10 | Getting Started 11 | --------------- 12 | 13 | Installation 14 | ~~~~~~~~~~~~ 15 | 16 | .. code-block:: sh 17 | 18 | $ go get -u github.com/yosida95/uritemplate/v3 19 | 20 | Documentation 21 | ~~~~~~~~~~~~~ 22 | 23 | The documentation is available on GoDoc_. 24 | 25 | Examples 26 | -------- 27 | 28 | See `examples on GoDoc`_. 29 | 30 | License 31 | ------- 32 | 33 | `uritemplate`_ is distributed under the BSD 3-Clause license. 34 | PLEASE READ ./LICENSE carefully and follow its clauses to use this software. 35 | 36 | Author 37 | ------ 38 | 39 | yosida95_ 40 | 41 | 42 | .. _`URI Template`: https://tools.ietf.org/html/rfc6570 43 | .. _Godoc: https://godoc.org/github.com/yosida95/uritemplate 44 | .. _`examples on GoDoc`: https://godoc.org/github.com/yosida95/uritemplate#pkg-examples 45 | .. _yosida95: https://yosida95.com/ 46 | .. _uritemplate: https://github.com/yosida95/uritemplate 47 | -------------------------------------------------------------------------------- /internal/tool/apps/delete.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Delete = bitrise.Tool{ 13 | APIGroups: []string{"apps"}, 14 | Definition: mcp.NewTool("delete_app", 15 | mcp.WithDescription("Delete an app from Bitrise. When deleting apps belonging to multiple workspaces always confirm that which workspaces' apps the user wants to delete."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodDelete, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/get_connected_app.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetConnectedApp = bitrise.Tool{ 13 | APIGroups: []string{"release-management", "read-only"}, 14 | Definition: mcp.NewTool("get_connected_app", 15 | mcp.WithDescription("Gives back a Release Management connected app for the authenticated account."), 16 | mcp.WithString("id", 17 | mcp.Description("Identifier of the Release Management connected app"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | id, err := request.RequireString("id") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIRMBaseURL, 30 | Path: fmt.Sprintf("/connected-apps/%s", id), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/server/elicitation.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/mark3labs/mcp-go/mcp" 8 | ) 9 | 10 | var ( 11 | // ErrNoActiveSession is returned when there is no active session in the context 12 | ErrNoActiveSession = errors.New("no active session") 13 | // ErrElicitationNotSupported is returned when the session does not support elicitation 14 | ErrElicitationNotSupported = errors.New("session does not support elicitation") 15 | ) 16 | 17 | // RequestElicitation sends an elicitation request to the client. 18 | // The client must have declared elicitation capability during initialization. 19 | // The session must implement SessionWithElicitation to support this operation. 20 | func (s *MCPServer) RequestElicitation(ctx context.Context, request mcp.ElicitationRequest) (*mcp.ElicitationResult, error) { 21 | session := ClientSessionFromContext(ctx) 22 | if session == nil { 23 | return nil, ErrNoActiveSession 24 | } 25 | 26 | // Check if the session supports elicitation requests 27 | if elicitationSession, ok := session.(SessionWithElicitation); ok { 28 | return elicitationSession.RequestElicitation(ctx, request) 29 | } 30 | 31 | return nil, ErrElicitationNotSupported 32 | } 33 | -------------------------------------------------------------------------------- /internal/tool/apps/get_bitrise_yml.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetBitriseYML = bitrise.Tool{ 13 | APIGroups: []string{"apps", "read-only"}, 14 | Definition: mcp.NewTool("get_bitrise_yml", 15 | mcp.WithDescription("Get the current Bitrise YML config file of a specified Bitrise app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app (e.g., \"d8db74e2675d54c4\" or \"8eb495d0-f653-4eed-910b-8d6b56cc0ec7\")"), 18 | mcp.Required(), 19 | ), 20 | ), 21 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 22 | appSlug, err := request.RequireString("app_slug") 23 | if err != nil { 24 | return mcp.NewToolResultError(err.Error()), nil 25 | } 26 | 27 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 28 | Method: http.MethodGet, 29 | BaseURL: bitrise.APIBaseURL, 30 | Path: fmt.Sprintf("/apps/%s/bitrise.yml", appSlug), 31 | }) 32 | if err != nil { 33 | return mcp.NewToolResultErrorFromErr("call api", err), nil 34 | } 35 | return mcp.NewToolResultText(res), nil 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bitrise MCP Server 2 | 3 | [![Build Status](https://app.bitrise.io/app/37d1538c-d2d6-4b20-a2cc-78862be22342/status.svg?token=QQWdHofHMTWA2EIkXT4rcA&branch=main)](https://app.bitrise.io/app/37d1538c-d2d6-4b20-a2cc-78862be22342) 4 | 5 | MCP Server for the Bitrise API, enabling app management, build operations, artifact management, and more. 6 | 7 | ## Features 8 | 9 | - **Comprehensive API Access**: Access to Bitrise APIs including apps, builds, artifacts, and more. 10 | - **Authentication Support**: Secure API token-based access to Bitrise resources. 11 | - **Detailed Documentation**: [Well-documented tools with parameter descriptions](/docs/tools.md). 12 | 13 | ## Installation 14 | 15 | - **[VS Code](/docs/install-vscode.md)** - Installation for VS Code IDE 16 | - **[GitHub Copilot in other IDEs](/docs/install-other-copilot-ides.md)** - Installation for JetBrains, Visual Studio, Eclipse, and Xcode with GitHub Copilot 17 | - **[Claude Applications](/docs/install-claude.md)** - Installation guide for Claude Desktop and Claude Code CLI 18 | - **[Cursor](/docs/install-cursor.md)** - Installation guide for Cursor IDE 19 | - **[Windsurf](/docs/install-windsurf.md)** - Installation guide for Windsurf IDE 20 | - **[Gemini CLI](/docs/install-gemini-cli.md)** - Installation guide for Gemini CLI 21 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cast/Makefile: -------------------------------------------------------------------------------- 1 | GOVERSION := $(shell go version | cut -d ' ' -f 3 | cut -d '.' -f 2) 2 | 3 | .PHONY: check fmt lint test test-race vet test-cover-html help 4 | .DEFAULT_GOAL := help 5 | 6 | check: test-race fmt vet lint ## Run tests and linters 7 | 8 | test: ## Run tests 9 | go test ./... 10 | 11 | test-race: ## Run tests with race detector 12 | go test -race ./... 13 | 14 | fmt: ## Run gofmt linter 15 | ifeq "$(GOVERSION)" "12" 16 | @for d in `go list` ; do \ 17 | if [ "`gofmt -l -s $$GOPATH/src/$$d | tee /dev/stderr`" ]; then \ 18 | echo "^ improperly formatted go files" && echo && exit 1; \ 19 | fi \ 20 | done 21 | endif 22 | 23 | lint: ## Run golint linter 24 | @for d in `go list` ; do \ 25 | if [ "`golint $$d | tee /dev/stderr`" ]; then \ 26 | echo "^ golint errors!" && echo && exit 1; \ 27 | fi \ 28 | done 29 | 30 | vet: ## Run go vet linter 31 | @if [ "`go vet | tee /dev/stderr`" ]; then \ 32 | echo "^ go vet errors!" && echo && exit 1; \ 33 | fi 34 | 35 | test-cover-html: ## Generate test coverage report 36 | go test -coverprofile=coverage.out -covermode=count 37 | go tool cover -func=coverage.out 38 | 39 | help: 40 | @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 41 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/time.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package zap 22 | 23 | import "time" 24 | 25 | func timeToMillis(t time.Time) int64 { 26 | return t.UnixNano() / int64(time.Millisecond) 27 | } 28 | -------------------------------------------------------------------------------- /internal/tool/builds/get.go: -------------------------------------------------------------------------------- 1 | package builds 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Get = bitrise.Tool{ 13 | APIGroups: []string{"builds", "read-only"}, 14 | Definition: mcp.NewTool("get_build", 15 | mcp.WithDescription("Get a specific build of a given app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | buildSlug, err := request.RequireString("build_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/builds/%s", appSlug, buildSlug), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/grouproles/list.go: -------------------------------------------------------------------------------- 1 | package grouproles 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var List = bitrise.Tool{ 13 | APIGroups: []string{"group-roles", "read-only"}, 14 | Definition: mcp.NewTool("list_group_roles", 15 | mcp.WithDescription("List group roles for an app"), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("role_name", 21 | mcp.Description("Name of the role"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | roleName, err := request.RequireString("role_name") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/roles/%s", appSlug, roleName), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/go . 3 | { 4 | "name": "Go", 5 | "image": "mcr.microsoft.com/devcontainers/go:2-1.25-bookworm", 6 | "features": { 7 | "ghcr.io/devcontainers/features/docker-in-docker:2": {} 8 | }, 9 | "postCreateCommand": "go mod tidy && go mod vendor && make install-golangci-lint", 10 | "customizations": { 11 | "vscode": { 12 | "extensions": [ 13 | "golang.go", 14 | "ms-azuretools.vscode-containers" 15 | ], 16 | "settings": { 17 | "[go]": { 18 | "editor.formatOnSave": true, 19 | "editor.defaultFormatter": "golang.go", 20 | "editor.codeActionsOnSave": { 21 | "source.organizeImports": "explicit", 22 | "source.fixAll": "explicit" 23 | } 24 | }, 25 | "go.useLanguageServer": true, 26 | "gopls": { 27 | "ui.semanticTokens": true, 28 | "ui.completion.usePlaceholders": true 29 | }, 30 | "go.lintTool": "golangci-lint", 31 | "go.lintFlags": [ 32 | "--path-mode=abs", 33 | "--fast-only" 34 | ], 35 | "go.formatTool": "custom", 36 | "go.alternateTools": { 37 | "customFormatter": "golangci-lint" 38 | }, 39 | "go.formatFlags": [ 40 | "fmt", 41 | "--stdin" 42 | ], 43 | "go.coverOnSave": false 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /internal/tool/workspaces/add_member_to_group.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var AddMemberToGroup = bitrise.Tool{ 13 | APIGroups: []string{"workspaces"}, 14 | Definition: mcp.NewTool("add_member_to_group", 15 | mcp.WithDescription("Add a member to a group."), 16 | mcp.WithString("group_slug", 17 | mcp.Description("Slug of the group"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("user_slug", 21 | mcp.Description("Slug of the user"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | groupSlug, err := request.RequireString("group_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | userSlug, err := request.RequireString("user_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodPut, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/groups/%s/members/%s", groupSlug, userSlug), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/cache/delete_item.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var DeleteItem = bitrise.Tool{ 13 | APIGroups: []string{"cache-items"}, 14 | Definition: mcp.NewTool("delete_cache_item", 15 | mcp.WithDescription("Delete a key-value cache item."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("cache_item_id", 21 | mcp.Description("Key of the cache item"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | cacheItemID, err := request.RequireString("cache_item_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodDelete, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/cache/%s", appSlug, cacheItemID), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/pipelines/get.go: -------------------------------------------------------------------------------- 1 | package pipelines 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Get = bitrise.Tool{ 13 | APIGroups: []string{"pipelines", "read-only"}, 14 | Definition: mcp.NewTool("get_pipeline", 15 | mcp.WithDescription("Get a pipeline of a given app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("pipeline_id", 21 | mcp.Description("Identifier of the pipeline"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | pipelineID, err := request.RequireString("pipeline_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/pipelines/%s", appSlug, pipelineID), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/builds/get_steps.go: -------------------------------------------------------------------------------- 1 | package builds 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetSteps = bitrise.Tool{ 13 | APIGroups: []string{"builds", "read-only"}, 14 | Definition: mcp.NewTool("get_build_steps", 15 | mcp.WithDescription("Get step statuses of a specific build of a given app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | buildSlug, err := request.RequireString("build_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/builds/%s/log/summary", appSlug, buildSlug), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/pipelines/rebuild.go: -------------------------------------------------------------------------------- 1 | package pipelines 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Rebuild = bitrise.Tool{ 13 | APIGroups: []string{"pipelines"}, 14 | Definition: mcp.NewTool("rebuild_pipeline", 15 | mcp.WithDescription("Rebuild a pipeline."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("pipeline_id", 21 | mcp.Description("Identifier of the pipeline"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | pipelineID, err := request.RequireString("pipeline_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodPost, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/pipelines/%s/rebuild", appSlug, pipelineID), 39 | Body: map[string]any{}, 40 | }) 41 | if err != nil { 42 | return mcp.NewToolResultErrorFromErr("call api", err), nil 43 | } 44 | return mcp.NewToolResultText(res), nil 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /internal/tool/builds/get_build_bitrise_yml.go: -------------------------------------------------------------------------------- 1 | package builds 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetBuildBitriseYML = bitrise.Tool{ 13 | APIGroups: []string{"builds", "read-only"}, 14 | Definition: mcp.NewTool("get_build_bitrise_yml", 15 | mcp.WithDescription("Get the bitrise.yml of a build."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | buildSlug, err := request.RequireString("build_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/builds/%s/bitrise.yml", appSlug, buildSlug), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/webhooks/delete_outgoing.go: -------------------------------------------------------------------------------- 1 | package webhooks 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var DeleteOutgoing = bitrise.Tool{ 13 | APIGroups: []string{"outgoing-webhooks"}, 14 | Definition: mcp.NewTool("delete_outgoing_webhook", 15 | mcp.WithDescription("Delete the outgoing webhook of an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("webhook_slug", 21 | mcp.Description("Identifier of the webhook"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | webhookSlug, err := request.RequireString("webhook_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodDelete, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/outgoing-webhooks/%s", appSlug, webhookSlug), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/version1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | ) 10 | 11 | // NewUUID returns a Version 1 UUID based on the current NodeID and clock 12 | // sequence, and the current time. If the NodeID has not been set by SetNodeID 13 | // or SetNodeInterface then it will be set automatically. If the NodeID cannot 14 | // be set NewUUID returns nil. If clock sequence has not been set by 15 | // SetClockSequence then it will be set automatically. If GetTime fails to 16 | // return the current NewUUID returns nil and an error. 17 | // 18 | // In most cases, New should be used. 19 | func NewUUID() (UUID, error) { 20 | var uuid UUID 21 | now, seq, err := GetTime() 22 | if err != nil { 23 | return uuid, err 24 | } 25 | 26 | timeLow := uint32(now & 0xffffffff) 27 | timeMid := uint16((now >> 32) & 0xffff) 28 | timeHi := uint16((now >> 48) & 0x0fff) 29 | timeHi |= 0x1000 // Version 1 30 | 31 | binary.BigEndian.PutUint32(uuid[0:], timeLow) 32 | binary.BigEndian.PutUint16(uuid[4:], timeMid) 33 | binary.BigEndian.PutUint16(uuid[6:], timeHi) 34 | binary.BigEndian.PutUint16(uuid[8:], seq) 35 | 36 | nodeMu.Lock() 37 | if nodeID == zeroID { 38 | setNodeInterface("") 39 | } 40 | copy(uuid[10:], nodeID[:]) 41 | nodeMu.Unlock() 42 | 43 | return uuid, nil 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/bytes_unsafe.go: -------------------------------------------------------------------------------- 1 | // +build !appengine,!appenginevm 2 | 3 | package jsonparser 4 | 5 | import ( 6 | "reflect" 7 | "strconv" 8 | "unsafe" 9 | "runtime" 10 | ) 11 | 12 | // 13 | // The reason for using *[]byte rather than []byte in parameters is an optimization. As of Go 1.6, 14 | // the compiler cannot perfectly inline the function when using a non-pointer slice. That is, 15 | // the non-pointer []byte parameter version is slower than if its function body is manually 16 | // inlined, whereas the pointer []byte version is equally fast to the manually inlined 17 | // version. Instruction count in assembly taken from "go tool compile" confirms this difference. 18 | // 19 | // TODO: Remove hack after Go 1.7 release 20 | // 21 | func equalStr(b *[]byte, s string) bool { 22 | return *(*string)(unsafe.Pointer(b)) == s 23 | } 24 | 25 | func parseFloat(b *[]byte) (float64, error) { 26 | return strconv.ParseFloat(*(*string)(unsafe.Pointer(b)), 64) 27 | } 28 | 29 | // A hack until issue golang/go#2632 is fixed. 30 | // See: https://github.com/golang/go/issues/2632 31 | func bytesToString(b *[]byte) string { 32 | return *(*string)(unsafe.Pointer(b)) 33 | } 34 | 35 | func StringToBytes(s string) []byte { 36 | b := make([]byte, 0, 0) 37 | bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 38 | sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) 39 | bh.Data = sh.Data 40 | bh.Cap = sh.Len 41 | bh.Len = sh.Len 42 | runtime.KeepAlive(s) 43 | return b 44 | } 45 | -------------------------------------------------------------------------------- /internal/tool/cache/get_item_download_url.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetItemDownloadURL = bitrise.Tool{ 13 | APIGroups: []string{"cache-items", "read-only"}, 14 | Definition: mcp.NewTool("get_cache_item_download_url", 15 | mcp.WithDescription("Get the download URL for a cache item."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("cache_item_id", 21 | mcp.Description("Key of the cache item"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | cacheItemID, err := request.RequireString("cache_item_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/cache-items/%s/download", appSlug, cacheItemID), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/yosida95/uritemplate/v3/equals.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Kohei YOSHIDA. All rights reserved. 2 | // 3 | // This program is free software; you can redistribute it and/or 4 | // modify it under the terms of The BSD 3-Clause License 5 | // that can be found in the LICENSE file. 6 | 7 | package uritemplate 8 | 9 | type CompareFlags uint8 10 | 11 | const ( 12 | CompareVarname CompareFlags = 1 << iota 13 | ) 14 | 15 | // Equals reports whether or not two URI Templates t1 and t2 are equivalent. 16 | func Equals(t1 *Template, t2 *Template, flags CompareFlags) bool { 17 | if len(t1.exprs) != len(t2.exprs) { 18 | return false 19 | } 20 | for i := 0; i < len(t1.exprs); i++ { 21 | switch t1 := t1.exprs[i].(type) { 22 | case literals: 23 | t2, ok := t2.exprs[i].(literals) 24 | if !ok { 25 | return false 26 | } 27 | if t1 != t2 { 28 | return false 29 | } 30 | case *expression: 31 | t2, ok := t2.exprs[i].(*expression) 32 | if !ok { 33 | return false 34 | } 35 | if t1.op != t2.op || len(t1.vars) != len(t2.vars) { 36 | return false 37 | } 38 | for n := 0; n < len(t1.vars); n++ { 39 | v1 := t1.vars[n] 40 | v2 := t2.vars[n] 41 | if flags&CompareVarname == CompareVarname && v1.name != v2.name { 42 | return false 43 | } 44 | if v1.maxlen != v2.maxlen || v1.explode != v2.explode { 45 | return false 46 | } 47 | } 48 | default: 49 | panic("unhandled case") 50 | } 51 | } 52 | return true 53 | } 54 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/zapcore/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | // Package zapcore defines and implements the low-level interfaces upon which 22 | // zap is built. By providing alternate implementations of these interfaces, 23 | // external packages can extend zap's capabilities. 24 | package zapcore // import "go.uber.org/zap/zapcore" 25 | -------------------------------------------------------------------------------- /internal/tool/workspaces/create_workspace_group.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var CreateWorkspaceGroup = bitrise.Tool{ 13 | APIGroups: []string{"workspaces"}, 14 | Definition: mcp.NewTool("create_workspace_group", 15 | mcp.WithDescription("Create a new group in a workspace."), 16 | mcp.WithString("workspace_slug", 17 | mcp.Description("Slug of the Bitrise workspace"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("group_name", 21 | mcp.Description("Name of the group"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | workspaceSlug, err := request.RequireString("workspace_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | groupName, err := request.RequireString("group_name") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodPost, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/organizations/%s/groups", workspaceSlug), 39 | Body: map[string]any{ 40 | "name": groupName, 41 | }, 42 | }) 43 | if err != nil { 44 | return mcp.NewToolResultErrorFromErr("call api", err), nil 45 | } 46 | return mcp.NewToolResultText(res), nil 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /internal/tool/workspaces/invite_member_to_workspace.go: -------------------------------------------------------------------------------- 1 | package workspaces 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var InviteMemberToWorkspace = bitrise.Tool{ 13 | APIGroups: []string{"workspaces"}, 14 | Definition: mcp.NewTool("invite_member_to_workspace", 15 | mcp.WithDescription("Invite new Bitrise users to a workspace."), 16 | mcp.WithString("workspace_slug", 17 | mcp.Description("Slug of the Bitrise workspace"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("email", 21 | mcp.Description("Email address of the user"), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | workspaceSlug, err := request.RequireString("workspace_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | email, err := request.RequireString("email") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodPost, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/organizations/%s/members", workspaceSlug), 39 | Body: map[string]any{ 40 | "email": email, 41 | }, 42 | }) 43 | if err != nil { 44 | return mcp.NewToolResultErrorFromErr("call api", err), nil 45 | } 46 | return mcp.NewToolResultText(res), nil 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /internal/tool/apps/list.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "strconv" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var List = bitrise.Tool{ 13 | APIGroups: []string{"apps", "read-only"}, 14 | Definition: mcp.NewTool("list_apps", 15 | mcp.WithDescription("List all apps for the currently authenticated user account"), 16 | mcp.WithString("sort_by", 17 | mcp.Description("Order of the apps: last_build_at (default) or created_at. If set, you should accept the response as sorted"), 18 | mcp.Enum("last_build_at", "created_at"), 19 | mcp.DefaultString("last_build_at"), 20 | ), 21 | mcp.WithString("next", 22 | mcp.Description("Slug of the first app in the response"), 23 | ), 24 | mcp.WithNumber("limit", 25 | mcp.Description("Max number of elements per page (default: 50)"), 26 | mcp.DefaultNumber(50), 27 | ), 28 | ), 29 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 30 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 31 | Method: http.MethodGet, 32 | BaseURL: bitrise.APIBaseURL, 33 | Path: "/apps", 34 | Params: map[string]string{ 35 | "sort_by": request.GetString("sort_by", "last_build_at"), 36 | "next": request.GetString("next", ""), 37 | "limit": strconv.Itoa(request.GetInt("limit", 50)), 38 | }, 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009,2014 Google Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | // Package bufferpool houses zap's shared internal buffer pool. Third-party 22 | // packages can recreate the same functionality with buffers.NewPool. 23 | package bufferpool 24 | 25 | import "go.uber.org/zap/buffer" 26 | 27 | var ( 28 | _pool = buffer.NewPool() 29 | // Get retrieves a buffer from the pool, creating one if necessary. 30 | Get = _pool.Get 31 | ) 32 | -------------------------------------------------------------------------------- /vendor/github.com/bahlo/generic-list-go/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/get_tester_group.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetTesterGroup = bitrise.Tool{ 13 | APIGroups: []string{"release-management", "read-only"}, 14 | Definition: mcp.NewTool("get_tester_group", 15 | mcp.WithDescription("Gives back the details of the selected tester group."), 16 | mcp.WithString("connected_app_id", 17 | mcp.Description("The uuidV4 identifier of the app the tester group is connected to. This field is mandatory."), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("id", 21 | mcp.Description("The uuidV4 identifier of the tester group. This field is mandatory."), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | connectedAppID, err := request.RequireString("connected_app_id") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | id, err := request.RequireString("id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIRMBaseURL, 38 | Path: fmt.Sprintf("/connected-apps/%s/tester-groups/%s", connectedAppID, id), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /internal/tool/builds/abort.go: -------------------------------------------------------------------------------- 1 | package builds 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Abort = bitrise.Tool{ 13 | APIGroups: []string{"builds"}, 14 | Definition: mcp.NewTool("abort_build", 15 | mcp.WithDescription("Abort a specific build."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("reason", 25 | mcp.Description("Reason for aborting the build"), 26 | ), 27 | ), 28 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 29 | appSlug, err := request.RequireString("app_slug") 30 | if err != nil { 31 | return mcp.NewToolResultError(err.Error()), nil 32 | } 33 | buildSlug, err := request.RequireString("build_slug") 34 | if err != nil { 35 | return mcp.NewToolResultError(err.Error()), nil 36 | } 37 | 38 | body := map[string]any{} 39 | if v := request.GetString("reason", ""); v != "" { 40 | body["abort_reason"] = v 41 | } 42 | 43 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 44 | Method: http.MethodPost, 45 | BaseURL: bitrise.APIBaseURL, 46 | Path: fmt.Sprintf("/apps/%s/builds/%s/abort", appSlug, buildSlug), 47 | Body: body, 48 | }) 49 | if err != nil { 50 | return mcp.NewToolResultErrorFromErr("call api", err), nil 51 | } 52 | return mcp.NewToolResultText(res), nil 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/yosida95/uritemplate/v3/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016, Kohei YOSHIDA . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the copyright holder nor the names of its 12 | contributors may be used to endorse or promote products derived from 13 | this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /internal/tool/pipelines/abort.go: -------------------------------------------------------------------------------- 1 | package pipelines 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Abort = bitrise.Tool{ 13 | APIGroups: []string{"pipelines"}, 14 | Definition: mcp.NewTool("abort_pipeline", 15 | mcp.WithDescription("Abort a pipeline."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("pipeline_id", 21 | mcp.Description("Identifier of the pipeline"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("reason", 25 | mcp.Description("Reason for aborting the pipeline"), 26 | ), 27 | ), 28 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 29 | appSlug, err := request.RequireString("app_slug") 30 | if err != nil { 31 | return mcp.NewToolResultError(err.Error()), nil 32 | } 33 | pipelineID, err := request.RequireString("pipeline_id") 34 | if err != nil { 35 | return mcp.NewToolResultError(err.Error()), nil 36 | } 37 | 38 | body := map[string]any{} 39 | if v := request.GetString("reason", ""); v != "" { 40 | body["abort_reason"] = v 41 | } 42 | 43 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 44 | Method: http.MethodPost, 45 | BaseURL: bitrise.APIBaseURL, 46 | Path: fmt.Sprintf("/apps/%s/pipelines/%s/abort", appSlug, pipelineID), 47 | Body: body, 48 | }) 49 | if err != nil { 50 | return mcp.NewToolResultErrorFromErr("call api", err), nil 51 | } 52 | return mcp.NewToolResultText(res), nil 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /internal/tool/apps/update_bitrise_yml.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var UpdateBitriseYML = bitrise.Tool{ 13 | APIGroups: []string{"apps"}, 14 | Definition: mcp.NewTool("update_bitrise_yml", 15 | mcp.WithDescription("Update the Bitrise YML config file of a specified Bitrise app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app (e.g., \"d8db74e2675d54c4\" or \"8eb495d0-f653-4eed-910b-8d6b56cc0ec7\")"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("bitrise_yml_as_json", 21 | mcp.Description("The new Bitrise YML config file content to be updated. It must be a string."), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | appSlug, err := request.RequireString("app_slug") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | ymlContent, err := request.RequireString("bitrise_yml_as_json") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodPost, 37 | BaseURL: bitrise.APIBaseURL, 38 | Path: fmt.Sprintf("/apps/%s/bitrise.yml", appSlug), 39 | Body: map[string]any{ 40 | "app_config_datastore_yaml": ymlContent, 41 | }, 42 | }) 43 | if err != nil { 44 | return mcp.NewToolResultErrorFromErr("call api", err), nil 45 | } 46 | return mcp.NewToolResultText(res), nil 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // # Note 4 | // 5 | // All functions in this package return a bool value indicating whether the assertion has passed. 6 | // 7 | // # Example Usage 8 | // 9 | // The following is a complete example using assert in a standard test function: 10 | // 11 | // import ( 12 | // "testing" 13 | // "github.com/stretchr/testify/assert" 14 | // ) 15 | // 16 | // func TestSomething(t *testing.T) { 17 | // 18 | // var a string = "Hello" 19 | // var b string = "Hello" 20 | // 21 | // assert.Equal(t, a, b, "The two words should be the same.") 22 | // 23 | // } 24 | // 25 | // if you assert many times, use the format below: 26 | // 27 | // import ( 28 | // "testing" 29 | // "github.com/stretchr/testify/assert" 30 | // ) 31 | // 32 | // func TestSomething(t *testing.T) { 33 | // assert := assert.New(t) 34 | // 35 | // var a string = "Hello" 36 | // var b string = "Hello" 37 | // 38 | // assert.Equal(a, b, "The two words should be the same.") 39 | // } 40 | // 41 | // # Assertions 42 | // 43 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 44 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 45 | // testing framework. This allows the assertion funcs to write the failings and other details to 46 | // the correct place. 47 | // 48 | // Every assertion function also takes an optional string message as the final argument, 49 | // allowing custom error messages to be appended to the message the assertion method outputs. 50 | package assert 51 | -------------------------------------------------------------------------------- /vendor/github.com/wk8/go-ordered-map/v2/.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | tests: false 3 | 4 | linters: 5 | disable-all: true 6 | enable: 7 | - asciicheck 8 | - bidichk 9 | - bodyclose 10 | - containedctx 11 | - contextcheck 12 | - decorder 13 | - depguard 14 | - dogsled 15 | - dupl 16 | - durationcheck 17 | - errcheck 18 | - errchkjson 19 | # FIXME: commented out as it crashes with 1.18 for now 20 | # - errname 21 | - errorlint 22 | - exportloopref 23 | - forbidigo 24 | - funlen 25 | - gci 26 | - gochecknoglobals 27 | - gochecknoinits 28 | - gocognit 29 | - goconst 30 | - gocritic 31 | - gocyclo 32 | - godox 33 | - gofmt 34 | - gofumpt 35 | - goheader 36 | - goimports 37 | - gomnd 38 | - gomoddirectives 39 | - gomodguard 40 | - goprintffuncname 41 | - gosec 42 | - gosimple 43 | - govet 44 | - grouper 45 | - ifshort 46 | - importas 47 | - ineffassign 48 | - lll 49 | - maintidx 50 | - makezero 51 | - misspell 52 | - nakedret 53 | - nilerr 54 | - nilnil 55 | - noctx 56 | - nolintlint 57 | - paralleltest 58 | - prealloc 59 | - predeclared 60 | - promlinter 61 | # FIXME: doesn't support 1.18 yet 62 | # - revive 63 | - rowserrcheck 64 | - sqlclosecheck 65 | - staticcheck 66 | - structcheck 67 | - stylecheck 68 | - tagliatelle 69 | - tenv 70 | - testpackage 71 | - thelper 72 | - tparallel 73 | - typecheck 74 | - unconvert 75 | - unparam 76 | - unused 77 | - varcheck 78 | - varnamelen 79 | - wastedassign 80 | - whitespace 81 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go: -------------------------------------------------------------------------------- 1 | //go:build !testify_yaml_fail && !testify_yaml_custom 2 | 3 | // Package yaml is just an indirection to handle YAML deserialization. 4 | // 5 | // This package is just an indirection that allows the builder to override the 6 | // indirection with an alternative implementation of this package that uses 7 | // another implementation of YAML deserialization. This allows to not either not 8 | // use YAML deserialization at all, or to use another implementation than 9 | // [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]). 10 | // 11 | // Alternative implementations are selected using build tags: 12 | // 13 | // - testify_yaml_fail: [Unmarshal] always fails with an error 14 | // - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it 15 | // before calling any of [github.com/stretchr/testify/assert.YAMLEq] or 16 | // [github.com/stretchr/testify/assert.YAMLEqf]. 17 | // 18 | // Usage: 19 | // 20 | // go test -tags testify_yaml_fail 21 | // 22 | // You can check with "go list" which implementation is linked: 23 | // 24 | // go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 25 | // go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 26 | // go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 27 | // 28 | // [PR #1120]: https://github.com/stretchr/testify/pull/1120 29 | package yaml 30 | 31 | import goyaml "gopkg.in/yaml.v3" 32 | 33 | // Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal]. 34 | func Unmarshal(in []byte, out interface{}) error { 35 | return goyaml.Unmarshal(in, out) 36 | } 37 | -------------------------------------------------------------------------------- /internal/tool/artifacts/delete.go: -------------------------------------------------------------------------------- 1 | package artifacts 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Delete = bitrise.Tool{ 13 | APIGroups: []string{"artifacts"}, 14 | Definition: mcp.NewTool("delete_artifact", 15 | mcp.WithDescription("Delete a build artifact."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("artifact_slug", 25 | mcp.Description("Identifier of the artifact"), 26 | mcp.Required(), 27 | ), 28 | ), 29 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 30 | appSlug, err := request.RequireString("app_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | buildSlug, err := request.RequireString("build_slug") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | artifactSlug, err := request.RequireString("artifact_slug") 39 | if err != nil { 40 | return mcp.NewToolResultError(err.Error()), nil 41 | } 42 | 43 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 44 | Method: http.MethodDelete, 45 | BaseURL: bitrise.APIBaseURL, 46 | Path: fmt.Sprintf("/apps/%s/builds/%s/artifacts/%s", appSlug, buildSlug, artifactSlug), 47 | }) 48 | if err != nil { 49 | return mcp.NewToolResultErrorFromErr("call api", err), nil 50 | } 51 | return mcp.NewToolResultText(res), nil 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/internal/tz.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import "time" 4 | 5 | // Timezones used for local datetime, date, and time TOML types. 6 | // 7 | // The exact way times and dates without a timezone should be interpreted is not 8 | // well-defined in the TOML specification and left to the implementation. These 9 | // defaults to current local timezone offset of the computer, but this can be 10 | // changed by changing these variables before decoding. 11 | // 12 | // TODO: 13 | // Ideally we'd like to offer people the ability to configure the used timezone 14 | // by setting Decoder.Timezone and Encoder.Timezone; however, this is a bit 15 | // tricky: the reason we use three different variables for this is to support 16 | // round-tripping – without these specific TZ names we wouldn't know which 17 | // format to use. 18 | // 19 | // There isn't a good way to encode this right now though, and passing this sort 20 | // of information also ties in to various related issues such as string format 21 | // encoding, encoding of comments, etc. 22 | // 23 | // So, for the time being, just put this in internal until we can write a good 24 | // comprehensive API for doing all of this. 25 | // 26 | // The reason they're exported is because they're referred from in e.g. 27 | // internal/tag. 28 | // 29 | // Note that this behaviour is valid according to the TOML spec as the exact 30 | // behaviour is left up to implementations. 31 | var ( 32 | localOffset = func() int { _, o := time.Now().Zone(); return o }() 33 | LocalDatetime = time.FixedZone("datetime-local", localOffset) 34 | LocalDate = time.FixedZone("date-local", localOffset) 35 | LocalTime = time.FixedZone("time-local", localOffset) 36 | ) 37 | -------------------------------------------------------------------------------- /internal/tool/artifacts/get.go: -------------------------------------------------------------------------------- 1 | package artifacts 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Get = bitrise.Tool{ 13 | APIGroups: []string{"artifacts", "read-only"}, 14 | Definition: mcp.NewTool("get_artifact", 15 | mcp.WithDescription("Get a specific build artifact."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("artifact_slug", 25 | mcp.Description("Identifier of the artifact"), 26 | mcp.Required(), 27 | ), 28 | ), 29 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 30 | appSlug, err := request.RequireString("app_slug") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | buildSlug, err := request.RequireString("build_slug") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | artifactSlug, err := request.RequireString("artifact_slug") 39 | if err != nil { 40 | return mcp.NewToolResultError(err.Error()), nil 41 | } 42 | 43 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 44 | Method: http.MethodGet, 45 | BaseURL: bitrise.APIBaseURL, 46 | Path: fmt.Sprintf("/apps/%s/builds/%s/artifacts/%s", appSlug, buildSlug, artifactSlug), 47 | }) 48 | if err != nil { 49 | return mcp.NewToolResultErrorFromErr("call api", err), nil 50 | } 51 | return mcp.NewToolResultText(res), nil 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/internal/color/color.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | // Package color adds coloring functionality for TTY output. 22 | package color 23 | 24 | import "fmt" 25 | 26 | // Foreground colors. 27 | const ( 28 | Black Color = iota + 30 29 | Red 30 | Green 31 | Yellow 32 | Blue 33 | Magenta 34 | Cyan 35 | White 36 | ) 37 | 38 | // Color represents a text color. 39 | type Color uint8 40 | 41 | // Add adds the coloring to the given string. 42 | func (c Color) Add(s string) string { 43 | return fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(c), s) 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/sql.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "database/sql/driver" 9 | "fmt" 10 | ) 11 | 12 | // Scan implements sql.Scanner so UUIDs can be read from databases transparently. 13 | // Currently, database types that map to string and []byte are supported. Please 14 | // consult database-specific driver documentation for matching types. 15 | func (uuid *UUID) Scan(src interface{}) error { 16 | switch src := src.(type) { 17 | case nil: 18 | return nil 19 | 20 | case string: 21 | // if an empty UUID comes from a table, we return a null UUID 22 | if src == "" { 23 | return nil 24 | } 25 | 26 | // see Parse for required string format 27 | u, err := Parse(src) 28 | if err != nil { 29 | return fmt.Errorf("Scan: %v", err) 30 | } 31 | 32 | *uuid = u 33 | 34 | case []byte: 35 | // if an empty UUID comes from a table, we return a null UUID 36 | if len(src) == 0 { 37 | return nil 38 | } 39 | 40 | // assumes a simple slice of bytes if 16 bytes 41 | // otherwise attempts to parse 42 | if len(src) != 16 { 43 | return uuid.Scan(string(src)) 44 | } 45 | copy((*uuid)[:], src) 46 | 47 | default: 48 | return fmt.Errorf("Scan: unable to scan type %T into UUID", src) 49 | } 50 | 51 | return nil 52 | } 53 | 54 | // Value implements sql.Valuer so that UUIDs can be written to databases 55 | // transparently. Currently, UUIDs map to strings. Please consult 56 | // database-specific driver documentation for matching types. 57 | func (uuid UUID) Value() (driver.Value, error) { 58 | return uuid.String(), nil 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/server/errors.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | // Common server errors 10 | ErrUnsupported = errors.New("not supported") 11 | ErrResourceNotFound = errors.New("resource not found") 12 | ErrPromptNotFound = errors.New("prompt not found") 13 | ErrToolNotFound = errors.New("tool not found") 14 | 15 | // Session-related errors 16 | ErrSessionNotFound = errors.New("session not found") 17 | ErrSessionExists = errors.New("session already exists") 18 | ErrSessionNotInitialized = errors.New("session not properly initialized") 19 | ErrSessionDoesNotSupportTools = errors.New("session does not support per-session tools") 20 | ErrSessionDoesNotSupportResources = errors.New("session does not support per-session resources") 21 | ErrSessionDoesNotSupportResourceTemplates = errors.New("session does not support resource templates") 22 | ErrSessionDoesNotSupportLogging = errors.New("session does not support setting logging level") 23 | 24 | // Notification-related errors 25 | ErrNotificationNotInitialized = errors.New("notification channel not initialized") 26 | ErrNotificationChannelBlocked = errors.New("notification channel queue is full - client may not be processing notifications fast enough") 27 | ) 28 | 29 | // ErrDynamicPathConfig is returned when attempting to use static path methods with dynamic path configuration 30 | type ErrDynamicPathConfig struct { 31 | Method string 32 | } 33 | 34 | func (e *ErrDynamicPathConfig) Error() string { 35 | return fmt.Sprintf("%s cannot be used with WithDynamicBasePath. Use dynamic path logic in your router.", e.Method) 36 | } 37 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/README.md: -------------------------------------------------------------------------------- 1 | # multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] 2 | 3 | `multierr` allows combining one or more Go `error`s together. 4 | 5 | ## Features 6 | 7 | - **Idiomatic**: 8 | multierr follows best practices in Go, and keeps your code idiomatic. 9 | - It keeps the underlying error type hidden, 10 | allowing you to deal in `error` values exclusively. 11 | - It provides APIs to safely append into an error from a `defer` statement. 12 | - **Performant**: 13 | multierr is optimized for performance: 14 | - It avoids allocations where possible. 15 | - It utilizes slice resizing semantics to optimize common cases 16 | like appending into the same error object from a loop. 17 | - **Interoperable**: 18 | multierr interoperates with the Go standard library's error APIs seamlessly: 19 | - The `errors.Is` and `errors.As` functions *just work*. 20 | - **Lightweight**: 21 | multierr comes with virtually no dependencies. 22 | 23 | ## Installation 24 | 25 | ```bash 26 | go get -u go.uber.org/multierr@latest 27 | ``` 28 | 29 | ## Status 30 | 31 | Stable: No breaking changes will be made before 2.0. 32 | 33 | ------------------------------------------------------------------------------- 34 | 35 | Released under the [MIT License]. 36 | 37 | [MIT License]: LICENSE.txt 38 | [doc-img]: https://pkg.go.dev/badge/go.uber.org/multierr 39 | [doc]: https://pkg.go.dev/go.uber.org/multierr 40 | [ci-img]: https://github.com/uber-go/multierr/actions/workflows/go.yml/badge.svg 41 | [cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg 42 | [ci]: https://github.com/uber-go/multierr/actions/workflows/go.yml 43 | [cov]: https://codecov.io/gh/uber-go/multierr 44 | -------------------------------------------------------------------------------- /internal/tool/grouproles/replace.go: -------------------------------------------------------------------------------- 1 | package grouproles 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Replace = bitrise.Tool{ 13 | APIGroups: []string{"group-roles"}, 14 | Definition: mcp.NewTool("replace_group_roles", 15 | mcp.WithDescription("Replace group roles for an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("role_name", 21 | mcp.Description("Name of the role"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithArray("group_slugs", 25 | mcp.Description("List of group slugs"), 26 | mcp.Required(), 27 | mcp.WithStringItems(), 28 | ), 29 | ), 30 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 31 | appSlug, err := request.RequireString("app_slug") 32 | if err != nil { 33 | return mcp.NewToolResultError(err.Error()), nil 34 | } 35 | roleName, err := request.RequireString("role_name") 36 | if err != nil { 37 | return mcp.NewToolResultError(err.Error()), nil 38 | } 39 | groupSlugs, err := request.RequireStringSlice("group_slugs") 40 | if err != nil { 41 | return mcp.NewToolResultError(err.Error()), nil 42 | } 43 | 44 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 45 | Method: http.MethodPut, 46 | BaseURL: bitrise.APIBaseURL, 47 | Path: fmt.Sprintf("/apps/%s/roles/%s", appSlug, roleName), 48 | Body: map[string]any{ 49 | "groups": groupSlugs, 50 | }, 51 | }) 52 | if err != nil { 53 | return mcp.NewToolResultErrorFromErr("call api", err), nil 54 | } 55 | return mcp.NewToolResultText(res), nil 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /vendor/github.com/wk8/go-ordered-map/v2/yaml.go: -------------------------------------------------------------------------------- 1 | package orderedmap 2 | 3 | import ( 4 | "fmt" 5 | 6 | "gopkg.in/yaml.v3" 7 | ) 8 | 9 | var ( 10 | _ yaml.Marshaler = &OrderedMap[int, any]{} 11 | _ yaml.Unmarshaler = &OrderedMap[int, any]{} 12 | ) 13 | 14 | // MarshalYAML implements the yaml.Marshaler interface. 15 | func (om *OrderedMap[K, V]) MarshalYAML() (interface{}, error) { 16 | if om == nil { 17 | return []byte("null"), nil 18 | } 19 | 20 | node := yaml.Node{ 21 | Kind: yaml.MappingNode, 22 | } 23 | 24 | for pair := om.Oldest(); pair != nil; pair = pair.Next() { 25 | key, value := pair.Key, pair.Value 26 | 27 | keyNode := &yaml.Node{} 28 | 29 | // serialize key to yaml, then deserialize it back into the node 30 | // this is a hack to get the correct tag for the key 31 | if err := keyNode.Encode(key); err != nil { 32 | return nil, err 33 | } 34 | 35 | valueNode := &yaml.Node{} 36 | if err := valueNode.Encode(value); err != nil { 37 | return nil, err 38 | } 39 | 40 | node.Content = append(node.Content, keyNode, valueNode) 41 | } 42 | 43 | return &node, nil 44 | } 45 | 46 | // UnmarshalYAML implements the yaml.Unmarshaler interface. 47 | func (om *OrderedMap[K, V]) UnmarshalYAML(value *yaml.Node) error { 48 | if value.Kind != yaml.MappingNode { 49 | return fmt.Errorf("pipeline must contain YAML mapping, has %v", value.Kind) 50 | } 51 | 52 | if om.list == nil { 53 | om.initialize(0) 54 | } 55 | 56 | for index := 0; index < len(value.Content); index += 2 { 57 | var key K 58 | var val V 59 | 60 | if err := value.Content[index].Decode(&key); err != nil { 61 | return err 62 | } 63 | if err := value.Content[index+1].Decode(&val); err != nil { 64 | return err 65 | } 66 | 67 | om.Set(key, val) 68 | } 69 | 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/internal/level_enabler.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | // Package internal and its subpackages hold types and functionality 22 | // that are not part of Zap's public API. 23 | package internal 24 | 25 | import "go.uber.org/zap/zapcore" 26 | 27 | // LeveledEnabler is an interface satisfied by LevelEnablers that are able to 28 | // report their own level. 29 | // 30 | // This interface is defined to use more conveniently in tests and non-zapcore 31 | // packages. 32 | // This cannot be imported from zapcore because of the cyclic dependency. 33 | type LeveledEnabler interface { 34 | zapcore.LevelEnabler 35 | 36 | Level() zapcore.Level 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) 4 | 5 | 6 | ### Features 7 | 8 | * add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) 14 | * Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) 15 | 16 | ## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) 17 | 18 | 19 | ### Features 20 | 21 | * Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) 22 | 23 | ## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) 24 | 25 | 26 | ### Features 27 | 28 | * UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) 29 | 30 | ### Fixes 31 | 32 | * Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) 33 | 34 | ## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) 40 | 41 | ## Changelog 42 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/flag.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package zap 22 | 23 | import ( 24 | "flag" 25 | 26 | "go.uber.org/zap/zapcore" 27 | ) 28 | 29 | // LevelFlag uses the standard library's flag.Var to declare a global flag 30 | // with the specified name, default, and usage guidance. The returned value is 31 | // a pointer to the value of the flag. 32 | // 33 | // If you don't want to use the flag package's global state, you can use any 34 | // non-nil *Level as a flag.Value with your own *flag.FlagSet. 35 | func LevelFlag(name string, defaultLevel zapcore.Level, usage string) *zapcore.Level { 36 | lvl := defaultLevel 37 | flag.Var(&lvl, name, usage) 38 | return &lvl 39 | } 40 | -------------------------------------------------------------------------------- /internal/tool/builds/get_build_log_test.go: -------------------------------------------------------------------------------- 1 | package builds 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestLogWindow_Peek(t *testing.T) { 10 | givenLog := "line1\nline2\nline3\nline4\nline5" 11 | cases := map[string]struct { 12 | given logWindow 13 | want GetBuildLogResponse 14 | }{ 15 | "read forward from start with limit less than total lines": { 16 | given: logWindow{ 17 | Log: givenLog, 18 | Offset: 0, 19 | Limit: 3, 20 | }, 21 | want: GetBuildLogResponse{ 22 | LogLines: "line1\nline2\nline3", 23 | NextOffset: 3, 24 | TotalLines: 5, 25 | }, 26 | }, 27 | "continue reading": { 28 | given: logWindow{ 29 | Log: givenLog, 30 | Offset: 3, 31 | Limit: 3, 32 | }, 33 | want: GetBuildLogResponse{ 34 | LogLines: "line4\nline5", 35 | TotalLines: 5, 36 | }, 37 | }, 38 | "offset is outside bounds": { 39 | given: logWindow{ 40 | Log: givenLog, 41 | Offset: 10, 42 | Limit: 3, 43 | }, 44 | want: GetBuildLogResponse{ 45 | LogLines: "", 46 | TotalLines: 5, 47 | }, 48 | }, 49 | "read from end": { 50 | given: logWindow{ 51 | Log: givenLog, 52 | Offset: -1, 53 | Limit: 3, 54 | }, 55 | want: GetBuildLogResponse{ 56 | LogLines: "line3\nline4\nline5", 57 | NextOffset: -4, 58 | TotalLines: 5, 59 | }, 60 | }, 61 | "continue reading from end": { 62 | given: logWindow{ 63 | Log: givenLog, 64 | Offset: -4, 65 | Limit: 3, 66 | }, 67 | want: GetBuildLogResponse{ 68 | LogLines: "line1\nline2", 69 | TotalLines: 5, 70 | }, 71 | }, 72 | } 73 | 74 | for name, tc := range cases { 75 | t.Run(name, func(t *testing.T) { 76 | got := tc.given.Peek() 77 | assert.Equal(t, tc.want, got) 78 | }) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/zapcore/reflected_encoder.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package zapcore 22 | 23 | import ( 24 | "encoding/json" 25 | "io" 26 | ) 27 | 28 | // ReflectedEncoder serializes log fields that can't be serialized with Zap's 29 | // JSON encoder. These have the ReflectType field type. 30 | // Use EncoderConfig.NewReflectedEncoder to set this. 31 | type ReflectedEncoder interface { 32 | // Encode encodes and writes to the underlying data stream. 33 | Encode(interface{}) error 34 | } 35 | 36 | func defaultReflectedEncoder(w io.Writer) ReflectedEncoder { 37 | enc := json.NewEncoder(w) 38 | // For consistency with our custom JSON encoder. 39 | enc.SetEscapeHTML(false) 40 | return enc 41 | } 42 | -------------------------------------------------------------------------------- /vendor/go.uber.org/multierr/error_post_go120.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017-2023 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | //go:build go1.20 22 | // +build go1.20 23 | 24 | package multierr 25 | 26 | // Unwrap returns a list of errors wrapped by this multierr. 27 | func (merr *multiError) Unwrap() []error { 28 | return merr.Errors() 29 | } 30 | 31 | type multipleErrors interface { 32 | Unwrap() []error 33 | } 34 | 35 | func extractErrors(err error) []error { 36 | if err == nil { 37 | return nil 38 | } 39 | 40 | // check if the given err is an Unwrapable error that 41 | // implements multipleErrors interface. 42 | eg, ok := err.(multipleErrors) 43 | if !ok { 44 | return []error{err} 45 | } 46 | 47 | return append(([]error)(nil), eg.Unwrap()...) 48 | } 49 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/buffer/pool.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package buffer 22 | 23 | import ( 24 | "go.uber.org/zap/internal/pool" 25 | ) 26 | 27 | // A Pool is a type-safe wrapper around a sync.Pool. 28 | type Pool struct { 29 | p *pool.Pool[*Buffer] 30 | } 31 | 32 | // NewPool constructs a new Pool. 33 | func NewPool() Pool { 34 | return Pool{ 35 | p: pool.New(func() *Buffer { 36 | return &Buffer{ 37 | bs: make([]byte, 0, _size), 38 | } 39 | }), 40 | } 41 | } 42 | 43 | // Get retrieves a Buffer from the pool, creating one if necessary. 44 | func (p Pool) Get() *Buffer { 45 | buf := p.p.Get() 46 | buf.Reset() 47 | buf.pool = p 48 | return buf 49 | } 50 | 51 | func (p Pool) put(buf *Buffer) { 52 | p.p.Put(buf) 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe !go1.4 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /internal/tool/artifacts/list.go: -------------------------------------------------------------------------------- 1 | package artifacts 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | 9 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 10 | "github.com/mark3labs/mcp-go/mcp" 11 | ) 12 | 13 | var List = bitrise.Tool{ 14 | APIGroups: []string{"artifacts", "read-only"}, 15 | Definition: mcp.NewTool("list_artifacts", 16 | mcp.WithDescription("Get a list of all build artifacts."), 17 | mcp.WithString("app_slug", 18 | mcp.Description("Identifier of the Bitrise app"), 19 | mcp.Required(), 20 | ), 21 | mcp.WithString("build_slug", 22 | mcp.Description("Identifier of the build"), 23 | mcp.Required(), 24 | ), 25 | mcp.WithString("next", 26 | mcp.Description("Slug of the first artifact in the response"), 27 | ), 28 | mcp.WithNumber("limit", 29 | mcp.Description("Max number of elements per page (default: 50)"), 30 | ), 31 | ), 32 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 33 | appSlug, err := request.RequireString("app_slug") 34 | if err != nil { 35 | return mcp.NewToolResultError(err.Error()), nil 36 | } 37 | buildSlug, err := request.RequireString("build_slug") 38 | if err != nil { 39 | return mcp.NewToolResultError(err.Error()), nil 40 | } 41 | 42 | params := map[string]string{} 43 | if v := request.GetString("next", ""); v != "" { 44 | params["next"] = v 45 | } 46 | if _, ok := request.GetArguments()["limit"]; ok { 47 | params["limit"] = strconv.Itoa(request.GetInt("limit", 50)) 48 | } 49 | 50 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 51 | Method: http.MethodGet, 52 | BaseURL: bitrise.APIBaseURL, 53 | Path: fmt.Sprintf("/apps/%s/builds/%s/artifacts", appSlug, buildSlug), 54 | Params: params, 55 | }) 56 | if err != nil { 57 | return mcp.NewToolResultErrorFromErr("call api", err), nil 58 | } 59 | return mcp.NewToolResultText(res), nil 60 | }, 61 | } 62 | -------------------------------------------------------------------------------- /docs/install-vscode.md: -------------------------------------------------------------------------------- 1 | # Install Bitrise MCP Server in VS Code 2 | 3 | ## Prerequisites 4 | - [VS Code](https://code.visualstudio.com/Download) installed 5 | - [Create a Bitrise API Token](https://devcenter.bitrise.io/api/authentication): 6 | - Go to your [Bitrise Account Settings/Security](https://app.bitrise.io/me/account/security). 7 | - Navigate to the "Personal access tokens" section. 8 | - Copy the generated token. 9 | - For local setup: [Go](https://go.dev/) (>=1.25) installed 10 | 11 | ## Remote Server Setup (Streamable HTTP) 12 | 13 | Follow [VS Code | Add an MCP server](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_add-an-mcp-server) and add the following configuration to your settings: 14 | 15 | ```json 16 | { 17 | "servers": { 18 | "bitrise": { 19 | "type": "http", 20 | "url": "https://mcp.bitrise.io", 21 | "headers": { 22 | "Authorization": "Bearer ${input:bitrise-token}" 23 | } 24 | } 25 | }, 26 | "inputs": [ 27 | { 28 | "id": "bitrise-token", 29 | "type": "promptString", 30 | "description": "Bitrise token", 31 | "password": true 32 | } 33 | ] 34 | } 35 | ``` 36 | 37 | Save the configuration. VS Code will automatically recognize the change and load the tools into Copilot Chat. 38 | 39 | ## Local Server Setup (Go required) 40 | 41 | Do the same as above, but use the following configuration instead: 42 | 43 | ```json 44 | { 45 | "servers": { 46 | "bitrise-local": { 47 | "type": "stdio", 48 | "command": "go", 49 | "args": [ 50 | "run", 51 | "github.com/bitrise-io/bitrise-mcp/v2@v2" 52 | ], 53 | "env": { 54 | "BITRISE_TOKEN": "${input:bitrise-token}" 55 | } 56 | } 57 | }, 58 | "inputs": [ 59 | { 60 | "id": "bitrise-token", 61 | "type": "promptString", 62 | "description": "Bitrise token", 63 | "password": true 64 | } 65 | ] 66 | } 67 | ``` 68 | 69 | ## Advanced configuration 70 | 71 | See [Tools](/docs/tools.md) for enabling/disabling specific API groups. 72 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/get_installable_artifact_upload_and_proc_status.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var GetInstallableArtifactUploadAndProcessingStatus = bitrise.Tool{ 13 | APIGroups: []string{"release-management", "read-only"}, 14 | Definition: mcp.NewTool("get_installable_artifact_upload_and_proc_status", 15 | mcp.WithDescription("Gets the processing and upload status of an installable artifact. An artifact will need to be processed after upload to be usable. This endpoint helps understanding when an uploaded installable artifacts becomes usable for later purposes."), 16 | mcp.WithString("connected_app_id", 17 | mcp.Description("Identifier of the Release Management connected app for the installable artifact. This field is mandatory."), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("installable_artifact_id", 21 | mcp.Description("The uuidv4 identifier for the installable artifact. This field is mandatory."), 22 | mcp.Required(), 23 | ), 24 | ), 25 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 26 | connectedAppID, err := request.RequireString("connected_app_id") 27 | if err != nil { 28 | return mcp.NewToolResultError(err.Error()), nil 29 | } 30 | installableArtifactID, err := request.RequireString("installable_artifact_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | 35 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 36 | Method: http.MethodGet, 37 | BaseURL: bitrise.APIRMBaseURL, 38 | Path: fmt.Sprintf("/connected-apps/%s/installable-artifacts/%s/status", connectedAppID, installableArtifactID), 39 | }) 40 | if err != nil { 41 | return mcp.NewToolResultErrorFromErr("call api", err), nil 42 | } 43 | return mcp.NewToolResultText(res), nil 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/zapcore/level_strings.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package zapcore 22 | 23 | import "go.uber.org/zap/internal/color" 24 | 25 | var ( 26 | _levelToColor = map[Level]color.Color{ 27 | DebugLevel: color.Magenta, 28 | InfoLevel: color.Blue, 29 | WarnLevel: color.Yellow, 30 | ErrorLevel: color.Red, 31 | DPanicLevel: color.Red, 32 | PanicLevel: color.Red, 33 | FatalLevel: color.Red, 34 | } 35 | _unknownLevelColor = color.Red 36 | 37 | _levelToLowercaseColorString = make(map[Level]string, len(_levelToColor)) 38 | _levelToCapitalColorString = make(map[Level]string, len(_levelToColor)) 39 | ) 40 | 41 | func init() { 42 | for level, color := range _levelToColor { 43 | _levelToLowercaseColorString[level] = color.Add(level.String()) 44 | _levelToCapitalColorString[level] = color.Add(level.CapitalString()) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /internal/tool/apps/update.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Update = bitrise.Tool{ 13 | APIGroups: []string{"apps"}, 14 | Definition: mcp.NewTool("update_app", 15 | mcp.WithDescription("Update an app. Only app_slug is required. Omit all other fields you don't wish to update"), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithBoolean("is_public", 21 | mcp.Description("Whether the app's builds visibility is \"public\""), 22 | ), 23 | mcp.WithString("project_type", 24 | mcp.Description("Type of project"), 25 | ), 26 | mcp.WithString("provider", 27 | mcp.Description("Repository provider"), 28 | ), 29 | mcp.WithString("repo_url", 30 | mcp.Description("Repository URL"), 31 | ), 32 | ), 33 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 34 | appSlug, err := request.RequireString("app_slug") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | body := map[string]any{} 39 | if _, ok := request.GetArguments()["is_public"]; ok { 40 | body["is_public"] = request.GetBool("is_public", false) 41 | } 42 | if v := request.GetString("project_type", ""); v != "" { 43 | body["project_type"] = v 44 | } 45 | if v := request.GetString("provider", ""); v != "" { 46 | body["provider"] = v 47 | } 48 | if v := request.GetString("repo_url", ""); v != "" { 49 | body["repo_url"] = v 50 | } 51 | 52 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 53 | Method: http.MethodPatch, 54 | BaseURL: bitrise.APIBaseURL, 55 | Path: fmt.Sprintf("/apps/%s", appSlug), 56 | Body: body, 57 | }) 58 | if err != nil { 59 | return mcp.NewToolResultErrorFromErr("call api", err), nil 60 | } 61 | return mcp.NewToolResultText(res), nil 62 | }, 63 | } 64 | -------------------------------------------------------------------------------- /internal/tool/webhooks/create_outgoing.go: -------------------------------------------------------------------------------- 1 | package webhooks 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var CreateOutgoing = bitrise.Tool{ 13 | APIGroups: []string{"outgoing-webhooks"}, 14 | Definition: mcp.NewTool("create_outgoing_webhook", 15 | mcp.WithDescription("Create an outgoing webhook for an app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithArray("events", 21 | mcp.Description("List of events to trigger the webhook"), 22 | mcp.Required(), 23 | mcp.WithStringItems(), 24 | ), 25 | mcp.WithString("url", 26 | mcp.Description("URL of the webhook"), 27 | mcp.Required(), 28 | ), 29 | mcp.WithObject("headers", 30 | mcp.Description("Headers to be sent with the webhook"), 31 | ), 32 | ), 33 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 34 | appSlug, err := request.RequireString("app_slug") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | events, err := request.RequireStringSlice("events") 39 | if err != nil { 40 | return mcp.NewToolResultError(err.Error()), nil 41 | } 42 | url, err := request.RequireString("url") 43 | if err != nil { 44 | return mcp.NewToolResultError(err.Error()), nil 45 | } 46 | 47 | body := map[string]any{ 48 | "events": events, 49 | "url": url, 50 | } 51 | if v, ok := request.GetArguments()["headers"]; ok { 52 | body["headers"] = v 53 | } 54 | 55 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 56 | Method: http.MethodPost, 57 | BaseURL: bitrise.APIBaseURL, 58 | Path: fmt.Sprintf("/apps/%s/outgoing-webhooks", appSlug), 59 | Body: body, 60 | }) 61 | if err != nil { 62 | return mcp.NewToolResultErrorFromErr("call api", err), nil 63 | } 64 | return mcp.NewToolResultText(res), nil 65 | }, 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/invopop/jsonschema/.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | tests: true 3 | max-same-issues: 50 4 | 5 | output: 6 | print-issued-lines: false 7 | 8 | linters: 9 | enable: 10 | - gocyclo 11 | - gocritic 12 | - goconst 13 | - dupl 14 | - unconvert 15 | - goimports 16 | - unused 17 | - govet 18 | - nakedret 19 | - errcheck 20 | - revive 21 | - ineffassign 22 | - goconst 23 | - unparam 24 | - gofmt 25 | 26 | linters-settings: 27 | vet: 28 | check-shadowing: true 29 | use-installed-packages: true 30 | dupl: 31 | threshold: 100 32 | goconst: 33 | min-len: 8 34 | min-occurrences: 3 35 | gocyclo: 36 | min-complexity: 20 37 | gocritic: 38 | disabled-checks: 39 | - ifElseChain 40 | gofmt: 41 | rewrite-rules: 42 | - pattern: "interface{}" 43 | replacement: "any" 44 | - pattern: "a[b:len(a)]" 45 | replacement: "a[b:]" 46 | 47 | issues: 48 | max-per-linter: 0 49 | max-same: 0 50 | exclude-dirs: 51 | - resources 52 | - old 53 | exclude-files: 54 | - cmd/protopkg/main.go 55 | exclude-use-default: false 56 | exclude: 57 | # Captured by errcheck. 58 | - "^(G104|G204):" 59 | # Very commonly not checked. 60 | - 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*Print(f|ln|)|os\.(Un)?Setenv). is not checked' 61 | # Weird error only seen on Kochiku... 62 | - "internal error: no range for" 63 | - 'exported method `.*\.(MarshalJSON|UnmarshalJSON|URN|Payload|GoString|Close|Provides|Requires|ExcludeFromHash|MarshalText|UnmarshalText|Description|Check|Poll|Severity)` should have comment or be unexported' 64 | - "composite literal uses unkeyed fields" 65 | - 'declaration of "err" shadows declaration' 66 | - "by other packages, and that stutters" 67 | - "Potential file inclusion via variable" 68 | - "at least one file in a package should have a package comment" 69 | - "bad syntax for struct tag pair" 70 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/zapcore/lazy_with.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package zapcore 22 | 23 | import "sync" 24 | 25 | type lazyWithCore struct { 26 | Core 27 | sync.Once 28 | fields []Field 29 | } 30 | 31 | // NewLazyWith wraps a Core with a "lazy" Core that will only encode fields if 32 | // the logger is written to (or is further chained in a lon-lazy manner). 33 | func NewLazyWith(core Core, fields []Field) Core { 34 | return &lazyWithCore{ 35 | Core: core, 36 | fields: fields, 37 | } 38 | } 39 | 40 | func (d *lazyWithCore) initOnce() { 41 | d.Once.Do(func() { 42 | d.Core = d.Core.With(d.fields) 43 | }) 44 | } 45 | 46 | func (d *lazyWithCore) With(fields []Field) Core { 47 | d.initOnce() 48 | return d.Core.With(fields) 49 | } 50 | 51 | func (d *lazyWithCore) Check(e Entry, ce *CheckedEntry) *CheckedEntry { 52 | d.initOnce() 53 | return d.Core.Check(e, ce) 54 | } 55 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/writerc.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // Copyright (c) 2006-2010 Kirill Simonov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | // of the Software, and to permit persons to whom the Software is furnished to do 10 | // so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package yaml 24 | 25 | // Set the writer error and return false. 26 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 27 | emitter.error = yaml_WRITER_ERROR 28 | emitter.problem = problem 29 | return false 30 | } 31 | 32 | // Flush the output buffer. 33 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 34 | if emitter.write_handler == nil { 35 | panic("write handler not set") 36 | } 37 | 38 | // Check if the buffer is empty. 39 | if emitter.buffer_pos == 0 { 40 | return true 41 | } 42 | 43 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 44 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 45 | } 46 | emitter.buffer_pos = 0 47 | return true 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/buger/jsonparser/oss-fuzz-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | git clone https://github.com/dvyukov/go-fuzz-corpus 4 | zip corpus.zip go-fuzz-corpus/json/corpus/* 5 | 6 | cp corpus.zip $OUT/fuzzparsestring_seed_corpus.zip 7 | compile_go_fuzzer github.com/buger/jsonparser FuzzParseString fuzzparsestring 8 | 9 | cp corpus.zip $OUT/fuzzeachkey_seed_corpus.zip 10 | compile_go_fuzzer github.com/buger/jsonparser FuzzEachKey fuzzeachkey 11 | 12 | cp corpus.zip $OUT/fuzzdelete_seed_corpus.zip 13 | compile_go_fuzzer github.com/buger/jsonparser FuzzDelete fuzzdelete 14 | 15 | cp corpus.zip $OUT/fuzzset_seed_corpus.zip 16 | compile_go_fuzzer github.com/buger/jsonparser FuzzSet fuzzset 17 | 18 | cp corpus.zip $OUT/fuzzobjecteach_seed_corpus.zip 19 | compile_go_fuzzer github.com/buger/jsonparser FuzzObjectEach fuzzobjecteach 20 | 21 | cp corpus.zip $OUT/fuzzparsefloat_seed_corpus.zip 22 | compile_go_fuzzer github.com/buger/jsonparser FuzzParseFloat fuzzparsefloat 23 | 24 | cp corpus.zip $OUT/fuzzparseint_seed_corpus.zip 25 | compile_go_fuzzer github.com/buger/jsonparser FuzzParseInt fuzzparseint 26 | 27 | cp corpus.zip $OUT/fuzzparsebool_seed_corpus.zip 28 | compile_go_fuzzer github.com/buger/jsonparser FuzzParseBool fuzzparsebool 29 | 30 | cp corpus.zip $OUT/fuzztokenstart_seed_corpus.zip 31 | compile_go_fuzzer github.com/buger/jsonparser FuzzTokenStart fuzztokenstart 32 | 33 | cp corpus.zip $OUT/fuzzgetstring_seed_corpus.zip 34 | compile_go_fuzzer github.com/buger/jsonparser FuzzGetString fuzzgetstring 35 | 36 | cp corpus.zip $OUT/fuzzgetfloat_seed_corpus.zip 37 | compile_go_fuzzer github.com/buger/jsonparser FuzzGetFloat fuzzgetfloat 38 | 39 | cp corpus.zip $OUT/fuzzgetint_seed_corpus.zip 40 | compile_go_fuzzer github.com/buger/jsonparser FuzzGetInt fuzzgetint 41 | 42 | cp corpus.zip $OUT/fuzzgetboolean_seed_corpus.zip 43 | compile_go_fuzzer github.com/buger/jsonparser FuzzGetBoolean fuzzgetboolean 44 | 45 | cp corpus.zip $OUT/fuzzgetunsafestring_seed_corpus.zip 46 | compile_go_fuzzer github.com/buger/jsonparser FuzzGetUnsafeString fuzzgetunsafestring 47 | 48 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/zapcore/clock.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package zapcore 22 | 23 | import "time" 24 | 25 | // DefaultClock is the default clock used by Zap in operations that require 26 | // time. This clock uses the system clock for all operations. 27 | var DefaultClock = systemClock{} 28 | 29 | // Clock is a source of time for logged entries. 30 | type Clock interface { 31 | // Now returns the current local time. 32 | Now() time.Time 33 | 34 | // NewTicker returns *time.Ticker that holds a channel 35 | // that delivers "ticks" of a clock. 36 | NewTicker(time.Duration) *time.Ticker 37 | } 38 | 39 | // systemClock implements default Clock that uses system time. 40 | type systemClock struct{} 41 | 42 | func (systemClock) Now() time.Time { 43 | return time.Now() 44 | } 45 | 46 | func (systemClock) NewTicker(duration time.Duration) *time.Ticker { 47 | return time.NewTicker(duration) 48 | } 49 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/notify_tester_group.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var NotifyTesterGroup = bitrise.Tool{ 13 | APIGroups: []string{"release-management"}, 14 | Definition: mcp.NewTool("notify_tester_group", 15 | mcp.WithDescription("Notifies a tester group about a new test build."), 16 | mcp.WithString("connected_app_id", 17 | mcp.Description("The uuidV4 identifier of the related Release Management connected app."), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("id", 21 | mcp.Description("The uuidV4 identifier of the tester group whose members will be notified about the test build."), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("test_build_id", 25 | mcp.Description("The unique identifier of the test build what will be sent in the notification of the tester group."), 26 | mcp.Required(), 27 | ), 28 | ), 29 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 30 | connectedAppID, err := request.RequireString("connected_app_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | id, err := request.RequireString("id") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | testBuildID, err := request.RequireString("test_build_id") 39 | if err != nil { 40 | return mcp.NewToolResultError(err.Error()), nil 41 | } 42 | 43 | body := map[string]any{ 44 | "test_build_id": testBuildID, 45 | } 46 | 47 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 48 | Method: http.MethodPost, 49 | BaseURL: bitrise.APIRMBaseURL, 50 | Path: fmt.Sprintf("/connected-apps/%s/tester-groups/%s/notify", connectedAppID, id), 51 | Body: body, 52 | }) 53 | if err != nil { 54 | return mcp.NewToolResultErrorFromErr("call api", err), nil 55 | } 56 | return mcp.NewToolResultText(res), nil 57 | }, 58 | } 59 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/add_testers_to_tester_group.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var AddTestersToTesterGroup = bitrise.Tool{ 13 | APIGroups: []string{"release-management"}, 14 | Definition: mcp.NewTool("add_testers_to_tester_group", 15 | mcp.WithDescription("Adds testers to a tester group of a connected app."), 16 | mcp.WithString("connected_app_id", 17 | mcp.Description("The uuidV4 identifier of the related Release Management connected app."), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("id", 21 | mcp.Description("The uuidV4 identifier of the tester group to which testers will be added."), 22 | mcp.Required(), 23 | ), 24 | mcp.WithArray("user_slugs", 25 | mcp.Description("The list of users identified by slugs that will be added to the tester group."), 26 | mcp.Required(), 27 | mcp.WithStringItems(), 28 | ), 29 | ), 30 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 31 | connectedAppID, err := request.RequireString("connected_app_id") 32 | if err != nil { 33 | return mcp.NewToolResultError(err.Error()), nil 34 | } 35 | id, err := request.RequireString("id") 36 | if err != nil { 37 | return mcp.NewToolResultError(err.Error()), nil 38 | } 39 | userSlugs, err := request.RequireStringSlice("user_slugs") 40 | if err != nil { 41 | return mcp.NewToolResultError(err.Error()), nil 42 | } 43 | 44 | body := map[string]any{ 45 | "user_slugs": userSlugs, 46 | } 47 | 48 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 49 | Method: http.MethodPost, 50 | BaseURL: bitrise.APIRMBaseURL, 51 | Path: fmt.Sprintf("/connected-apps/%s/tester-groups/%s/add-testers", connectedAppID, id), 52 | Body: body, 53 | }) 54 | if err != nil { 55 | return mcp.NewToolResultErrorFromErr("call api", err), nil 56 | } 57 | return mcp.NewToolResultText(res), nil 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/list_tester_groups.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | 9 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 10 | "github.com/mark3labs/mcp-go/mcp" 11 | ) 12 | 13 | var ListTesterGroups = bitrise.Tool{ 14 | APIGroups: []string{"release-management", "read-only"}, 15 | Definition: mcp.NewTool("list_tester_groups", 16 | mcp.WithDescription("Gives back a list of tester groups related to a specific Release Management connected app."), 17 | mcp.WithString("connected_app_id", 18 | mcp.Description("The uuidV4 identifier of the app the tester group is connected to. This field is mandatory."), 19 | mcp.Required(), 20 | ), 21 | mcp.WithNumber("items_per_page", 22 | mcp.Description("Specifies the maximum number of tester groups to return related to a specific connected app. Default value is 10."), 23 | mcp.DefaultNumber(10), 24 | ), 25 | mcp.WithNumber("page", 26 | mcp.Description("Specifies which page should be returned from the whole result set in a paginated scenario. Default value is 1."), 27 | mcp.DefaultNumber(1), 28 | ), 29 | ), 30 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 31 | connectedAppID, err := request.RequireString("connected_app_id") 32 | if err != nil { 33 | return mcp.NewToolResultError(err.Error()), nil 34 | } 35 | 36 | params := map[string]string{} 37 | if v := request.GetInt("items_per_page", 10); v != 10 { 38 | params["items_per_page"] = strconv.Itoa(v) 39 | } 40 | if v := request.GetInt("page", 1); v != 1 { 41 | params["page"] = strconv.Itoa(v) 42 | } 43 | 44 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 45 | Method: http.MethodGet, 46 | BaseURL: bitrise.APIRMBaseURL, 47 | Path: fmt.Sprintf("/connected-apps/%s/tester-groups", connectedAppID), 48 | Params: params, 49 | }) 50 | if err != nil { 51 | return mcp.NewToolResultErrorFromErr("call api", err), nil 52 | } 53 | return mcp.NewToolResultText(res), nil 54 | }, 55 | } 56 | -------------------------------------------------------------------------------- /vendor/github.com/invopop/jsonschema/id.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/url" 7 | "strings" 8 | ) 9 | 10 | // ID represents a Schema ID type which should always be a URI. 11 | // See draft-bhutton-json-schema-00 section 8.2.1 12 | type ID string 13 | 14 | // EmptyID is used to explicitly define an ID with no value. 15 | const EmptyID ID = "" 16 | 17 | // Validate is used to check if the ID looks like a proper schema. 18 | // This is done by parsing the ID as a URL and checking it has all the 19 | // relevant parts. 20 | func (id ID) Validate() error { 21 | u, err := url.Parse(id.String()) 22 | if err != nil { 23 | return fmt.Errorf("invalid URL: %w", err) 24 | } 25 | if u.Hostname() == "" { 26 | return errors.New("missing hostname") 27 | } 28 | if !strings.Contains(u.Hostname(), ".") { 29 | return errors.New("hostname does not look valid") 30 | } 31 | if u.Path == "" { 32 | return errors.New("path is expected") 33 | } 34 | if u.Scheme != "https" && u.Scheme != "http" { 35 | return errors.New("unexpected schema") 36 | } 37 | return nil 38 | } 39 | 40 | // Anchor sets the anchor part of the schema URI. 41 | func (id ID) Anchor(name string) ID { 42 | b := id.Base() 43 | return ID(b.String() + "#" + name) 44 | } 45 | 46 | // Def adds or replaces a definition identifier. 47 | func (id ID) Def(name string) ID { 48 | b := id.Base() 49 | return ID(b.String() + "#/$defs/" + name) 50 | } 51 | 52 | // Add appends the provided path to the id, and removes any 53 | // anchor data that might be there. 54 | func (id ID) Add(path string) ID { 55 | b := id.Base() 56 | if !strings.HasPrefix(path, "/") { 57 | path = "/" + path 58 | } 59 | return ID(b.String() + path) 60 | } 61 | 62 | // Base removes any anchor information from the schema 63 | func (id ID) Base() ID { 64 | s := id.String() 65 | i := strings.LastIndex(s, "#") 66 | if i != -1 { 67 | s = s[0:i] 68 | } 69 | s = strings.TrimRight(s, "/") 70 | return ID(s) 71 | } 72 | 73 | // String provides string version of ID 74 | func (id ID) String() string { 75 | return string(id) 76 | } 77 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "io" 9 | ) 10 | 11 | // randomBits completely fills slice b with random data. 12 | func randomBits(b []byte) { 13 | if _, err := io.ReadFull(rander, b); err != nil { 14 | panic(err.Error()) // rand should never fail 15 | } 16 | } 17 | 18 | // xvalues returns the value of a byte as a hexadecimal digit or 255. 19 | var xvalues = [256]byte{ 20 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 21 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 22 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 23 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 24 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 25 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 26 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 27 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 28 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 29 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 30 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 32 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 33 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 34 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 35 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 36 | } 37 | 38 | // xtob converts hex characters x1 and x2 into a byte. 39 | func xtob(x1, x2 byte) (byte, bool) { 40 | b1 := xvalues[x1] 41 | b2 := xvalues[x2] 42 | return (b1 << 4) | b2, b1 != 255 && b2 != 255 43 | } 44 | -------------------------------------------------------------------------------- /internal/tool/artifacts/update.go: -------------------------------------------------------------------------------- 1 | package artifacts 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var Update = bitrise.Tool{ 13 | APIGroups: []string{"artifacts"}, 14 | Definition: mcp.NewTool("update_artifact", 15 | mcp.WithDescription("Update a build artifact."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("build_slug", 21 | mcp.Description("Identifier of the build"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("artifact_slug", 25 | mcp.Description("Identifier of the artifact"), 26 | mcp.Required(), 27 | ), 28 | mcp.WithBoolean("is_public_page_enabled", 29 | mcp.Description("Enable public page for the artifact"), 30 | mcp.Required(), 31 | ), 32 | ), 33 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 34 | appSlug, err := request.RequireString("app_slug") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | buildSlug, err := request.RequireString("build_slug") 39 | if err != nil { 40 | return mcp.NewToolResultError(err.Error()), nil 41 | } 42 | artifactSlug, err := request.RequireString("artifact_slug") 43 | if err != nil { 44 | return mcp.NewToolResultError(err.Error()), nil 45 | } 46 | isPublicPageEnabled, err := request.RequireBool("is_public_page_enabled") 47 | if err != nil { 48 | return mcp.NewToolResultError(err.Error()), nil 49 | } 50 | 51 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 52 | Method: http.MethodPatch, 53 | BaseURL: bitrise.APIBaseURL, 54 | Path: fmt.Sprintf("/apps/%s/builds/%s/artifacts/%s", appSlug, buildSlug, artifactSlug), 55 | Body: map[string]any{ 56 | "is_public_page_enabled": isPublicPageEnabled, 57 | }, 58 | }) 59 | if err != nil { 60 | return mcp.NewToolResultErrorFromErr("call api", err), nil 61 | } 62 | return mcp.NewToolResultText(res), nil 63 | }, 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/mark3labs/mcp-go/mcp/typed_tools.go: -------------------------------------------------------------------------------- 1 | package mcp 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | // TypedToolHandlerFunc is a function that handles a tool call with typed arguments 9 | type TypedToolHandlerFunc[T any] func(ctx context.Context, request CallToolRequest, args T) (*CallToolResult, error) 10 | 11 | // StructuredToolHandlerFunc is a function that handles a tool call with typed arguments and returns structured output 12 | type StructuredToolHandlerFunc[TArgs any, TResult any] func(ctx context.Context, request CallToolRequest, args TArgs) (TResult, error) 13 | 14 | // NewTypedToolHandler creates a ToolHandlerFunc that automatically binds arguments to a typed struct 15 | func NewTypedToolHandler[T any](handler TypedToolHandlerFunc[T]) func(ctx context.Context, request CallToolRequest) (*CallToolResult, error) { 16 | return func(ctx context.Context, request CallToolRequest) (*CallToolResult, error) { 17 | var args T 18 | if err := request.BindArguments(&args); err != nil { 19 | return NewToolResultError(fmt.Sprintf("failed to bind arguments: %v", err)), nil 20 | } 21 | return handler(ctx, request, args) 22 | } 23 | } 24 | 25 | // NewStructuredToolHandler creates a ToolHandlerFunc that automatically binds arguments to a typed struct 26 | // and returns structured output. It automatically creates both structured and 27 | // text content (from the structured output) for backwards compatibility. 28 | func NewStructuredToolHandler[TArgs any, TResult any](handler StructuredToolHandlerFunc[TArgs, TResult]) func(ctx context.Context, request CallToolRequest) (*CallToolResult, error) { 29 | return func(ctx context.Context, request CallToolRequest) (*CallToolResult, error) { 30 | var args TArgs 31 | if err := request.BindArguments(&args); err != nil { 32 | return NewToolResultError(fmt.Sprintf("failed to bind arguments: %v", err)), nil 33 | } 34 | 35 | result, err := handler(ctx, request, args) 36 | if err != nil { 37 | return NewToolResultError(fmt.Sprintf("tool execution failed: %v", err)), nil 38 | } 39 | 40 | return NewToolResultStructuredOnly(result), nil 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/Makefile: -------------------------------------------------------------------------------- 1 | # Directory containing the Makefile. 2 | PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 3 | 4 | export GOBIN ?= $(PROJECT_ROOT)/bin 5 | export PATH := $(GOBIN):$(PATH) 6 | 7 | GOVULNCHECK = $(GOBIN)/govulncheck 8 | BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem 9 | 10 | # Directories containing independent Go modules. 11 | MODULE_DIRS = . ./exp ./benchmarks ./zapgrpc/internal/test 12 | 13 | # Directories that we want to track coverage for. 14 | COVER_DIRS = . ./exp 15 | 16 | .PHONY: all 17 | all: lint test 18 | 19 | .PHONY: lint 20 | lint: golangci-lint tidy-lint license-lint 21 | 22 | .PHONY: golangci-lint 23 | golangci-lint: 24 | @$(foreach mod,$(MODULE_DIRS), \ 25 | (cd $(mod) && \ 26 | echo "[lint] golangci-lint: $(mod)" && \ 27 | golangci-lint run --path-prefix $(mod)) &&) true 28 | 29 | .PHONY: tidy 30 | tidy: 31 | @$(foreach dir,$(MODULE_DIRS), \ 32 | (cd $(dir) && go mod tidy) &&) true 33 | 34 | .PHONY: tidy-lint 35 | tidy-lint: 36 | @$(foreach mod,$(MODULE_DIRS), \ 37 | (cd $(mod) && \ 38 | echo "[lint] tidy: $(mod)" && \ 39 | go mod tidy && \ 40 | git diff --exit-code -- go.mod go.sum) &&) true 41 | 42 | 43 | .PHONY: license-lint 44 | license-lint: 45 | ./checklicense.sh 46 | 47 | $(GOVULNCHECK): 48 | cd tools && go install golang.org/x/vuln/cmd/govulncheck 49 | 50 | .PHONY: test 51 | test: 52 | @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go test -race ./...) &&) true 53 | 54 | .PHONY: cover 55 | cover: 56 | @$(foreach dir,$(COVER_DIRS), ( \ 57 | cd $(dir) && \ 58 | go test -race -coverprofile=cover.out -coverpkg=./... ./... \ 59 | && go tool cover -html=cover.out -o cover.html) &&) true 60 | 61 | .PHONY: bench 62 | BENCH ?= . 63 | bench: 64 | @$(foreach dir,$(MODULE_DIRS), ( \ 65 | cd $(dir) && \ 66 | go list ./... | xargs -n1 go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) \ 67 | ) &&) true 68 | 69 | .PHONY: updatereadme 70 | updatereadme: 71 | rm -f README.md 72 | cat .readme.tmpl | go run internal/readme/readme.go > README.md 73 | 74 | .PHONY: vulncheck 75 | vulncheck: $(GOVULNCHECK) 76 | $(GOVULNCHECK) ./... 77 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/BurntSushi/toml v1.5.0 2 | ## explicit; go 1.18 3 | github.com/BurntSushi/toml 4 | github.com/BurntSushi/toml/internal 5 | # github.com/bahlo/generic-list-go v0.2.0 6 | ## explicit; go 1.18 7 | github.com/bahlo/generic-list-go 8 | # github.com/buger/jsonparser v1.1.1 9 | ## explicit; go 1.13 10 | github.com/buger/jsonparser 11 | # github.com/davecgh/go-spew v1.1.1 12 | ## explicit 13 | github.com/davecgh/go-spew/spew 14 | # github.com/google/uuid v1.6.0 15 | ## explicit 16 | github.com/google/uuid 17 | # github.com/invopop/jsonschema v0.13.0 18 | ## explicit; go 1.18 19 | github.com/invopop/jsonschema 20 | # github.com/jinzhu/configor v1.2.2 21 | ## explicit; go 1.16 22 | github.com/jinzhu/configor 23 | # github.com/mailru/easyjson v0.9.1 24 | ## explicit; go 1.20 25 | github.com/mailru/easyjson/buffer 26 | github.com/mailru/easyjson/jwriter 27 | # github.com/mark3labs/mcp-go v0.43.0 28 | ## explicit; go 1.23.0 29 | github.com/mark3labs/mcp-go/mcp 30 | github.com/mark3labs/mcp-go/server 31 | github.com/mark3labs/mcp-go/util 32 | # github.com/pmezard/go-difflib v1.0.0 33 | ## explicit 34 | github.com/pmezard/go-difflib/difflib 35 | # github.com/spf13/cast v1.10.0 36 | ## explicit; go 1.21.0 37 | github.com/spf13/cast 38 | github.com/spf13/cast/internal 39 | # github.com/stretchr/testify v1.11.1 40 | ## explicit; go 1.17 41 | github.com/stretchr/testify/assert 42 | github.com/stretchr/testify/assert/yaml 43 | # github.com/wk8/go-ordered-map/v2 v2.1.8 44 | ## explicit; go 1.18 45 | github.com/wk8/go-ordered-map/v2 46 | # github.com/yosida95/uritemplate/v3 v3.0.2 47 | ## explicit; go 1.14 48 | github.com/yosida95/uritemplate/v3 49 | # go.uber.org/multierr v1.11.0 50 | ## explicit; go 1.19 51 | go.uber.org/multierr 52 | # go.uber.org/zap v1.27.0 53 | ## explicit; go 1.19 54 | go.uber.org/zap 55 | go.uber.org/zap/buffer 56 | go.uber.org/zap/internal 57 | go.uber.org/zap/internal/bufferpool 58 | go.uber.org/zap/internal/color 59 | go.uber.org/zap/internal/exit 60 | go.uber.org/zap/internal/pool 61 | go.uber.org/zap/internal/stacktrace 62 | go.uber.org/zap/zapcore 63 | # gopkg.in/yaml.v3 v3.0.1 64 | ## explicit 65 | gopkg.in/yaml.v3 66 | -------------------------------------------------------------------------------- /internal/tool/webhooks/update_outgoing.go: -------------------------------------------------------------------------------- 1 | package webhooks 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var UpdateOutgoing = bitrise.Tool{ 13 | APIGroups: []string{"outgoing-webhooks"}, 14 | Definition: mcp.NewTool("update_outgoing_webhook", 15 | mcp.WithDescription("Update an outgoing webhook for an app. Even if you do not want to change one of the parameters, you still have to provide that parameter as well: simply use its existing value."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("webhook_slug", 21 | mcp.Description("Identifier of the webhook"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithArray("events", 25 | mcp.Description("List of events to trigger the webhook"), 26 | mcp.WithStringItems(), 27 | ), 28 | mcp.WithString("url", 29 | mcp.Description("URL of the webhook"), 30 | ), 31 | mcp.WithObject("headers", 32 | mcp.Description("Headers to be sent with the webhook"), 33 | ), 34 | ), 35 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 36 | appSlug, err := request.RequireString("app_slug") 37 | if err != nil { 38 | return mcp.NewToolResultError(err.Error()), nil 39 | } 40 | webhookSlug, err := request.RequireString("webhook_slug") 41 | if err != nil { 42 | return mcp.NewToolResultError(err.Error()), nil 43 | } 44 | 45 | body := map[string]any{} 46 | body["events"] = request.GetStringSlice("events", nil) 47 | body["url"] = request.GetString("url", "") 48 | body["headers"] = request.GetArguments()["headers"] 49 | 50 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 51 | Method: http.MethodPatch, 52 | BaseURL: bitrise.APIBaseURL, 53 | Path: fmt.Sprintf("/apps/%s/outgoing-webhooks/%s", appSlug, webhookSlug), 54 | Body: body, 55 | }) 56 | if err != nil { 57 | return mcp.NewToolResultErrorFromErr("call api", err), nil 58 | } 59 | return mcp.NewToolResultText(res), nil 60 | }, 61 | } 62 | -------------------------------------------------------------------------------- /internal/tool/apps/register_ssh_key.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var RegisterSSHKey = bitrise.Tool{ 13 | APIGroups: []string{"apps"}, 14 | Definition: mcp.NewTool("register_ssh_key", 15 | mcp.WithDescription("Add an SSH-key to a specific app."), 16 | mcp.WithString("app_slug", 17 | mcp.Description("Identifier of the Bitrise app"), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("auth_ssh_private_key", 21 | mcp.Description("Private SSH key"), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("auth_ssh_public_key", 25 | mcp.Description("Public SSH key"), 26 | mcp.Required(), 27 | ), 28 | mcp.WithBoolean("is_register_key_into_provider_service", 29 | mcp.Description("Register the key in the provider service"), 30 | ), 31 | ), 32 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 33 | appSlug, err := request.RequireString("app_slug") 34 | if err != nil { 35 | return mcp.NewToolResultError(err.Error()), nil 36 | } 37 | privateKey, err := request.RequireString("auth_ssh_private_key") 38 | if err != nil { 39 | return mcp.NewToolResultError(err.Error()), nil 40 | } 41 | publicKey, err := request.RequireString("auth_ssh_public_key") 42 | if err != nil { 43 | return mcp.NewToolResultError(err.Error()), nil 44 | } 45 | body := map[string]any{ 46 | "auth_ssh_private_key": privateKey, 47 | "auth_ssh_public_key": publicKey, 48 | } 49 | regKey := "is_register_key_into_provider_service" 50 | if _, ok := request.GetArguments()[regKey]; ok { 51 | body[regKey] = request.GetBool(regKey, false) 52 | } 53 | 54 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 55 | Method: http.MethodPost, 56 | BaseURL: bitrise.APIBaseURL, 57 | Path: fmt.Sprintf("/apps/%s/register-ssh-key", appSlug), 58 | Body: body, 59 | }) 60 | if err != nil { 61 | return mcp.NewToolResultErrorFromErr("call api", err), nil 62 | } 63 | return mcp.NewToolResultText(res), nil 64 | }, 65 | } 66 | -------------------------------------------------------------------------------- /internal/bitrise/call_api.go: -------------------------------------------------------------------------------- 1 | package bitrise 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | "io" 10 | "net/http" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | const ( 16 | APIBaseURL = "https://api.bitrise.io/v0.1" 17 | APIRMBaseURL = "https://api.bitrise.io/release-management/v1" 18 | userAgent = "bitrise-mcp/1.0" 19 | ) 20 | 21 | type CallAPIParams struct { 22 | Method string 23 | BaseURL string 24 | Path string 25 | Params map[string]string 26 | Body any 27 | } 28 | 29 | func CallAPI(ctx context.Context, p CallAPIParams) (string, error) { 30 | apiKey, err := patFromCtx(ctx) 31 | if err != nil { 32 | return "", errors.New("set authorization header to your bitrise pat") 33 | } 34 | 35 | var reqBody io.Reader 36 | if p.Body != nil { 37 | a, err := json.Marshal(p.Body) 38 | if err != nil { 39 | return "", fmt.Errorf("marshal request body: %w", err) 40 | } 41 | reqBody = bytes.NewBuffer(a) 42 | } 43 | 44 | fullURL := p.BaseURL 45 | if !strings.HasPrefix(p.Path, "/") { 46 | fullURL += "/" 47 | } 48 | fullURL += p.Path 49 | 50 | req, err := http.NewRequest(p.Method, fullURL, reqBody) 51 | if err != nil { 52 | return "", fmt.Errorf("create request: %w", err) 53 | } 54 | if p.Params != nil { 55 | q := req.URL.Query() 56 | for key, value := range p.Params { 57 | q.Add(key, value) 58 | } 59 | req.URL.RawQuery = q.Encode() 60 | } 61 | req.Header.Set("User-Agent", userAgent) 62 | req.Header.Set("Accept", "application/json") 63 | req.Header.Set("Content-Type", "application/json") 64 | req.Header.Set("Authorization", apiKey) 65 | 66 | client := http.Client{Timeout: 30 * time.Second} 67 | res, err := client.Do(req) 68 | if err != nil { 69 | return "", fmt.Errorf("execute request: %w", err) 70 | } 71 | defer res.Body.Close() 72 | if res.StatusCode >= 400 { 73 | resBody, _ := io.ReadAll(res.Body) 74 | return "", fmt.Errorf( 75 | "unexpected status code %d; response body: %s", 76 | res.StatusCode, resBody, 77 | ) 78 | } 79 | resBody, err := io.ReadAll(res.Body) 80 | if err != nil { 81 | return "", fmt.Errorf("read response body: %w", err) 82 | } 83 | return string(resBody), nil 84 | } 85 | -------------------------------------------------------------------------------- /vendor/go.uber.org/zap/internal/pool/pool.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | // Package pool provides internal pool utilities. 22 | package pool 23 | 24 | import ( 25 | "sync" 26 | ) 27 | 28 | // A Pool is a generic wrapper around [sync.Pool] to provide strongly-typed 29 | // object pooling. 30 | // 31 | // Note that SA6002 (ref: https://staticcheck.io/docs/checks/#SA6002) will 32 | // not be detected, so all internal pool use must take care to only store 33 | // pointer types. 34 | type Pool[T any] struct { 35 | pool sync.Pool 36 | } 37 | 38 | // New returns a new [Pool] for T, and will use fn to construct new Ts when 39 | // the pool is empty. 40 | func New[T any](fn func() T) *Pool[T] { 41 | return &Pool[T]{ 42 | pool: sync.Pool{ 43 | New: func() any { 44 | return fn() 45 | }, 46 | }, 47 | } 48 | } 49 | 50 | // Get gets a T from the pool, or creates a new one if the pool is empty. 51 | func (p *Pool[T]) Get() T { 52 | return p.pool.Get().(T) 53 | } 54 | 55 | // Put returns x into the pool. 56 | func (p *Pool[T]) Put(x T) { 57 | p.pool.Put(x) 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/google/uuid/hash.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "crypto/md5" 9 | "crypto/sha1" 10 | "hash" 11 | ) 12 | 13 | // Well known namespace IDs and UUIDs 14 | var ( 15 | NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) 16 | NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) 17 | NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) 18 | NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) 19 | Nil UUID // empty UUID, all zeros 20 | 21 | // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. 22 | Max = UUID{ 23 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 24 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 25 | } 26 | ) 27 | 28 | // NewHash returns a new UUID derived from the hash of space concatenated with 29 | // data generated by h. The hash should be at least 16 byte in length. The 30 | // first 16 bytes of the hash are used to form the UUID. The version of the 31 | // UUID will be the lower 4 bits of version. NewHash is used to implement 32 | // NewMD5 and NewSHA1. 33 | func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { 34 | h.Reset() 35 | h.Write(space[:]) //nolint:errcheck 36 | h.Write(data) //nolint:errcheck 37 | s := h.Sum(nil) 38 | var uuid UUID 39 | copy(uuid[:], s) 40 | uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) 41 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant 42 | return uuid 43 | } 44 | 45 | // NewMD5 returns a new MD5 (Version 3) UUID based on the 46 | // supplied name space and data. It is the same as calling: 47 | // 48 | // NewHash(md5.New(), space, data, 3) 49 | func NewMD5(space UUID, data []byte) UUID { 50 | return NewHash(md5.New(), space, data, 3) 51 | } 52 | 53 | // NewSHA1 returns a new SHA1 (Version 5) UUID based on the 54 | // supplied name space and data. It is the same as calling: 55 | // 56 | // NewHash(sha1.New(), space, data, 5) 57 | func NewSHA1(space UUID, data []byte) UUID { 58 | return NewHash(sha1.New(), space, data, 5) 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/BurntSushi/toml/type_toml.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // tomlType represents any Go type that corresponds to a TOML type. 4 | // While the first draft of the TOML spec has a simplistic type system that 5 | // probably doesn't need this level of sophistication, we seem to be militating 6 | // toward adding real composite types. 7 | type tomlType interface { 8 | typeString() string 9 | } 10 | 11 | // typeEqual accepts any two types and returns true if they are equal. 12 | func typeEqual(t1, t2 tomlType) bool { 13 | if t1 == nil || t2 == nil { 14 | return false 15 | } 16 | return t1.typeString() == t2.typeString() 17 | } 18 | 19 | func typeIsTable(t tomlType) bool { 20 | return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) 21 | } 22 | 23 | type tomlBaseType string 24 | 25 | func (btype tomlBaseType) typeString() string { return string(btype) } 26 | func (btype tomlBaseType) String() string { return btype.typeString() } 27 | 28 | var ( 29 | tomlInteger tomlBaseType = "Integer" 30 | tomlFloat tomlBaseType = "Float" 31 | tomlDatetime tomlBaseType = "Datetime" 32 | tomlString tomlBaseType = "String" 33 | tomlBool tomlBaseType = "Bool" 34 | tomlArray tomlBaseType = "Array" 35 | tomlHash tomlBaseType = "Hash" 36 | tomlArrayHash tomlBaseType = "ArrayHash" 37 | ) 38 | 39 | // typeOfPrimitive returns a tomlType of any primitive value in TOML. 40 | // Primitive values are: Integer, Float, Datetime, String and Bool. 41 | // 42 | // Passing a lexer item other than the following will cause a BUG message 43 | // to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. 44 | func (p *parser) typeOfPrimitive(lexItem item) tomlType { 45 | switch lexItem.typ { 46 | case itemInteger: 47 | return tomlInteger 48 | case itemFloat: 49 | return tomlFloat 50 | case itemDatetime: 51 | return tomlDatetime 52 | case itemString, itemStringEsc: 53 | return tomlString 54 | case itemMultilineString: 55 | return tomlString 56 | case itemRawString: 57 | return tomlString 58 | case itemRawMultilineString: 59 | return tomlString 60 | case itemBool: 61 | return tomlBool 62 | } 63 | p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) 64 | panic("unreachable") 65 | } 66 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/update_tester_group.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var UpdateTesterGroup = bitrise.Tool{ 13 | APIGroups: []string{"release-management"}, 14 | Definition: mcp.NewTool("update_tester_group", 15 | mcp.WithDescription("Updates the given tester group. The name and the auto notification setting can be updated optionally."), 16 | mcp.WithString("connected_app_id", 17 | mcp.Description("The uuidV4 identifier of the related Release Management connected app."), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("id", 21 | mcp.Description("The uuidV4 identifier of the tester group to which testers will be added."), 22 | mcp.Required(), 23 | ), 24 | mcp.WithString("name", 25 | mcp.Description("The new name for the tester group. Must be unique in the scope of the related connected app."), 26 | ), 27 | mcp.WithBoolean("auto_notify", 28 | mcp.Description("If set to true it indicates the tester group will receive email notifications automatically from now on about new installable builds."), 29 | mcp.DefaultBool(false), 30 | ), 31 | ), 32 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 33 | connectedAppID, err := request.RequireString("connected_app_id") 34 | if err != nil { 35 | return mcp.NewToolResultError(err.Error()), nil 36 | } 37 | id, err := request.RequireString("id") 38 | if err != nil { 39 | return mcp.NewToolResultError(err.Error()), nil 40 | } 41 | 42 | body := map[string]any{} 43 | if v := request.GetString("name", ""); v != "" { 44 | body["name"] = v 45 | } 46 | if v := request.GetBool("auto_notify", false); v { 47 | body["auto_notify"] = v 48 | } 49 | 50 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 51 | Method: http.MethodPut, 52 | BaseURL: bitrise.APIRMBaseURL, 53 | Path: fmt.Sprintf("/connected-apps/%s/tester-groups/%s", connectedAppID, id), 54 | Body: body, 55 | }) 56 | if err != nil { 57 | return mcp.NewToolResultErrorFromErr("call api", err), nil 58 | } 59 | return mcp.NewToolResultText(res), nil 60 | }, 61 | } 62 | -------------------------------------------------------------------------------- /internal/tool/releasemanagement/set_installable_artifact_public_install_page.go: -------------------------------------------------------------------------------- 1 | package releasemanagement 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/bitrise-io/bitrise-mcp/v2/internal/bitrise" 9 | "github.com/mark3labs/mcp-go/mcp" 10 | ) 11 | 12 | var SetInstallableArtifactPublicInstallPage = bitrise.Tool{ 13 | APIGroups: []string{"release-management"}, 14 | Definition: mcp.NewTool("set_installable_artifact_public_install_page", 15 | mcp.WithDescription("Changes whether public install page should be available for the installable artifact or not."), 16 | mcp.WithString("connected_app_id", 17 | mcp.Description("Identifier of the Release Management connected app for the installable artifact. This field is mandatory."), 18 | mcp.Required(), 19 | ), 20 | mcp.WithString("installable_artifact_id", 21 | mcp.Description("The uuidv4 identifier for the installable artifact. This field is mandatory."), 22 | mcp.Required(), 23 | ), 24 | mcp.WithBoolean("with_public_page", 25 | mcp.Description("Boolean flag for enabling/disabling public install page for the installable artifact. This field is mandatory."), 26 | mcp.Required(), 27 | ), 28 | ), 29 | Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { 30 | connectedAppID, err := request.RequireString("connected_app_id") 31 | if err != nil { 32 | return mcp.NewToolResultError(err.Error()), nil 33 | } 34 | installableArtifactID, err := request.RequireString("installable_artifact_id") 35 | if err != nil { 36 | return mcp.NewToolResultError(err.Error()), nil 37 | } 38 | withPublicPage, err := request.RequireBool("with_public_page") 39 | if err != nil { 40 | return mcp.NewToolResultError(err.Error()), nil 41 | } 42 | 43 | body := map[string]any{ 44 | "with_public_page": withPublicPage, 45 | } 46 | 47 | res, err := bitrise.CallAPI(ctx, bitrise.CallAPIParams{ 48 | Method: http.MethodPatch, 49 | BaseURL: bitrise.APIRMBaseURL, 50 | Path: fmt.Sprintf("/connected-apps/%s/installable-artifacts/%s/public-install-page", connectedAppID, installableArtifactID), 51 | Body: body, 52 | }) 53 | if err != nil { 54 | return mcp.NewToolResultErrorFromErr("call api", err), nil 55 | } 56 | return mcp.NewToolResultText(res), nil 57 | }, 58 | } 59 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | This project is covered by two different licenses: MIT and Apache. 3 | 4 | #### MIT License #### 5 | 6 | The following files were ported to Go from C files of libyaml, and thus 7 | are still covered by their original MIT license, with the additional 8 | copyright staring in 2011 when the project was ported over: 9 | 10 | apic.go emitterc.go parserc.go readerc.go scannerc.go 11 | writerc.go yamlh.go yamlprivateh.go 12 | 13 | Copyright (c) 2006-2010 Kirill Simonov 14 | Copyright (c) 2006-2011 Kirill Simonov 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy of 17 | this software and associated documentation files (the "Software"), to deal in 18 | the Software without restriction, including without limitation the rights to 19 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 20 | of the Software, and to permit persons to whom the Software is furnished to do 21 | so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | SOFTWARE. 33 | 34 | ### Apache License ### 35 | 36 | All the remaining project files are covered by the Apache license: 37 | 38 | Copyright (c) 2011-2019 Canonical Ltd 39 | 40 | Licensed under the Apache License, Version 2.0 (the "License"); 41 | you may not use this file except in compliance with the License. 42 | You may obtain a copy of the License at 43 | 44 | http://www.apache.org/licenses/LICENSE-2.0 45 | 46 | Unless required by applicable law or agreed to in writing, software 47 | distributed under the License is distributed on an "AS IS" BASIS, 48 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 | See the License for the specific language governing permissions and 50 | limitations under the License. 51 | --------------------------------------------------------------------------------